View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.portal.service.database;
35  
36  import fr.paris.lutece.portal.service.plugin.PluginEvent;
37  import fr.paris.lutece.portal.service.plugin.PluginEventListener;
38  import fr.paris.lutece.portal.service.plugin.PluginService;
39  import fr.paris.lutece.util.sql.TransactionManager;
40  
41  import org.apache.commons.lang3.StringUtils;
42  import org.apache.logging.log4j.LogManager;
43  import org.apache.logging.log4j.Logger;
44  import org.springframework.jdbc.datasource.DataSourceTransactionManager;
45  
46  import java.io.PrintWriter;
47  
48  import java.sql.Connection;
49  import java.sql.SQLException;
50  import java.sql.SQLFeatureNotSupportedException;
51  
52  import javax.sql.DataSource;
53  
54  /**
55   * DataSource transaction manager. This transaction manager use Spring transaction manager, and do not use {@link TransactionManager}. This transaction manager
56   * allow to use transaction in a given plugin, but does not influence other plugins. To create transactions throw multiple plugins, use
57   * {@link LuteceTransactionManager}
58   */
59  public class DAOUtilTransactionManager extends DataSourceTransactionManager implements PluginEventListener
60  {
61      private static final long serialVersionUID = -654531540978261621L;
62      private transient Logger _logger = LogManager.getLogger( "lutece.debug.sql.tx" );
63      private String _strPluginName;
64      private boolean _bInit;
65  
66      /**
67       * Registers the listener to {@link PluginService}.
68       */
69      public DAOUtilTransactionManager( )
70      {
71          PluginService.registerPluginEventListener( this );
72      }
73  
74      /**
75       * Gets the plugin name
76       * 
77       * @return the plugin name
78       */
79      public String getPluginName( )
80      {
81          return _strPluginName;
82      }
83  
84      /**
85       * Sets the plugin name
86       * 
87       * @param strPluginName
88       *            the plugin name
89       */
90      public void setPluginName( String strPluginName )
91      {
92          _strPluginName = strPluginName;
93      }
94  
95      /**
96       * {@inheritDoc}
97       */
98      @Override
99      public void processPluginEvent( PluginEvent event )
100     {
101         if ( getPluginName( ).equals( event.getPlugin( ).getName( ) ) )
102         {
103             if ( ( event.getEventType( ) == PluginEvent.PLUGIN_INSTALLED ) || ( event.getEventType( ) == PluginEvent.PLUGIN_POOL_CHANGED ) )
104             {
105                 if ( StringUtils.isNotBlank( event.getPlugin( ).getDbPoolName( ) )
106                         && !AppConnectionService.NO_POOL_DEFINED.equals( event.getPlugin( ).getDbPoolName( ) ) )
107                 {
108                     try
109                     {
110                         getLogger( ).debug( "DAOUtilTransactionManager changed datasource status..." );
111                         setDataSource( AppConnectionService.getPoolManager( ).getDataSource( event.getPlugin( ).getDbPoolName( ) ) );
112                         _bInit = true;
113                     }
114                     catch( Exception ex )
115                     {
116                         _bInit = false;
117                         getLogger( ).error(
118                                 "An error occured getting pool for DAOUtilTransactionManager for plugin {} , please check plugin is activated and pool is correctly set : {}",
119                                 event.getPlugin( ).getName( ), ex.getMessage( ), ex );
120                     }
121                 }
122                 else
123                 {
124                     getLogger( ).debug( "Pool for plugin {} is set to null, clearing transaction manager", event.getPlugin( ).getName( ) );
125                     setDataSource( null );
126                     _bInit = false;
127                 }
128             }
129             else
130                 if ( event.getEventType( ) == PluginEvent.PLUGIN_UNINSTALLED )
131                 {
132                     setDataSource( null );
133                     _bInit = false;
134                 }
135         }
136     }
137 
138     private Logger getLogger( )
139     {
140         if ( _logger == null )
141         {
142             _logger = LogManager.getLogger( "lutece.debug.sql.tx" );
143         }
144         return _logger;
145     }
146 
147     /**
148      * Returns a "fake" datasource to avoid spring checks failure when pool are not initialized. Returns the current datasource otherwise.
149      *
150      * @return the data source
151      */
152     @Override
153     public DataSource getDataSource( )
154     {
155         if ( _bInit )
156         {
157             return super.getDataSource( );
158         }
159 
160         /**
161          * Empty datasource
162          */
163         return new EmptyDataSource( );
164     }
165 
166     /**
167      * Empty datasource
168      */
169     private static class EmptyDataSource implements DataSource
170     {
171         @Override
172         public <T> T unwrap( Class<T> iface ) throws SQLException
173         {
174             return null;
175         }
176 
177         @Override
178         public boolean isWrapperFor( Class<?> iface ) throws SQLException
179         {
180             return false;
181         }
182 
183         @Override
184         public void setLoginTimeout( int seconds ) throws SQLException
185         {
186             // Do nothing
187         }
188 
189         @Override
190         public void setLogWriter( PrintWriter out ) throws SQLException
191         {
192             // Do nothing
193         }
194 
195         @Override
196         public int getLoginTimeout( ) throws SQLException
197         {
198             return 0;
199         }
200 
201         @Override
202         public PrintWriter getLogWriter( ) throws SQLException
203         {
204             return null;
205         }
206 
207         @Override
208         public Connection getConnection( String username, String password ) throws SQLException
209         {
210             return null;
211         }
212 
213         @Override
214         public Connection getConnection( ) throws SQLException
215         {
216             return null;
217         }
218 
219         /**
220          * Get the parent logger
221          * 
222          * @return the logger
223          * @throws SQLFeatureNotSupportedException
224          *             if this method is not supported
225          */
226         public java.util.logging.Logger getParentLogger( ) throws SQLFeatureNotSupportedException
227         {
228             throw new SQLFeatureNotSupportedException( );
229         }
230     }
231 }