EJB3: Entity Callbacks and Listeners Example 2
by admin ~ October 21, 2008
Following are the examples from the chapter “Entity Callbacks and Listeners” from the book “Enterprise JavaBeans 3.0″ by Bill Bruke & Richard Monson-Haefel. This example I have tried it out on JBoss AS 5.0.0.CR1. I have used Postgresql as the database. And I have used eclipse WTP as IDE.
Example2: Entity Listeners
Client.java
package com.titan.clients; import com.titan.travelagent.TravelAgentRemote; import com.titan.domain.*; import javax.naming.Context; import javax.rmi.PortableRemoteObject; public class Client { public static void main(String[] args) { try { Context jndiContext = getInitialContext(); Object ref = jndiContext .lookup("TitanCruises/TravelAgentBean/remote"); TravelAgentRemote dao = (TravelAgentRemote) PortableRemoteObject .narrow(ref, TravelAgentRemote.class); Customer cust = new Customer(); cust.setFirstName("Bill"); cust.setLastName("Burke"); int pk = dao.createCustomer(cust); cust = dao.findCustomer(pk); cust.setFirstName("Billy"); dao.doMerge(cust); dao.doFlush(cust.getId()); dao.doRemove(cust.getId()); } catch (javax.naming.NamingException ne) { ne.printStackTrace(); } } public static Context getInitialContext() throws javax.naming.NamingException { return new javax.naming.InitialContext(); } }
jndi.properties
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces java.naming.provider.url=127.0.0.1:1099
TravelAgentRemote.java
package com.titan.travelagent; import javax.ejb.Remote; import com.titan.domain.Customer; @Remote public interface TravelAgentRemote { public int createCustomer(Customer cust); public Customer findCustomer(int pKey); public void doMerge(Customer cust); public void doFlush(int pKey); public void doRemove(int pKey); }
TravelAgentBean.java
package com.titan.travelagent; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import com.titan.domain.Customer; @Stateless public class TravelAgentBean implements TravelAgentRemote { @PersistenceContext(unitName = "titan") private EntityManager manager; public int createCustomer(Customer cust) { System.out.println("--------------------------------------"); System.out.println("Calling createCustomer():" + cust.getFirstName()); System.out.println("Calling manager.persist()"); manager.persist(cust); System.out.println("Ending createCustomer."); return cust.getId(); } public Customer findCustomer(int pKey) { System.out.println("--------------------------------------"); System.out.println("Calling findCustomer()"); System.out.println("manager.find()"); Customer cust = manager.find(Customer.class, pKey); System.out.println("Returing from findCustomer(): " + cust.getFirstName()); return cust; } public void doMerge(Customer cust) { System.out.println("--------------------------------------"); System.out.println("Calling doMerge()"); manager.merge(cust); System.out.println("Returning from doMerge()"); } public void doFlush(int pKey) { System.out.println("--------------------------------------"); System.out.println("Calling doFlush()"); System.out.println("manager.find()"); Customer cust = manager.find(Customer.class, pKey); System.out.println("cust.setName()"); cust.setFirstName("doFlush"); System.out.println("calling manager.flush()"); manager.flush(); System.out.println("returning from doFlush()"); } public void doRemove(int pKey) { System.out.println("--------------------------------------"); System.out.println("Calling doRemove()"); System.out.println("manager.find()"); Customer cust = manager.find(Customer.class, pKey); System.out.println("calling manager.remove()"); manager.remove(cust); System.out.println("returning from doRemove()"); } }
Customer.java
package com.titan.domain; import javax.persistence.*; @Entity @EntityListeners(com.titan.stats.EntityListener.class) public class Customer implements java.io.Serializable { private int id; private String lastName; private String firstName; @Id @GeneratedValue public int getId() { return id; } public void setId(int pk) { id = pk; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } }
EntityStatsMBean.java
package com.titan.stats; public interface EntityStatsMBean { public String output(); }
EntityStats.java
package com.titan.stats; public class EntityStats implements EntityStatsMBean { public String output() { StringBuffer buf = new StringBuffer( "<table><tr><td>Entity Name</td> <td>Loads</td><td>Inserts</td> <td>Updates</td><td>Deletes</td></tr>"); for (EntityListener.Stats stats : EntityListener.map.values()) { buf.append("<tr><td>" + stats.entity).append("</td>"); buf.append("<td>" + stats.loads).append("</td>"); buf.append("<td>" + stats.inserts).append("</td>"); buf.append("<td>" + stats.updates).append("</td>"); buf.append("<td>" + stats.removes).append("</td></tr>"); } buf.append("</table>"); return buf.toString(); } }
EntityListener.java
package com.titan.stats; import javax.persistence.*; import java.util.concurrent.ConcurrentHashMap; public class EntityListener { public static class Stats { public String entity; public int updates; public int loads; public int inserts; public int removes; } public static ConcurrentHashMap<String, Stats> map = new ConcurrentHashMap<String, Stats>(); private static Stats getStats(Object entity) { String name = entity.getClass().getName(); Stats stats = map.get(name); if (stats == null) { stats = new Stats(); map.put(name, stats); stats.entity = name; } return stats; } @PostUpdate public void update(Object entity) { System.out.println("@PostUpdate: " + entity.getClass().getName()); Stats stats = getStats(entity); synchronized (stats) { stats.updates++; } } @PostPersist public void persist(Object entity) { System.out.println("@PostPersist: " + entity.getClass().getName()); Stats stats = getStats(entity); synchronized (stats) { stats.inserts++; } } @PostLoad public void load(Object entity) { System.out.println("@PostLoad: " + entity.getClass().getName()); Stats stats = getStats(entity); synchronized (stats) { stats.loads++; } } @PostRemove public void remove(Object entity) { System.out.println("@PostRemove: " + entity.getClass().getName()); Stats stats = getStats(entity); synchronized (stats) { stats.removes++; } } }
persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence:persistence version="1.0" xmlns:persistence="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd "> <persistence:persistence-unit name="titan" transaction-type="JTA"> <persistence:description>none</persistence:description> <persistence:jta-data-source>java:/TitanDB</persistence:jta-data-source> <persistence:properties> <persistence:property name="hibernate.hbm2ddl.auto" value="create"/> </persistence:properties> </persistence:persistence-unit> </persistence:persistence>
application.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd"> <application> <display-name>TitanCruisesExample</display-name> <module> <ejb>TravelAgentBean.jar</ejb> </module> <module> <ejb>EntityStats.jar</ejb> </module> <module> <ejb>DomainBean.jar</ejb> </module> </application>
build.xml
<?xml version="1.0" encoding="UTF-8"?> <project name="Packaging Generator" default="_packaging_generation_"> <target name="_packaging_generation_" depends="TitanCruisesExample" /> <target name="TitanCruisesExample" description="TitanCruises.ear" depends="TravelAgentBean"> <jar destfile="TitanCruises.ear"> <zipfileset dir="conf" prefix="META-INF"> <include name="application.xml" /> </zipfileset> <zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises10_2"> <include name="TravelAgentBean.jar" /> <include name="DomainBean.jar" /> <include name="EntityStats.jar" /> </zipfileset> </jar> </target> <target name="TravelAgentBean" description="DataAccessBean.jar" depends="EntityStats"> <jar destfile="TravelAgentBean.jar"> <zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises10_2/bin/com/titan/travelagent" prefix="com/titan/travelagent" /> </jar> </target> <target name="EntityStats" description="EntityStats.jar" depends="DomainBean"> <jar destfile="EntityStats.jar"> <zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises10_2/bin/com/titan/stats" prefix="com/titan/stats" /> </jar> </target> <target name="DomainBean" description="DomainBean.jar"> <jar destfile="DomainBean.jar"> <zipfileset dir="conf" prefix="META-INF"> <include name="persistence.xml" /> </zipfileset> <zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises10_2/bin/com/titan/domain" prefix="com/titan/domain" /> </jar> </target> </project>
Data Source: postgres-TitanDB-ds.xml
This file is deployed in the deploy directory of the JBoss Application Server.
<?xml version="1.0" encoding="UTF-8"?> <datasources> <local-tx-datasource> <jndi-name>TitanDB</jndi-name> <use-java-context>true</use-java-context> <connection-url>jdbc:postgresql://127.0.0.1:5432/ejb3db</connection-url> <driver-class>org.postgresql.Driver</driver-class> <user-name>ranjan</user-name> <password>ranjan</password> <metadata> <type-mapping>PostgreSQL 8.0</type-mapping> </metadata> </local-tx-datasource> </datasources>
Packaging Structure
TitanCruises.ear | |--- META-INF | | | |--- application.xml | | | |--- MENIFEST.MF | |--- DomainBean.jar | | | |--- META-INF | | | | | |--- persistence.xml | | | | | |--- MENIFEST.MF | | | |--- com | | | |--- titan | | | |--- domain | | | |--- Customer.class | |--- DataAccessBean.jar | | | |--- META-INF | | | | | |--- MENIFEST.MF | | | |--- com | | | |--- titan | | | |--- travelagent | | | |--- TravelAgentRemote.class | |--- TravelAgentBean.class |--- EntityStats.jar | | | |--- META-INF | | | | | |--- MENIFEST.MF | | | |--- com | | | |--- titan | | | |--- stats | | | |--- EntityStatsMBean.class | |--- EntityStats.class | |--- EntityListener.class
Server Console after successful deployment of the application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 16:30:57,642 INFO [JBossASKernel] Created KernelDeployment for: DomainBean.jar 16:30:57,656 INFO [JBossASKernel] installing bean: persistence.units:ear=TitanCruises.ear,unitName=titan 16:30:57,656 INFO [JBossASKernel] with dependencies: 16:30:57,656 INFO [JBossASKernel] and demands: 16:30:57,656 INFO [JBossASKernel] jboss.jca:name=TitanDB,service=DataSourceBinding 16:30:57,656 INFO [JBossASKernel] and supplies: 16:30:57,657 INFO [JBossASKernel] persistence.units:unitName=titan 16:30:57,657 INFO [JBossASKernel] Added bean(persistence.units:ear=TitanCruises.ear,unitName=titan) to KernelDeployment of: DomainBean.jar 16:30:57,770 INFO [STDOUT] ======> Creating interceptor metadata bridge 16:31:26,503 INFO [JBossASKernel] Created KernelDeployment for: TravelAgentBean.jar 16:31:26,503 INFO [JBossASKernel] installing bean: jboss.j2ee:ear=TitanCruises.ear,jar=TravelAgentBean.jar,name=TravelAgentBean,service=EJB3 16:31:26,503 INFO [JBossASKernel] with dependencies: 16:31:26,503 INFO [JBossASKernel] and demands: 16:31:26,503 INFO [JBossASKernel] persistence.units:ear=TitanCruises.ear,unitName=titan 16:31:26,503 INFO [JBossASKernel] jboss.ejb:service=EJBTimerService 16:31:26,503 INFO [JBossASKernel] and supplies: 16:31:26,503 INFO [JBossASKernel] jndi:TitanCruises/TravelAgentBean/remote 16:31:26,503 INFO [JBossASKernel] jndi:TravelAgentBean 16:31:26,503 INFO [JBossASKernel] Class:com.titan.travelagent.TravelAgentRemote 16:31:26,503 INFO [JBossASKernel] jndi:TitanCruises/TravelAgentBean/remote-com.titan.travelagent.TravelAgentRemote 16:31:26,503 INFO [JBossASKernel] Added bean(jboss.j2ee:ear=TitanCruises.ear,jar=TravelAgentBean.jar,name=TravelAgentBean,service=EJB3) to KernelDeployment of: TravelAgentBean.jar 16:31:26,533 INFO [PersistenceUnitDeployment] Starting persistence unit persistence.units:ear=TitanCruises.ear,unitName=titan 16:31:26,650 INFO [Version] Hibernate Annotations 3.4.0.CR1 16:31:26,726 INFO [Environment] Hibernate 3.3.0.CR1 16:31:26,740 INFO [Environment] hibernate.properties not found 16:31:26,748 INFO [Environment] Bytecode provider name : javassist 16:31:26,762 INFO [Environment] using JDK 1.4 java.sql.Timestamp handling 16:31:27,019 INFO [Version] Hibernate Commons Annotations 3.1.0.CR1 16:31:27,026 INFO [Version] Hibernate EntityManager 3.4.0.CR1 16:31:27,168 WARN [Ejb3Configuration] Persistence provider caller does not implement the EJB3 spec correctly. PersistenceUnitInfo.getNewTempClassLoader() is null. 16:31:27,349 INFO [AnnotationBinder] Binding entity from annotated class: com.titan.domain.Customer 16:31:27,431 INFO [EntityBinder] Bind entity com.titan.domain.Customer on table Customer 16:31:27,539 INFO [Version] Hibernate Validator 3.1.0.CR1 16:31:27,807 INFO [ConnectionProviderFactory] Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider 16:31:27,811 INFO [InjectedDataSourceConnectionProvider] Using provided datasource 16:31:28,501 INFO [SettingsFactory] RDBMS: PostgreSQL, version: 8.1.11 16:31:28,501 INFO [SettingsFactory] JDBC driver: PostgreSQL Native Driver, version: PostgreSQL 8.1 JDBC3 with SSL (build 412) 16:31:28,588 INFO [Dialect] Using dialect: org.hibernate.dialect.PostgreSQLDialect 16:31:28,605 INFO [TransactionFactoryFactory] Transaction strategy: org.hibernate.ejb.transaction.JoinableCMTTransactionFactory 16:31:28,637 INFO [TransactionManagerLookupFactory] instantiating TransactionManagerLookup: org.hibernate.transaction.JBossTransactionManagerLookup 16:31:29,156 INFO [TransactionManagerLookupFactory] instantiated TransactionManagerLookup 16:31:29,156 INFO [SettingsFactory] Automatic flush during beforeCompletion(): disabled 16:31:29,157 INFO [SettingsFactory] Automatic session close at end of transaction: disabled 16:31:29,157 INFO [SettingsFactory] JDBC batch size: 15 16:31:29,157 INFO [SettingsFactory] JDBC batch updates for versioned data: disabled 16:31:29,159 INFO [SettingsFactory] Scrollable result sets: enabled 16:31:29,159 INFO [SettingsFactory] JDBC3 getGeneratedKeys(): disabled 16:31:29,159 INFO [SettingsFactory] Connection release mode: auto 16:31:29,162 INFO [SettingsFactory] Default batch fetch size: 1 16:31:29,162 INFO [SettingsFactory] Generate SQL with comments: disabled 16:31:29,162 INFO [SettingsFactory] Order SQL updates by primary key: disabled 16:31:29,162 INFO [SettingsFactory] Order SQL inserts for batching: disabled 16:31: |


