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.plugins.jpa.modules.hibernate.service;
35  
36  import fr.paris.lutece.portal.service.jpa.EntityManagerService;
37  import fr.paris.lutece.portal.service.util.AppPropertiesService;
38  import fr.paris.lutece.util.jpa.JPAConstants;
39  
40  import org.apache.log4j.Logger;
41  
42  import org.hibernate.SessionFactory;
43  
44  import org.hibernate.ejb.HibernateEntityManagerFactory;
45  
46  import org.hibernate.jmx.StatisticsService;
47  
48  import org.hibernate.stat.Statistics;
49  
50  import java.lang.management.ManagementFactory;
51  
52  import java.util.ArrayList;
53  import java.util.List;
54  import java.util.Map;
55  import java.util.Map.Entry;
56  
57  import javax.management.MBeanServer;
58  import javax.management.ObjectName;
59  
60  import javax.persistence.EntityManagerFactory;
61  
62  
63  /**
64   * Provides Hibernate monitoring data, relying on {@link EntityManagerService}.
65   *
66   */
67  public class HibernateMonitorService
68  {
69      private static final Logger logger = Logger.getLogger( JPAConstants.JPA_LOGGER );
70      private EntityManagerService _service;
71      private boolean _bJMXEnabled;
72      private boolean _bStatisticsEnabled;
73  
74      /**
75       * Gets Hibernate statistics for all pools.
76       * @return list of {@link HibernateStatistics}
77       */
78      public List<HibernateStatistics> computeStatistics(  )
79      {
80          List<HibernateStatistics> listStats = new ArrayList<HibernateStatistics>(  );
81  
82          for ( Entry<String, EntityManagerFactory> entry : _service.getEntityManagerFactories(  ).entrySet(  ) )
83          {
84              Statistics stats = getEntityManagerFactoryImpl( entry.getValue(  ) ).getSessionFactory(  ).getStatistics(  );
85  
86              HibernateStatistics hibernateStatistics = new HibernateStatistics(  );
87              hibernateStatistics.setPoolName( entry.getKey(  ) );
88              hibernateStatistics.setStats( stats );
89  
90              listStats.add( hibernateStatistics );
91          }
92  
93          return listStats;
94      }
95  
96      /**
97       * <code>true</code> if JMX is enabled, <code>false</code> otherwise.
98       * @param bJMXEnabled <code>true</code> if JMX is enabled, <code>false</code> otherwise.
99       */
100     public void setJMXEnabled( boolean bJMXEnabled )
101     {
102         _bJMXEnabled = bJMXEnabled;
103     }
104 
105     /**
106      * <code>true</code> if JMX is enabled, <code>false</code> otherwise.
107      * @return <code>true</code> if JMX is enabled, <code>false</code> otherwise.
108      */
109     public boolean isJMXEnabled(  )
110     {
111         return _bJMXEnabled;
112     }
113 
114     /**
115      * <code>true</code> if statistics are enabled, <code>false</code> otherwise.
116      * @param bStatisticsEnabled <code>true</code> if statistics are enabled, <code>false</code> otherwise.
117      */
118     public void setStatisticsEnabled( boolean bStatisticsEnabled )
119     {
120         _bStatisticsEnabled = bStatisticsEnabled;
121     }
122 
123     /**
124      * <code>true</code> if statistics are enabled, <code>false</code> otherwise.
125      * @return <code>true</code> if statistics are enabled, <code>false</code> otherwise.
126      */
127     public boolean isStatisticsEnabled(  )
128     {
129         return _bStatisticsEnabled;
130     }
131 
132     /**
133      * Sets the EntityManagerService
134      * @param service the EntityManagerService
135      */
136     public void setEntityManagerService( EntityManagerService service )
137     {
138         _service = service;
139     }
140 
141     /**
142      * The EntityManagerService
143      * @return the EntityManagerService
144      */
145     public EntityManagerService getEntityManagerService(  )
146     {
147         return _service;
148     }
149 
150     /**
151      * {@inheritDoc}
152      */
153     public void init(  )
154     {
155         // enable statistics
156         if ( isStatisticsEnabled(  ) )
157         {
158             if ( _service.getEntityManagerFactories(  ) != null )
159             {
160                 doEnableStatistics(  );
161             }
162             else
163             {
164                 logger.error( 
165                     "EntityManagerService is not started yet, can't enable hibernate statistics. Manual activation needed." );
166                 setStatisticsEnabled( false );
167             }
168         }
169 
170         // enable hibernate JMX...
171         if ( isJMXEnabled(  ) )
172         {
173             if ( _service.getEntityManagerFactories(  ) != null )
174             {
175                 setJMXEnabled( registerMBeans( _service.getEntityManagerFactories(  ) ) );
176                 // also enable statistics...
177                 setStatisticsEnabled( true );
178             }
179             else
180             {
181                 logger.error( 
182                     "EntityManagerService is not started yet, can't start hibernate JMX beans. Manual activation needed." );
183                 setJMXEnabled( false );
184             }
185         }
186     }
187 
188     /**
189      * JMX manual activation.
190      * @return {@link #isJMXEnabled()}
191      */
192     public boolean doActivateJMXBeans(  )
193     {
194         if ( _service.getEntityManagerFactories(  ) != null )
195         {
196             setJMXEnabled( registerMBeans( _service.getEntityManagerFactories(  ) ) );
197         }
198 
199         return isJMXEnabled(  );
200     }
201 
202     /**
203      * Clear pool statistics.
204      * @param strPoolName the pool name
205      */
206     public void doClearStatistics( String strPoolName )
207     {
208         EntityManagerFactory emf = _service.getEntityManagerFactory( strPoolName );
209 
210         if ( emf != null )
211         {
212             HibernateEntityManagerFactory emfImpl = getEntityManagerFactoryImpl( emf );
213             emfImpl.getSessionFactory(  ).getStatistics(  ).clear(  );
214         }
215     }
216 
217     /**
218      * Enables statistics (for all pools).
219      * @see Statistics#setStatisticsEnabled(boolean)
220      */
221     public void doEnableStatistics(  )
222     {
223         setHibernateStatisticsEnabled( true );
224     }
225 
226     /**
227      * Disables statistics (for all pools).
228      * @see Statistics#setStatisticsEnabled(boolean)
229      */
230     public void doDisableStatistics(  )
231     {
232         setHibernateStatisticsEnabled( false );
233     }
234 
235     /**
236      * Sets statistics status to factories
237      * @param bEnabled enabled
238      */
239     private void setHibernateStatisticsEnabled( boolean bEnabled )
240     {
241         for ( EntityManagerFactory emf : _service.getEntityManagerFactories(  ).values(  ) )
242         {
243             HibernateEntityManagerFactory emfImpl = getEntityManagerFactoryImpl( emf );
244             emfImpl.getSessionFactory(  ).getStatistics(  ).setStatisticsEnabled( bEnabled );
245 
246             if ( !bEnabled )
247             {
248                 emfImpl.getSessionFactory(  ).getStatistics(  ).clear(  );
249             }
250         }
251 
252         setStatisticsEnabled( bEnabled );
253     }
254 
255     /**
256      * Casts the JPA {@link EntityManagerFactory} to Hibernate {@link HibernateEntityManagerFactory}
257      * @param emf factory
258      * @return the hibernate impl
259      */
260     private HibernateEntityManagerFactory getEntityManagerFactoryImpl( EntityManagerFactory emf )
261     {
262         return (HibernateEntityManagerFactory) emf;
263     }
264 
265     /**
266      * Registers JMX Beans for the given factories
267      * @param mapFactories the factories
268      * @return <code>true</code> if MBeans successfully registered, <code>false</code> otherwise.
269      */
270     private boolean registerMBeans( Map<String, EntityManagerFactory> mapFactories )
271     {
272         logger.debug( "Initializing JMX for hibernate" );
273 
274         for ( Entry<String, EntityManagerFactory> entry : mapFactories.entrySet(  ) )
275         {
276             logger.debug( "Registering JMX for hibernate pool : " + entry.getKey(  ) );
277 
278             HibernateEntityManagerFactory emf = getEntityManagerFactoryImpl( entry.getValue(  ) );
279 
280             if ( !registerMBean( emf.getSessionFactory(  ), entry.getKey(  ) ) )
281             {
282                 return false;
283             }
284         }
285 
286         return true;
287     }
288 
289     /**
290      * Registers factory mbean.
291      * @param sessionFactory the factory
292      * @param strPoolName the pool name (added to the MBean name)
293      * @return <code>true</code> if the mbean is registered, <code>false</code> otherwise.
294      */
295     private boolean registerMBean( SessionFactory sessionFactory, String strPoolName )
296     {
297         MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(  );
298 
299         StatisticsService mBean = new StatisticsService(  );
300         mBean.setStatisticsEnabled( true );
301         mBean.setSessionFactory( sessionFactory );
302 
303         ObjectName name;
304 
305         try
306         {
307             name = new ObjectName( "Hibernate:type=statistics-" + strPoolName + ",application=" +
308                     AppPropertiesService.getProperty( "lutece.name" ) );
309             mbeanServer.registerMBean( mBean, name );
310         }
311         catch ( Exception e )
312         {
313             logger.error( e.getMessage(  ), e );
314 
315             return false;
316         }
317 
318         return true;
319     }
320 
321     /**
322      * {@inheritDoc}
323      */
324     public String getName(  )
325     {
326         return "HibernateMonitor";
327     }
328 }