You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by Alexander Saint Croix <sa...@gmail.com> on 2008/01/27 09:59:50 UTC

Fault loading example for OpenEJB3

Hey, guys--I finally got the fault loading example to work.  I'll post the
code here in the list so that other users can look at it in the future.

First, all of this code uses entity beans from the alpha-05 release of CORM
(my Open Source commercial O/R model project for Java), which can be
downloaded from
http://java.eremite.org/bin/view/CORM/CORM_Project_Downloads?rev=25

The example below shows how to use fault loading in an extended session
context in order to simplify testing the cascade relationships for multiple
collection-valued references inside of a single persistent entity bean.  My
entity bean is an instance of org.eremite.corm.party.Party (sorry, no public
SVN yet, but I'll paste some of the code below).

The major pieces I needed to create for this example were #1: The Context
factory I use to make sure all of my test cases don't create a new database
(this saves time), #2: The test case, #3: A Stateful Session bean "bean
manager" that contained an entity manager inside of an EXTENDED persistence
context, and its local interface (not shown), #4: the peristence.xml file,
which I place in my src/test/resources directory for mvn, #5: nachos, to
keep things calm down below while I worked.  I'll show the code for Party
and first four pieces below.  You will have to find your own nachos.  Also,
all of the code listed below is AFL 3.0 licensed, so have at it.

Exhibit #0: The Party class:

> package org.eremite.corm.party;
>
> import org.eremite.corm.BaseArchetype;
> import org.eremite.corm.party.address.AssociatedAddress;
> import org.eremite.corm.party.relationship.Capability;
> import org.eremite.corm.party.relationship.PartyRole;
>
> import javax.persistence.*;
> import java.util.*;
>
> @Entity
> public class Party extends BaseArchetype {
>
>     @OneToMany(cascade={
>             CascadeType.PERSIST,
>             CascadeType.MERGE,
>             CascadeType.REMOVE}, mappedBy="party")
>     private Set <AssociatedAddress> addresses = new HashSet
> <AssociatedAddress> ();
>
>     @OneToMany(cascade={
>             CascadeType.PERSIST,
>             CascadeType.MERGE,
>             CascadeType.REMOVE})
>     private Set <Binding> bindings = new HashSet <Binding> ();
>
>     @OneToMany(cascade={
>             CascadeType.PERSIST,
>             CascadeType.MERGE,
>             CascadeType.REMOVE})
>     private Set <RegisteredIdentifier> registeredIds =
>             new HashSet <RegisteredIdentifier> ();
>
>     @OneToMany(cascade={
>             CascadeType.PERSIST,
>             CascadeType.MERGE,
>             CascadeType.REMOVE})
>     private Set <Capability> capabilities = new HashSet<Capability>();
>
>     @OneToMany(cascade={
>             CascadeType.PERSIST,
>             CascadeType.MERGE,
>             CascadeType.REMOVE}, mappedBy="party")
>     private Set <PartyRole> roles = new HashSet <PartyRole> ();
>
>     /* Default Zero-arg Constructor */
>     public Party() {}
>
>     public Set<AssociatedAddress> getAddresses() {
>         return addresses;
>     }
>
>     public void setAddresses(Set<AssociatedAddress> addresses) {
>         this.addresses = addresses;
>     }
>
>     public Set<Binding> getPreferences() {
>         return bindings;
>     }
>
>     public void setPreferences(Set<Binding> preferences) {
>         this.bindings = bindings;
>     }
>
>     public Set<RegisteredIdentifier> getRegisteredIdentifiers() {
>         return registeredIds;
>     }
>
>     public void setRegisteredIdentifiers(Set<RegisteredIdentifier>
> registeredIds) {
>         this.registeredIds = registeredIds;
>     }
>
>     public Set<PartyRole> getPartyRoles() {
>         return roles;
>     }
>
>     public void setPartyRoles(Set<PartyRole> roles) {
>         this.roles = roles;
>     }
>
>     public Set<Capability> getCapabilities() {
>         return this.capabilities;
>     }
>
>     public void setCapabilities(Set<Capability> capabilities) {
>         this.capabilities = capabilities;
>     }
>
>     public void addPartyRole(PartyRole ... roles) {
>         getPartyRoles().addAll(Arrays.asList(roles));
>     }
>
>     public void addPartyRole(PartyRole role) {
>         getPartyRoles().add(role);
>     }
>
>     public void addRegisteredIdentifier(RegisteredIdentifier rid) {
>         getRegisteredIdentifiers().add(rid);
>     }
>
>     public void addRegisteredIdentifier(RegisteredIdentifier ... rids) {
>         getRegisteredIdentifiers().addAll(java.util.Arrays.asList(rids));
>     }
>
>     public void addPreference(Binding ... bindings) {
>         getPreferences().addAll(Arrays.asList(bindings));
>     }
>
>     public void addCapability(Capability ... capabilities) {
>         getCapabilities().addAll(Arrays.asList(capabilities));
>     }
>
>     public void addCapability(Capability capability) {
>         getCapabilities().add(capability);
>     }
>
>     public void addAddress(AssociatedAddress ... addresses) {
>         getAddresses().addAll(Arrays.asList(addresses));
>     }
>
>     public void addAddress(AssociatedAddress address) {
>         getAddresses().add(address);
>     }
> }
>

Note that the Party class has 5 collection-valued references to other
entities.  For brevity I'll not show the definitions of those entities
here.  Also note that Party and all other entities in my project descend
from the same MappedSuperclass, "Archetype".  This helps me considerably
during testing and other areas.  Archetype has a name, description and ID
field, and is not shown here.

Exhibit #1: The Context Factory

> package org.eremite.corm.party.testutil;
>
> import javax.naming.Context;
> import javax.naming.InitialContext;
> import javax.naming.NamingException;
> import java.util.Properties;
>
> public class ContextFactory {
>     private Context context;
>     private static ContextFactory instance;
>
>     public static Context reference() {
>         if(instance == null) instance = new ContextFactory();
>         return instance.getContext();
>     }
>
>     private ContextFactory() {
>         Properties p = new Properties();
>         p.put(Context.INITIAL_CONTEXT_FACTORY, "
> org.apache.openejb.client.LocalInitialContextFactory");
>         p.put("partyDB", "new://Resource?type=DataSource");
>         p.put("partyDB.JdbcDriver", "org.hsqldb.jdbcDriver");
>         p.put("partyDB.JdbcUrl", "jdbc:hsqldb:mem:partydb");
>
>         p.put("partyDBUnmanaged", "new://Resource?type=DataSource");
>         p.put("partyDBUnmanaged.JdbcDriver", "org.hsqldb.jdbcDriver");
>         p.put("partyDBUnmanaged.JdbcUrl", "jdbc:hsqldb:mem:partydb");
>         p.put("partyDBUnmanaged.JtaManaged", "false");
>         try {
>             context = new InitialContext(p);
>         } catch (NamingException e) {
>             e.printStackTrace();
>         }
>     }
>
>     private Context getContext() {
>         return this.context;
>     }
> }
>

The ContextFactory is something I whipped up to make sure that my different
TestCases didn't all recreate the InitialContext.  The addition of this
class helped me shave considerable time off of my maven build, and therefore
has been useful for speeding up development.

Exhibit #2: The Test Case

> package org.eremite.corm.party;
>
> import junit.framework.TestCase;
> import org.eremite.corm.Archetype;
> import org.eremite.corm.party.address.Address;
> import org.eremite.corm.party.address.AssociatedAddress;
> import org.eremite.corm.party.relationship.Capability;
> import org.eremite.corm.party.relationship.PartyRole;
> import org.eremite.corm.party.relationship.PartyRoleType;
> import org.eremite.corm.party.testutil.BeanManager;
> import org.eremite.corm.party.testutil.ComponentFactory;
> import org.eremite.corm.party.testutil.ExtendedBeanManager;
>
> import javax.naming.Context;
> import java.util.Iterator;
> import java.util.Set;
>
> public class PartyCascade02Test extends TestCase {
>
>     protected ExtendedBeanManager mgr;
>     protected BeanManager db;
>     protected ComponentFactory one;
>     protected Context context;
>
>     public void setUp() throws Exception {
>         super.setUp();
>
>         context = org.eremite.corm.party.testutil.ContextFactory.reference
> ();
>         mgr = (ExtendedBeanManager) context.lookup
> ("ExtendedBeanManagerLocal");
>         db = (BeanManager) context.lookup("BeanManagerLocal");
>         one = new ComponentFactory();
>     }
>
>     public void tearDown() throws Exception {
>         super.tearDown();
>     }
>
>     public void testFaultLoading() {
>
>         Party p1 = new Party();
>         PartyRole<Party> initialRole = new PartyRole<Party>(new
> PartyRoleType(), p1);
>         Capability initialCapability = new Capability();
>         Binding initialPreference = new Binding();
>         RegisteredIdentifier initialRegID = new RegisteredIdentifier();
>         AssociatedAddress initialAA = new AssociatedAddress(p1, new
> Address());
>
>         p1.addCapability(initialCapability);
>         p1.addPreference(initialPreference);
>         p1.addRegisteredIdentifier(initialRegID);
>
>         assertNotNull(p1.getAddresses());
>         assertNotNull(p1.getCapabilities());
>         assertNotNull(p1.getPartyRoles());
>         assertNotNull(p1.getPreferences());
>         assertNotNull(p1.getRegisteredIdentifiers());
>
>         assertTrue(p1.getAddresses().contains(initialAA));
>         assertTrue(p1.getCapabilities().contains(initialCapability));
>         assertTrue(p1.getPartyRoles().contains(initialRole));
>         assertTrue(p1.getPreferences().contains(initialPreference));
>         assertTrue(p1.getRegisteredIdentifiers().contains(initialRegID));
>
>         // First unit of work -- cascading persist
>         mgr.persist(p1);
>         long id = p1.getID();
>         assertTrue(id != 0);
>
>         // Second unit of work -- get party by ID
>         Party p2 = mgr.getPartyByID(id);
>         assertNotNull(p2);
>         assertNotNull(p2.getAddresses());
>         assertNotNull(p2.getCapabilities());
>         assertNotNull(p2.getPreferences());
>         assertNotNull(p2.getPartyRoles());
>         assertNotNull(p2.getRegisteredIdentifiers());
>
>         assertTrue(p2.getAddresses().size() > 0);
>         assertTrue(p2.getCapabilities().size() > 0);
>         assertTrue(p2.getPreferences().size() > 0);
>         assertTrue(p2.getPartyRoles().size() > 0);
>         assertTrue(p2.getRegisteredIdentifiers().size() > 0);
>
>         Set<AssociatedAddress> addresses = p2.getAddresses();
>         Set<Capability> capabilities = p2.getCapabilities();
>         Set<Binding> preferences = p2.getPreferences();
>         Set<PartyRole> partyRoles = p2.getPartyRoles();
>         Set<RegisteredIdentifier> regIDs = p2.getRegisteredIdentifiers();
>
>         assertNotNull(addresses);
>         assertNotNull(capabilities);
>         assertNotNull(preferences);
>         assertNotNull(partyRoles);
>         assertNotNull(regIDs);
>
>         assertTrue(hasArchetypeWithID(addresses, initialAA.getID()));
>         assertTrue(hasArchetypeWithID(capabilities,
> initialCapability.getID()));
>         assertTrue(hasArchetypeWithID(preferences, initialPreference.getID
> ()));
>         assertTrue(hasArchetypeWithID(partyRoles, initialRole.getID()));
>         assertTrue(hasArchetypeWithID(regIDs, initialRegID.getID()));
>
>         p2.setName("preMerge");
>         Archetype address2, cap2, pref2, role2, regID2,
>                 address3, cap3, pref3, role3, regID3;
>
>         address2 = getByID(addresses, initialAA.getID());
>         cap2 = getByID(capabilities, initialCapability.getID());
>         pref2 = getByID(preferences, initialPreference.getID());
>         role2 = getByID(partyRoles, initialRole.getID());
>         regID2 = getByID(regIDs, initialRegID.getID());
>
>         address2.setName("preMerge address");
>         cap2.setName("preMerge capability");
>         pref2.setName("preMerge preference");
>         role2.setName("preMerge partyRole");
>         regID2.setName("preMerge regID");
>
>         // Third unit of work -- cascading merges
>         mgr.merge(p2);
>
>         // Fourth unit of work -- get party by ID
>         Party p3 = mgr.getPartyByID(id);
>
>         assertNotNull(p3);
>         assertNotNull(p3.getAddresses());
>         assertNotNull(p3.getCapabilities());
>         assertNotNull(p3.getPreferences());
>         assertNotNull(p3.getPartyRoles());
>         assertNotNull(p3.getRegisteredIdentifiers());
>
>         assertTrue(p3.getAddresses().size() > 0);
>         assertTrue(p3.getCapabilities().size() > 0);
>         assertTrue(p3.getPreferences().size() > 0);
>         assertTrue(p3.getPartyRoles().size() > 0);
>         assertTrue(p3.getRegisteredIdentifiers().size() > 0);
>
>         Set<AssociatedAddress> addresses2 = p3.getAddresses();
>         Set<Capability> capabilities2 = p3.getCapabilities();
>         Set<Binding> preferences2 = p3.getPreferences();
>         Set<PartyRole> partyRoles2 = p3.getPartyRoles();
>         Set<RegisteredIdentifier> regIDs2 = p3.getRegisteredIdentifiers();
>
>         assertNotNull(addresses2);
>         assertNotNull(capabilities2);
>         assertNotNull(preferences2);
>         assertNotNull(partyRoles2);
>         assertNotNull(regIDs2);
>
>         assertTrue(hasArchetypeWithID(addresses2, initialAA.getID()));
>         assertTrue(hasArchetypeWithID(capabilities2,
> initialCapability.getID()));
>         assertTrue(hasArchetypeWithID(preferences2,
> initialPreference.getID()));
>         assertTrue(hasArchetypeWithID(partyRoles2, initialRole.getID()));
>         assertTrue(hasArchetypeWithID(regIDs2, initialRegID.getID()));
>
>         address3 = getByID(addresses2, initialAA.getID());
>         cap3 = getByID(capabilities2, initialCapability.getID());
>         pref3 = getByID(preferences2, initialPreference.getID());
>         role3 = getByID(partyRoles2, initialRole.getID());
>         regID3 = getByID(regIDs2, initialRegID.getID());
>
>         assertEquals(p2.getName(), p3.getName());
>         assertEquals(address2.getName(), address3.getName());
>         assertEquals(cap2.getName(), cap3.getName());
>         assertEquals(pref2.getName(), pref3.getName());
>         assertEquals(role2.getName(), role3.getName());
>         assertEquals(regID2.getName(), regID3.getName());
>
>         // 5th unit of work -- cascading remove
>         mgr.remove(p3);
>
>         // 6th - 13th units of work -- verification
>         assertEquals(0, mgr.sizeOf("Party"));
>         assertEquals(0, mgr.sizeOf("AssociatedAddress"));
>         assertEquals(0, mgr.sizeOf("Capability"));
>         assertEquals(0, mgr.sizeOf("Binding"));
>         assertEquals(0, mgr.sizeOf("PartyRole"));
>         assertEquals(0, mgr.sizeOf("RegisteredIdentifier"));
>         assertEquals(1, mgr.sizeOf("PartyRoleType"));
>         assertEquals(1, mgr.sizeOf("Address"));
>     }
>
>     private static void traceln(Object ... o) {
>         for(Object item : o) System.out.println(item);
>     }
>
>     private boolean hasArchetypeWithID(Set s, long ID) {
>         Iterator<Archetype> iter = (Iterator<Archetype>)s.iterator();
>         while(iter.hasNext()) {
>             Archetype a = iter.next();
>             if(a.getID() == ID) return true;
>         }
>         return false;
>     }
>
>     private Archetype getByID(Set s, long ID) {
>         Iterator<Archetype> iter = (Iterator<Archetype>)s.iterator();
>         while(iter.hasNext()) {
>             Archetype a = iter.next();
>             if(a.getID() == ID) return a;
>         }
>         fail("There was no archetype with ID==" + ID + " in the set.");
>         return null;
>     }
> }


Note that this was the test case for a class with 5 collection valued
references.  My goal was to reduce the number of times I needed to go to the
database while performing tests, so as to speed up the testing phase of my
maven build and thereby speed up development.  Major gains were between the
2nd and 6th units of work, as in previous versions I was unable to use fault
loading (for reasons which will be discussed below).

Exhibit #3: The Stateful Session Bean

> package org.eremite.corm.party.testutil;
>
> import org.eremite.corm.Archetype;
> import org.eremite.corm.party.Party;
>
> import javax.ejb.Stateful;
> import javax.persistence.EntityManager;
> import javax.persistence.PersistenceContext;
> import javax.persistence.PersistenceContextType;
> import javax.persistence.Query;
> import java.util.List;
>
> @Stateful(name="ExtendedBeanManager")
> public class ExtendedBeanManagerImpl implements ExtendedBeanManager {
>
>     @PersistenceContext(
>             unitName = "party-test-unit",
>             type = PersistenceContextType.EXTENDED)
>     private EntityManager em;
>
>     public Party getPartyByID(long ID) {
>         Query q = em.createQuery("SELECT a FROM Party as a WHERE a.ID=" +
> ID);
>         return (Party) q.getSingleResult();
>     }
>
>     public long persist(Archetype a) {
>         em.persist(a);
>         return a.getID();
>     }
>
>     public void merge(Archetype a) {
>         em.merge(a);
>     }
>
>     public void remove(Archetype a) {
>         em.remove(a);
>         em.flush();
>     }
>
>     public int sizeOf(String table) {
>         Query q = em.createQuery("SELECT a FROM " + table + " as a");
>         return q.getResultList().size();
>     }
> }


Exhibit #4: The persistence.xml file

> <?xml version="1.0" encoding="UTF-8"?>
> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
>
>   <persistence-unit name="party-test-unit">
>     <jta-data-source>java:openejb/Resource/partyDB</jta-data-source>
>
> <non-jta-data-source>java:openejb/Resource/partyDBUnmanaged</non-jta-data-source>
>     <class>org.eremite.corm.BaseArchetype</class>
>     <class>org.eremite.corm.party.address.Address</class>
>     <class>org.eremite.corm.party.address.AssociatedAddress</class>
>     <class>org.eremite.corm.party.address.EmailAddress</class>
>     <class>org.eremite.corm.party.address.GeographicAddress</class>
>     <class>org.eremite.corm.party.address.ISOCountryCode</class>
>     <class>org.eremite.corm.party.address.Locale</class>
>     <class>org.eremite.corm.party.address.TelecomAddress</class>
>     <class>org.eremite.corm.party.address.WebPageAddress</class>
>     <class>org.eremite.corm.party.relationship.AssignedResponsibility
> </class>
>     <class>org.eremite.corm.party.relationship.Capability</class>
>     <class>org.eremite.corm.party.relationship.PartyRelationship</class>
>     <class>org.eremite.corm.party.relationship.PartyRelationshipType
> </class>
>     <class>org.eremite.corm.party.relationship.PartyRole</class>
>     <class>org.eremite.corm.party.relationship.PartyRoleType</class>
>     <class>org.eremite.corm.party.relationship.Responsibility</class>
>     <class>org.eremite.corm.party.Organization</class>
>     <class>org.eremite.corm.party.OrganizationName</class>
>     <class>org.eremite.corm.party.Party</class>
>     <class>org.eremite.corm.party.PartySignature</class>
>     <class>org.eremite.corm.party.Person</class>
>     <class>org.eremite.corm.party.PersonName</class>
>     <class>org.eremite.corm.party.Binding</class>
>     <class>org.eremite.corm.party.BindingValue</class>
>     <class>org.eremite.corm.party.BindingType</class>
>     <class>org.eremite.corm.party.RegisteredIdentifier</class>
>
>     <properties>
>       <property name="openjpa.jdbc.SynchronizeMappings"
> value="buildSchema(ForeignKeys=true,
> SchemaAction='add,deleteTableContents')"/>
>       <!--<property name="openjpa.Log" value="SQL=TRACE, Query=TRACE"/>-->
>     </properties>
>   </persistence-unit>
> </persistence>


I did not change my persistence.xml file at all from the one I normally use
for testing.

My bean manager for this example was a complete rewrite of my former one.
The former bean manager was a Stateless Session Bean with an EntityManager
that operated in a TRANSACTION typed session context.  I do not know whether
it is possible to use fault loading from a Stateless Session Bean and from
an EntityManager that uses a TRANSACTION typed session context.  However, I
can confirm that the technique DOES work if one uses a Stateful Session Bean
with an EM that operates in an EXTENDED typed session context.  I will now
go through my cascade tests and update them to use this new mechanism, and
then will rinse and repeat for the rest of the modules in my project.

The overall result includes fewer trips to the database, simpler test cases,
forward progress on my project, and a much happier developer.

Regards,
--
Alexander R. Saint Croix