View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de 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.util.pool;
35  
36  import fr.paris.lutece.portal.service.init.LuteceInitException;
37  import fr.paris.lutece.util.ReferenceList;
38  import fr.paris.lutece.util.pool.service.ConnectionService;
39  import fr.paris.lutece.util.pool.service.LuteceConnectionService;
40  
41  import org.apache.log4j.Logger;
42  
43  import java.io.InputStream;
44  
45  import java.sql.Connection;
46  
47  import java.util.Collection;
48  import java.util.Enumeration;
49  import java.util.HashMap;
50  import java.util.Hashtable;
51  import java.util.Map;
52  import java.util.Properties;
53  
54  import javax.sql.DataSource;
55  
56  
57  /**
58   * This class can manages a set of database connections pools. It's implemented as a singleton. It provides methods to
59   * get or release a connection from a given pool.
60   */
61  public final class PoolManager
62  {
63      private static final String LOGGER_NAME = "lutece.pool";
64      private static PoolManager _instance;
65      private Logger _logger;
66      private Map<String, ConnectionService> _pools = new HashMap<String, ConnectionService>(  );
67  
68      /**
69       * Creates a new PoolManager object.
70       *
71       *
72       * @param isDbProperties A properties file containing pools parameters.
73       * @throws LuteceInitException If any error occured
74       */
75      private PoolManager( InputStream isDbProperties ) throws LuteceInitException
76      {
77          init( isDbProperties );
78      }
79  
80      /**
81       * This method returns the unique instance of the PoolManager.
82       *
83       * @return The unique instance of Poolmanager.
84       * @param isDbProperties An InputStream on a db.properties File to initialiaze the pool if it's not already created.
85       * @throws LuteceInitException  If any error occured
86       */
87      public static synchronized PoolManager getInstance( InputStream isDbProperties )
88          throws LuteceInitException
89      {
90          if ( _instance == null )
91          {
92              _instance = new PoolManager( isDbProperties );
93          }
94  
95          return _instance;
96      }
97  
98      /**
99       * Initializes pools with parameters defined in a db.properties File.
100      *
101      * @param is An InputStream on a db.properties File.
102      * @throws LuteceInitException If any error occured
103      */
104     private void init( InputStream is ) throws LuteceInitException
105     {
106         _logger = Logger.getLogger( LOGGER_NAME );
107 
108         Properties dbProps = new Properties(  );
109 
110         try
111         {
112             dbProps.load( is );
113         }
114         catch ( Exception e )
115         {
116             throw new LuteceInitException( "Can't read the properties file. Make sure db.properties is in the CLASSPATH",
117                 e );
118         }
119 
120         createPools( dbProps );
121     }
122 
123     /**
124      * Creates all pools defined in a properties file.
125      *
126      * @param props A properties file containing pools parameters.
127      * @throws LuteceInitException  If any error occured
128      */
129     private void createPools( Properties props ) throws LuteceInitException
130     {
131         Enumeration propNames = props.propertyNames(  );
132         String strPoolName = "";
133 
134         Hashtable<String, Hashtable<String, String>> htPools = new Hashtable<String, Hashtable<String, String>>(  );
135 
136         while ( propNames.hasMoreElements(  ) )
137         {
138             String name = (String) propNames.nextElement(  );
139 
140             try
141             {
142                 strPoolName = name.substring( 0, name.lastIndexOf( '.' ) );
143 
144                 //tests if the pool has yet somme of its porperties stored in the hatsable
145                 Hashtable<String, String> htParamsPool;
146 
147                 //if the pool has not yet property
148                 if ( htPools.get( strPoolName ) == null )
149                 {
150                     htParamsPool = new Hashtable<String, String>(  );
151                 }
152                 else
153                 {
154                     htParamsPool = htPools.get( strPoolName );
155                 }
156 
157                 htParamsPool.put( name, props.getProperty( name ) );
158                 htPools.put( strPoolName, htParamsPool );
159 
160                 _logger.debug( "property " + name );
161                 _logger.debug( "pool name " + strPoolName );
162             }
163             catch ( Exception e )
164             {
165                 throw new LuteceInitException( 
166                     "Invalid initialization of the pools. Problem encoutered with the property :  " + name, e );
167             }
168         }
169 
170         Enumeration enumKeys = htPools.keys(  );
171 
172         while ( enumKeys.hasMoreElements(  ) )
173         {
174             String key = "";
175 
176             try
177             {
178                 key = (String) enumKeys.nextElement(  );
179 
180                 Hashtable<String, String> htParamsPool = htPools.get( key );
181                 ConnectionService cs = null;
182 
183                 try
184                 {
185                     String strConnectionService = htParamsPool.get( key + ".poolservice" );
186 
187                     cs = (ConnectionService) Class.forName( strConnectionService ).newInstance(  );
188                 }
189                 catch ( NullPointerException nullEx )
190                 {
191                     cs = new LuteceConnectionService(  );
192                 }
193                 catch ( Exception e )
194                 {
195                     throw new LuteceInitException( "Exception when getting the property poolservice", e );
196                 }
197 
198                 if ( cs != null )
199                 {
200                     cs.setPoolName( key );
201                     cs.setLogger( _logger );
202                     cs.init( htParamsPool );
203                     _pools.put( key, cs );
204                 }
205             }
206             catch ( Exception e )
207             {
208                 throw new LuteceInitException( "Exception when getting the pool '" + key +
209                     "'. Please check your '/WEB-INF/conf/db.properties' file.", e );
210             }
211         }
212     }
213 
214     /**
215      * Returns an available connection from the pool.
216      *
217      * @param strPoolName The pool name
218      * @return A connection
219      */
220     public Connection getConnection( String strPoolName )
221     {
222         Connection conn = null;
223         ConnectionService pool = (ConnectionService) _pools.get( strPoolName );
224 
225         if ( pool != null )
226         {
227             conn = pool.getConnection(  );
228         }
229 
230         return conn;
231     }
232 
233     /**
234      * Returns a connection to pool.
235      *
236      * @param strPoolName Pool's name
237      * @param con A released connection
238      */
239     public void freeConnection( String strPoolName, Connection con )
240     {
241         ConnectionService cs = (ConnectionService) _pools.get( strPoolName );
242 
243         if ( cs != null )
244         {
245             cs.freeConnection( con );
246         }
247     }
248 
249     /**
250      * Releases all connections from all the pool.
251      */
252     public synchronized void release(  )
253     {
254         for ( ConnectionService pool : _pools.values(  ) )
255         {
256             pool.release(  );
257         }
258     }
259 
260     /**
261      * Returns all pools available
262      * @return The list of available pools
263      */
264     public Collection<ConnectionService> getPools(  )
265     {
266         return _pools.values(  );
267     }
268 
269     /**
270      * Returns pool's infos (currently opened connections)
271      * @return The pool's infos
272      */
273     public ReferenceList getPoolsInfos(  )
274     {
275         ReferenceList listPoolsInfos = new ReferenceList(  );
276         Collection<ConnectionService> listPools = getPools(  );
277 
278         for ( ConnectionService cs : listPools )
279         {
280             String strCurrentConnections = ( cs.getCurrentConnections(  ) == cs.INFO_NOT_AVAILABLE ) ? "-"
281                                                                                                      : ( "" +
282                 cs.getCurrentConnections(  ) );
283             String strMaxConnections = ( cs.getMaxConnections(  ) == cs.INFO_NOT_AVAILABLE ) ? "-"
284                                                                                              : ( "" +
285                 cs.getMaxConnections(  ) );
286             listPoolsInfos.addItem( cs.getPoolName(  ),
287                 strCurrentConnections + " / " + strMaxConnections + " (" + cs.getPoolProvider(  ) + ")" );
288         }
289 
290         return listPoolsInfos;
291     }
292 
293     /**
294      * Returns the datasource for a given pool name
295      * @param strPoolName The Pool name
296      * @return A data source object
297      */
298     public DataSource getDataSource( String strPoolName )
299     {
300         return _pools.get( strPoolName ).getDataSource(  );
301     }
302 }