2 Replies Latest reply on Apr 8, 2007 3:27 PM by kruno

    EntityManager and Conversation contex

    kruno

      I read both books Seam Contextual components and JBoss® Seam: Simplicity and Power Beyond Java? EE from Safari but I can't seem to find the answer.
      I was under impression that persistence context is the same as hiberante session and that if @PersistenceContext(type = EXTENDED) that it would last during conversation, and that it would be shared between EntityManagers from two different action beans if they are in the same conversation.
      I hope sample code would explain better my question:
      I made a little example.
      first there are two entity beans directory and file
      directory has a set of files
      Directory:

      package orka.test;
      
      import java.util.LinkedHashSet;
      import java.util.Set;
      
      import javax.persistence.CascadeType;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      
      import org.jboss.seam.annotations.Name;
      
      @Entity
      @Name("directory")
      @Table(name="directory")
      public class Directory {
      
       @Id
       @GeneratedValue(strategy=GenerationType.TABLE)
       private long sifra;
      
       private String name;
      
       @OneToMany(cascade={CascadeType.ALL},mappedBy="directory")
       private Set<File>files= new LinkedHashSet<File>();
      
      
      
      
       public Set<File> getFiles() {
       return files;
       }
      
      
       public void setFiles(Set<File> files) {
       this.files = files;
       }
      
      
       public long getSifra() {
       return sifra;
       }
      
      
       public void setSifra(long sifra) {
       this.sifra = sifra;
       }
      
      
       public String getName() {
       return name;
       }
      
      
       public void setName(String name) {
       this.name = name;
       }
      
      
      
      }
      
      


      File:
      package orka.test;
      
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.ManyToOne;
      import javax.persistence.Table;
      
      import org.hibernate.validator.NotNull;
      import org.jboss.seam.annotations.Name;
      
      
      @Entity
      @Name("file")
      @Table(name="file")
      public class File {
      
       @Id
       @GeneratedValue(strategy = GenerationType.TABLE)
       private long sifra;
      
       @NotNull
       private String name;
      
      
       @ManyToOne
       @JoinColumn(name="directory")
       private Directory directory;
      
      
       //geters seters
      
       public String getName() {
       return name;
       }
      
       public void setName(String name) {
       this.name = name;
       }
      
       public long getSifra() {
       return sifra;
       }
      
       public void setSifra(long sifra) {
       this.sifra = sifra;
       }
      
       public Directory getDirectory() {
       return directory;
       }
      
       public void setDirectory(Directory directory) {
       this.directory = directory;
       }
      
      
      
      }
      
      


      Then two action beans: DirectoryActionBean and FileActionBean
      DirectoryActionBean:
      package orka.test;
      
      import static javax.persistence.PersistenceContextType.EXTENDED;
      
      import javax.ejb.Remove;
      import javax.ejb.Stateful;
      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      
      import org.jboss.seam.annotations.Create;
      import org.jboss.seam.annotations.Destroy;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.log.Log;
      
      @Stateful
      @Name("directoryAction")
      public class DirectoryActionBean implements DirectoryAction {
      
       @PersistenceContext(type = EXTENDED)
       private EntityManager manager;
      
       @SuppressWarnings("unused")
       @org.jboss.seam.annotations.Logger
       private Log log;
      
       @In(required = false)
       @Out
       Directory directory;
      
       public void saveDir() {
       manager.persist(directory);
       }
      
       public String goFiles() {
       return "files";
       }
      
       @Remove
       @Destroy
       public void destroy() {
      
       }
      
       @Create
       public void create() {
      
       directory = new Directory();
       directory.setName("dirOne");
       manager.persist(directory);
      
       }
      
      }
      
      


      FileActionBean:
      package orka.test;
      
      import static javax.persistence.PersistenceContextType.EXTENDED;
      
      import javax.ejb.Remove;
      import javax.ejb.Stateful;
      import javax.persistence.EntityManager;
      import javax.persistence.PersistenceContext;
      
      import org.jboss.seam.annotations.Destroy;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.log.Log;
      
      
      
      
      @Stateful
      @Name("fileAction")
      public class FileActionBean implements FileAction {
      
      
       @PersistenceContext(type = EXTENDED)
       private EntityManager manager;
      
       @SuppressWarnings("unused")
       @org.jboss.seam.annotations.Logger
       private Log log;
      
       @In
       @Out
       Directory directory;
      
       public void newFile(){
       File file= new File();
       file.setName("fileOne");
       file.setDirectory(directory);
       directory.getFiles().add(file);
       manager.persist(file);
       }
      
      
       public String backToDir(){
       return "dir";
       }
      
       @Remove
       @Destroy
       public void destroy() {
      
       }
      }
      
      


      and at last part of pages.xml:
      
       <page view-id="/directory.jsp">
       <begin-conversation join="true"/>
       <navigation >
       <rule if-outcome="files">
       <redirect view-id="/file.jsp">
       </redirect>
       </rule>
      
       </navigation>
       </page>
      
       <page view-id="/file.jsp">
       <navigation >
       <rule if-outcome="dir">
       <redirect view-id="/directory.jsp">
       </redirect>
       </rule>
      
       </navigation>
       </page>
      

      I will not bother you with jsp pages let just say that directory.jsp references only directory entity bean a makes calls only to directoryActionBean it is the same pattern for file.jsp
      Now to explain what I do: At first
      I create one directory from directoryAction than go to file.jsp and create file, add him in directory and persist file.
      After that I return focus to directory.jsp and invoke method save.
      Then I get exception
      org.hibernate.PersistentObjectException: detached entity passed to persist: orka.test.File
       javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: orka.test.File
       at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:647)
       at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:218)
       at org.jboss.ejb3.entity.ExtendedEntityManager.persist(ExtendedEntityManager.java:104)
       at orka.test.DirectoryActionBean.saveDir(DirectoryActionBean.java:33)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
       at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
       at org.jboss.seam.intercept.EJBInvocationContext.proceed(EJBInvocationContext.java:37)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:55)
       at org.jboss.seam.interceptors.BijectionInterceptor.bijectNonreentrantComponent(BijectionInterceptor.java:79)
       at org.jboss.seam.interceptors.BijectionInterceptor.bijectComponent(BijectionInterceptor.java:58)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:18)
       at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:169)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:64)
       at org.jboss.seam.interceptors.ManagedEntityIdentityInterceptor.aroundInvoke(ManagedEntityIdentityInterceptor.java:36)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:18)
       at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:169)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:64)
       at org.jboss.seam.interceptors.OutcomeInterceptor.interceptOutcome(OutcomeInterceptor.java:21)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:18)
       at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:169)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:64)
       at org.jboss.seam.interceptors.ConversationInterceptor.endOrBeginLongRunningConversation(ConversationInterceptor.java:52)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:18)
       at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:169)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:64)
       at org.jboss.seam.interceptors.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:27)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.seam.util.Reflections.invoke(Reflections.java:18)
       at org.jboss.seam.intercept.Interceptor.aroundInvoke(Interceptor.java:169)
       at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:64)
       at org.jboss.seam.intercept.RootInterceptor.createSeamInvocationContext(RootInterceptor.java:144)
       at org.jboss.seam.intercept.RootInterceptor.invokeInContexts(RootInterceptor.java:129)
       at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:102)
       at org.jboss.seam.intercept.SessionBeanInterceptor.aroundInvoke(SessionBeanInterceptor.java:50)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:118)
       at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.entity.ExtendedPersistenceContextPropagationInterceptor.invoke(ExtendedPersistenceContextPropagationInterceptor.java:71)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:46)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
       ... 68 more
      

      It works fine if I merge directory before persist, but I don't understand why do I have to merge some thing if it was changed in side long running session and it should not have been detached. Maybe I am doing some thing wrong or I did not understand concept of conversation very well.
      Like I sad at the beginning I understood that one session could span many request/response cycles and many action beans as long as they are in one conversation and session is long-running.
      To merge some thing before persist in some situations is not a big deal, but I would really like to fully understand concepts behind seam
      Please Explain!!!
      Thanks in advance Kruno.