4 Replies Latest reply on Jul 16, 2006 11:57 AM by knaveofhearts

    Trouble with transactions

    knaveofhearts

      I am missing something fundamental about transactions and the discussion of entity relationships in ch. 7 combined with inheritence, as in ch. 8. There are a client, a stateless session bean, and 3 entities: GeopolUnit, Planet, and Country. Planet and Country both inherit from GeopolUnit. Planet is supposed to contain a list of countries, in a one-to-many unidirectional relationship. In the client, I can create a planet and a country separately. But when I try to create the planet already containing a country by un-commenting the "planet.add(country);" line in the client code listing below, I get the error. I have tried various combinations of putting methods into transactions and flushing things, but so far have been unsuccessful. (I think I ought to be able to omit the "createCountry" call in the client because of the cascade PERSIST constraint, but I get the same kind of error regardless of whether that call is in or out.)

      Any help is appreciated.
      K/H

      [java] Exception in thread "main" java.lang.RuntimeException: org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[Forma tId=257, GlobalId=mulder.vorticityCorp.com/24, BranchQual=, localId=24] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.persistence.PersistenceEx ception: org.hibernate.TransientObjectException: com.ejbWB.geopolUnit.Country)
       [java] at org.jboss.aspects.tx.TxPolicy.handleEndTransactionException(TxPolicy.java:198)
       [java] at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:180)
       [java] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
       [java] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:197)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:78)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:225)
       [java] at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:106)
       [java] at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:828)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:681)
       [java] at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:358)
       [java] at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:412)
       [java] at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:239)
       [java] Caused by: org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=mulder.vorticityCorp.com/2 4, BranchQual=, localId=24] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.persistence.PersistenceException: org.hibernate.TransientObjectExcept ion: com.ejbWB.geopolUnit.Country)
       [java] at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:372)
       [java] at org.jboss.tm.TxManager.commit(TxManager.java:240)
       [java] at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:175)
       [java] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
       [java] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:197)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:78)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:225)
       [java] at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:106)
       [java] at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:828)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:681)
       [java] at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:358)
       [java] at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:412)
       [java] at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:239)
       [java] at org.jboss.remoting.RemoteClientInvoker.invoke(RemoteClientInvoker.java:190)
       [java] at org.jboss.remoting.Client.invoke(Client.java:525)
       [java] at org.jboss.remoting.Client.invoke(Client.java:488)
       [java] at org.jboss.aspects.remoting.InvokeRemoteInterceptor.invoke(InvokeRemoteInterceptor.java:55)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.tx.ClientTxPropagationInterceptor.invoke(ClientTxPropagationInterceptor.java:61)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.security.SecurityClientInterceptor.invoke(SecurityClientInterceptor.java:55)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.remoting.IsLocalInterceptor.invoke(IsLocalInterceptor.java:65)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessRemoteProxy.invoke(StatelessRemoteProxy.java:102)
       [java] at $Proxy0.createPlanet(Unknown Source)
       [java] at com.ejbWB.clients.Client.main(Client.java:22)
       [java] Caused by: javax.persistence.PersistenceException: org.hibernate.TransientObjectException: com.ejbWB.geopolUnit.Country
       [java] at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:567)
       [java] at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:484)
       [java] at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1491)
       [java] at org.jboss.tm.TransactionImpl.beforePrepare(TransactionImpl.java:1110)
       [java] at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:324)
       [java] at org.jboss.tm.TxManager.commit(TxManager.java:240)
       [java] at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:175)
       [java] at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
       [java] at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:197)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:78)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       [java] at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       [java] at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:225)
       [java] at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:106)
       [java] at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:828)
       [java] at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:681)
       [java] at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:358)
       [java] at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:412)
       [java] at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:239)
       [java] Caused by: org.hibernate.TransientObjectException: com.ejbWB.geopolUnit.Country
       [java] at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:216)
       [java] at org.hibernate.type.EntityType.getIdentifier(EntityType.java:108)
       [java] at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:71)
       [java] at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:732)
       [java] at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1080)
       [java] at org.hibernate.action.CollectionRecreateAction.execute(CollectionRecreateAction.java:26)
       [java] at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
       [java] at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
       [java] at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:143)
       [java] at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
       [java] at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
       [java] at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:993)
       [java] at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:340)
       [java] at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:475)
      


      The client:
      package com.ejbWB.clients;
      
       import com.ejbWB.admin.AdminRemote;
       import com.ejbWB.geopolUnit.*;
       import javax.naming.*;
       import javax.rmi.PortableRemoteObject;
      
       public class Client
       {
       public static void main(String [] args) {
       try {
       Context jndiContext = getInitialContext();
       Object ref = jndiContext.lookup("AdminBean/remote");
       AdminRemote admin = (AdminRemote)ref;
       Planet planet = new Planet();
       Country country = new Country("Italy");
       long c_id = admin.createCountry(country);
       System.out.println("country id=" + c_id);
       //planet.add(country);
       long p_id = admin.createPlanet(planet);
       System.out.println("planet id=" + p_id);
       }
       catch (javax.naming.NamingException ne) {
       ne.printStackTrace();
       }
       }
       public static Context getInitialContext()
       throws javax.naming.NamingException {
       return new javax.naming.InitialContext();
       }
       }


      The session bean:
      package com.ejbWB.admin;
       import javax.ejb.*;
       import javax.persistence.*;
       import java.util.*;
       import com.ejbWB.geopolUnit.*;
      
       @Stateless
       public class AdminBean implements AdminRemote
       {
       @PersistenceContext(unitName="ejbWB") private EntityManager manager;
      
       public long createPlanet(Planet planet) {
       manager.persist(planet);
       return planet.getId();
       }
       public long createCountry(Country country) {
       manager.persist(country);
       return country.getId();
       }
       /* I WOULD LIKE TO BE ABLE TO HAVE THIS METHOD WORK
       public Planet findPlanet(long pKey) {
       Planet planet = manager.find(Planet.class, pKey);
       List<Country> countries = planet.getCountries();
       Iterator iter = countries.iterator();
       while (iter.hasNext()) {
       Country c = (Country)iter.next();
       String name = c.getName();
       }
       return planet;
       }
       */
       }[size]

      The remote interface is obvious and is omitted.

      The three entities:
      package com.ejbWB.geopolUnit;
       import javax.persistence.*;
      
       @Entity
       @Inheritance(strategy=InheritanceType.JOINED)
       public abstract class GeopolUnit implements java.io.Serializable {
       public GeopolUnit(String name) { setName(name); }
      
       @Id
       @GeneratedValue
       public long getId() { return id; }
       public void setId(long id) { this.id = id; }
      
       @Column(nullable=false)
       public String getName() { return name; }
       public void setName(String name) { this.name = new String(name); }
      
       private String name;
       private long id;
       }
       //--------------
       package com.ejbWB.geopolUnit;
       import javax.persistence.*;
       import java.util.List;
       import java.util.LinkedList;
      
       @Entity
       public class Planet extends GeopolUnit implements java.io.Serializable {
       public Planet() { super("Earth"); }
       public void add(Country country) { countries.add(country); }
      
       @OneToMany(cascade={CascadeType.PERSIST})
       @OrderBy("name ASC")
       public List<Country> getCountries() { return countries; }
       public void setCountries(List<Country> countries) { this.countries = countries; }
      
       private List<Country> countries = new LinkedList<Country>();
       }
       //--------------
       package com.ejbWB.geopolUnit;
       import javax.persistence.*;
      
       @Entity
       public class Country extends GeopolUnit implements java.io.Serializable {
       public Country(String name) { super(name); }
       }



        • 1. Re: Inheritance + one-to-many: was "Trouble with transaction
          knaveofhearts

          I no longer think this is a problem with transactions but rather OR mapping. Could someone please tell me, or have a code example of the annotations to configure combining inheritance with a one-to-many relationship among entities (i.e., A is the superclass of B. B contains a Collection of C objects) or for that matter a one-to-one (B contains an A) or many-to-many relationship? At this point, I am not picky about whether the relationship is uni- or bidirectional.

          As an trial, I first converted exercise 7.1 from the workbook so that the entities run in a container. Client1 exercises a one-to-one relationship between Customer and Address; Client2, a one-to-many relationship between Customer and Phone. The Admin EJB includes createCustomer(), findCustomer(), and updateCustomer() methods implemented in the obvious way. The clients interact with a stateless session Admin EJB As The new Client1 and Client2 produce the correct results after conversion.

          Then I created a "Base" entity and made Customer extend Base using the JOINED strategy. I eliminated the id field from the Customer class. This breaks both Client1 and Client2 in the sense that the Address field and the Collection member variables in the Customer object remain null after the merge performed by updateCustomer() in Admin. This is true even within the updateCustomer method/transaction itself, so it does not help to set the fetch type to EAGER or to traverse the fields explicitly.

          Suggestions?

          • 2. Re: Trouble with transactions
            knaveofhearts

            A correction:
            In the first paragraph of my previous post, please replace "B contains an A" with "B contains a C."

            And a clarification:
            In the third paragraph, the Base class contains only an "id" field and associated getId (annotated with @Id) and setId methods.

            • 3. Re: Trouble with transactions
              knaveofhearts

              I have gotten the original concept (i.e., Planet is a Geopolitical Unit, Country is a Geopolitical Unit, Planet contains collection of Countries) to work. Two things that caused me problems in coming up with a solution empirically:
              - Having a subclass entity that is serializable of a base entity class that is not. Entities supposedly don't have to be serializable (Burke et al., Enterprise Java Beans 3.0, p. 52), but I have not tried going back and tried making them all non-serializable;
              - Not having an empty constructor at each level; I do not remember reading that this as a requirement of entity POJOs in Burke et al., but it is certainly not in the index!!!

              The code I wound up with does not look especially like my original posting, since I proceeded by getting one small piece working right, and then building on it incrementally, rather than trying to figure out what was wrong with what I had done originally.

              K/H

              • 4. Re: Trouble with transactions
                knaveofhearts

                The requirement of a constructor with no arguments is mentioned in the text (p. 137).