Online Books:
java.net on MarkMail:
Search |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Extending the NetBeans Tutorial JSF-JPA-Hibernate Application, Part 3 - Enabling JMX Monitoring on Hibernate v3 and Ehcache 1.3.0 on "SimpleJpaHibernateApp"Posted by maxpoon on June 27, 2007 at 11:21 AM PDT
BackgroundThis is the continuation from the
previous article "Extending
the NetBeans Tutorial JSF-JPA-Hibernate Application, Part 2 - Enabling
JMX Monitoring on Hibernate v3 and Ehcache 1.3, on HibernateTutorialApp"
where we continue with (3) and (4) of the following :
(3) Configuring SimpleJpaHibernateApp to use Ehcache 1.3.0The configurations for SimpleJpaHibernateApp, created with the NetBeans tutorial "Using Hibernate With the Java Persistence API", to use Ehcache 1.3.0 are similar to those of "Configuring HibernateTutorialApp/HibernateTravelPOJO to use Ehcache 1.3.0" , except :
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Code Listing 4.1 - SimpleJpaHibernateApp's
JmxAgent.java |
| /* * JmxAgent.java * */ package simpleJpaHibernateApp.agents; import java.lang.management.ManagementFactory; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManager; import net.sf.ehcache.CacheManager; import net.sf.ehcache.management.ManagementService; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.jmx.StatisticsService; /** * JMX agent (singleton) for monitoring Hibernate and Ehcache * in SimpleJpaHibernateApp, which uses: * <ul> * <li>JavaServer Faces (JSF) web-tier</li> * <li>Java Persistence API (JPA) persistence</li> * <li>Hibernate Core (3.2.4 sp1) and Hibernate EntityManager (3.3.1)</li> * <li>Ehcache 1.3.0</li> * </ul> * * @author Max Poon (maxpoon@dev.java.net) */ public class JmxAgent { private EntityManager em; private Session session; private SessionFactory sf; /** * Instantiate, register MBeans, enable Hibernate & Ehcache JMX Statistics * @param emf javax.persistence.EntityManagerFactory to be passed in * from the invoking context (instead of creating it here * which is expensive operation) */ public void init(EntityManagerFactory emf) throws Exception { try { // Create EntityManager from EntityManagerFactory passed in // from the invoking context em = emf.createEntityManager(); // Get Hibernate Session and SessionFactory from EntityManager // *Important* for registering the Hibernate SessionFactory // with org.hibernate.jmx.StatisticsService later on // to enable JMX monitoring of Hibernate statistics session = (Session) em.getDelegate(); sf = session.getSessionFactory(); } catch (Exception ex) { ex.printStackTrace(); } finally { em.close(); } ObjectName on = new ObjectName ("Hibernate:type=statistics,application=SimpleJpaHibernateApp"); // Enable Hibernate JMX Statistics StatisticsService statsMBean = new StatisticsService(); statsMBean.setSessionFactory(sf); statsMBean.setStatisticsEnabled(true); mbs.registerMBean(statsMBean, on); /* * Enable Ehcache JMX Statistics * Use CacheManager.getInstance() instead of new CacheManager() * as net.sf.ehcache.hibernate.SingletonEhCacheProvider is used * to ensure reference to the same CacheManager instance as used * by Hibernate */ CacheManager cacheMgr = CacheManager.getInstance(); ManagementService.registerMBeans (cacheMgr, mbs, true, true, true, true); } /** * Returns an agent singleton. */ public synchronized static JmxAgent getDefault(EntityManagerFactory emf) throws Exception { if(singleton == null) { singleton = new JmxAgent(); singleton.init(emf); } return singleton; } public MBeanServer getMBeanServer() { return mbs; } // Platform MBeanServer used to register your MBeans private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); // Singleton instance private static JmxAgent singleton; } |
Unlike the HibernateTravelPOJO
application, there
is no HibernateUtil.java-like
object for getting Hibernate Session in
SimpleJpaHibernateApp. One solution is to initiate JmxAgent
during the 1st retrieval of EntityManager in following JSF
managed beans / controllers :
e.g. as shown in Code Listing 4.2 for simpleJpaHibernate.controllers.ProductController
:
| Code Listing 4.2 - ProductController.java
modified to initiate JmxAgent if needed |
| /* * ProductController.java * */ package simpleJpaHibernateApp.controller; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Resource; .... import simpleJpaHibernateApp.agents.JmxAgent; import simpleJpaHibernateApp.entities.Manufacturer; import simpleJpaHibernateApp.entities.Product; import simpleJpaHibernateApp.entities.ProductCode; /** * This version of ProductController uses JPA query with SQL joint * to retrieve all Products associated with a given ProductCode * indicated by its ID 'selectedProdCode'. * This shows simple code modification to get additional behaviour. * * @author Max Poon (maxpoon@dev.java.net) */ public class ProductController { /** Creates a new instance of ProductController */ public ProductController() { } private Product product; private ProductCode selectedProductCode; private String selectedProdCode; private DataModel model; @Resource private UserTransaction utx; @PersistenceUnit(unitName = "SimpleJpaHibernateAppPU") private EntityManagerFactory emf; private EntityManager getEntityManager() { initJMX(); return emf.createEntityManager(); } // Initiate JMX if needed void initJMX() { try { JmxAgent.getDefault(emf); } catch (Exception ex) { ex.printStackTrace(); } } ... ... |
Similar modifications should also be
done for :
| Figure
4.3.1 - "Listing ProductCodes" page of SimpleJpaHibernateApp |

| Figure
4.3.2 - JConsole showing Hibernate Entity Names, Queries, 2nd Level
Cache Regions, and related statistics |
| Figure 4.3.3 -
JConsole showing Ehcache Statistics on ProductCode, with 6 cache miss
for the 6 ProductCode instances retrieved |
| Figure 4.3.4 - "Detail of ProductCode" page
of SimpleJpaHibernateApp for ProdCode="SW" |

| Figure
4.3.5 - JConsole showing Hibernate Statistics being updated as compared
to Figure
4.3.2 |
| Figure 4.3.6 -
JConsole showing Ehcache Statistics for ProductCode updated (with 2
more cache misses and 7 more cache hits) as compared to Figure
4.3.3 |
| Figure 4.3.7 - "Listing Products" page of SimpleJpaHibernateApp for ProdCode="SW" |

| Figure 4.3.8 - JConsole showing Hibernate Statistics being updated as compared to Figure 4.3.5 |
| Figure 4.3.9 - JConsole showing Ehcache Statistics for ProductCode updated, with 1 more (ProductCode where ProdCode="SW") cache hit as compared to Figure 4.3.6 |
| Figure
4.3.10 - JConsole showing Ehcache
Statistics for Product, with 8 new retrieval, i.e. cache misses, for
the 8 Product
instances where ProdCode="SW" as shown in Figure
4.3.7 |
| Coding Listing 4.4.1 -
simpleJpaHibernateApp.controllers.ProductController#getProducts() -
using JPA Query with SQL joint and parameter binding |
| /** * This version of ProductController uses JPA query with SQL joint * to retrieve all Products associated with a given ProductCode * indicated by its ID 'selectedProdCode'. * This shows simple code modification to get additional behaviour. * * @author Max Poon (maxpoon@dev.java.net) */ public class ProductController { ... public DataModel getProducts() { EntityManager em = getEntityManager(); try{ Query q; if (selectedProdCode != null && selectedProdCode.length() != 0) { q = em.createQuery("select object(o) from Product as o " + "where o.productCode.prodCode = :selectedProdCode") .setParameter("selectedProdCode", selectedProdCode); } else { q = em.createQuery("select object(o) from Product as o"); } q.setMaxResults(batchSize); q.setFirstResult(firstItem); model = new ListDataModel(q.getResultList()); return model; } finally { em.close(); } } ... public int getItemCount() { EntityManager em = getEntityManager(); try{ Query q; if (selectedProdCode != null && selectedProdCode.length() != 0) { q = em.createQuery("select count(o) from Product as o " + "where o.productCode.prodCode = :selectedProdCode") .setParameter("selectedProdCode", selectedProdCode); } else { q = em.createQuery("select count(o) from Product as o"); } int count = ((Long) q.getSingleResult()).intValue(); return count; } finally { em.close(); } } ... |
| Coding Listing 4.4.2 -
simpleJpaHibernateApp.controllers.ProductController#getProducts() and
getItemCount() -
using JPA Entity Collection, e.g. to show use of Hibernate Collection
Cache in additional to Class Caching |
| /** * This version of ProductController uses entity collection for * retrieving all Products associated with a given ProductCode * indicated by its ID 'selectedProdCode' to show JMX monitoring * on collection cache in additional to entity class cache * * @author Max Poon (maxpoon@dev.java.net) */ public class ProductController { ... public DataModel getProducts() { EntityManager em = getEntityManager(); try{ List<Product> productList; if (selectedProdCode != null && selectedProdCode.length() != 0) { ProductCode productCode = em.find(ProductCode.class, selectedProdCode); productList = (List<Product>) productCode.getProductCollection(); } else { Query q = em.createQuery("select object(o) from Product as o"); q.setMaxResults(batchSize); q.setFirstResult(firstItem); productList = (List<Product>) q.getResultList(); } model = new ListDataModel(productList); return model; } finally { em.close(); } } ... public int getItemCount() { EntityManager em = getEntityManager(); try{ int count; if (selectedProdCode != null && selectedProdCode.length() != 0) { ProductCode productCode = em.find(ProductCode.class, selectedProdCode); count = productCode.getProductCollection().size(); } else { Query q = em.createQuery("select count(o) from Product as o"); count = ((Long) q.getSingleResult()).intValue(); } return count; } finally { em.close(); } ... |
| Code Listing 4.4.3 - ProductCode.java with
Hibernate @Cache Annotation to enable Entity Class Cache on ProductCode
and Collection Cache on ProductCode.productionCollection |
| /* * ProductCode.java * */ package simpleJpaHibernateApp.entities; import java.io.Serializable; import java.util.Collection; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.Table; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; /** * Entity class ProductCode, adding Hibernate Annotations to enable * Entity Class Cache on ProductCode, and * Collection Cache on ProductCode.productCollection * * @author Max Poon (maxpoon@dev.java.net) */ @Entity @Table(name = "PRODUCT_CODE") @NamedQueries( { ...... } ) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class ProductCode implements Serializable { @Id @Column(name = "PROD_CODE", nullable = false) private String prodCode; @Column(name = "DISCOUNT_CODE", nullable = false) private char discountCode; @Column(name = "DESCRIPTION") private String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "productCode") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) private Collection<Product> productCollection; ...... |
| Figure
4.4.1 - JConsole showing Hibernate JMX statistics, on
SimpleJpaHibernateApp using @Cache Annotation (to enable Collection
Cache), as compared to Figure
4.3.8
for SimpleJpaHibernateApp using JPA Query |
| Figure 4.4.2 - JConsole showing Ehcache JMX Class Cache Statistics for ProductCode, on SimpleJpaHibernateApp using @Cache Annotation to enable Collection Cache, as compared to Figure 4.3.9 for SimpleJpaHibernateApp using JPA Query |
| Figure 4.4.3 - JConsole showing Ehcache JMX Class Cache Statistics for Product, on SimpleJpaHibernateApp using @Cache Annotation to enable Collection Cache, as compared to Figure 4.3.10 for SimpleJpaHibernateApp using JPA Query |
| Using
JPA Query with SQL Joint |
Using
Entity Collection & Collection Cache |
|
| Hibernate JMX Statistics |
||
| Entity
Load Count |
28 |
29 |
| 2nd
Level Cache Hit |
2 |
109 |
| 2nd
Level Cache Miss |
1 |
2 |
| 2nd
Level Cache Put |
28 |
30 |
| Query
Execution Count |
27 |
20 |
| Query
Execution Max Time (ms) |
181 |
60 |
| Query
Execution Max Time Query String |
select count(o) from Product as o where o.productCode.prodCode = :selectProdCode; |
select object(o) from Product as o; |
| Ehcache JMX Statistics |
||
| ProductCode Cache Hit / Miss | 3 / 13 |
8 / 16 |
| Product
Cache Hit / Miss |
0 / 8 |
48 / 8 |
| ProductCode.productCollection
Cache Hit / Miss |
Not Available |
6 / 2 |
| Figure 4.4.5 - New Structure of
SimpleJpaHibernateApp NetBeans Project |
|
|