11 Replies Latest reply on Jun 11, 2009 3:49 PM by alin.heyoulin.qq.com

    Web Beans RI and equivalent (if any) to SMPC?

    gonorrhea

      Does the Web Beans RI have an equivalent to Seam-managed persistence context?  (I have a feeling the answer to this is no but Seam 3 does).


      In particular, referring to figure 9.1 in Seam in Action (DAllen), we note the independence of a Seam-managed persistence context with the coupling of the container-managed persistence managers to their stateful session bean components.


      So currently in Seam 2.x, the options for an EntityManager (which manages a PC) are the following in an EE envmt using session beans (typically SFSB) to model the conversations:



      1. transaction-scoped, container-managed

      2. extended, container-managed

      3. extended, Seam-managed (SMPC)



      According to JPA (Mike Keith), we believe that container-managed, transaction-scoped entity managers are the best model for most applications.


      I myself (and I'm sure GKing and rest of JBoss/Seam core team) have doubts about the above comment.  Entity detachment after tx commits, potential lazy-loading exceptions during object navigation in JSP/JSF, etc.


      My question is this:


      whether it's Seam 2, Seam 3, or Web Beans RI, if you need to ensure atomic conversations in a scenario with three conversation-scoped SFSBs, each one serving as a backing bean for a separate form on the same page, is it best to not use SMPC with manual flush (or equivalent in Web Beans)?


      If you use Hibernate MANUAL flush mode with SMPC to achieve atomic conversation, the problem is that if you only have one SFSB, any manual flush() of the PC will cause updates to managed entities in all three forms to happen if the entities are dirty aka write-behind (when you only want one form to be updated!)  You lose isolation and the symptom is premature updates to entities that were not supposed to be updated/synchronized.  If you use AUTO (default) flush, the PC is flushed when tx commits after completion of SFSB business method (assuming there is no JPAQL query in the method, in which case the persistence provider may flush before the query).


      So to fix this in Web Beans or Seam 3, would a good solution be to break the SFSB into three SFSBs (one per form in the facelet/JSF page) and use @PersistenceContext, either tx-scoped or extended type, rather than @In EntityManager entityManager (SMPC) with one SFSB?


      JPA (Mike Keith): Extended entity managers work with a single persistence context that is tied to the life cycle of a SFSB.  Does that mean that if you use @PersistenceContext(type=PersistenceContextType.EXTENDED) in more than one SFSB, each one is unique and manages a different set of entities? 


      Whereas in the case of SMPC, everytime it is injected in a Seam component, it is managing the same set of entities as its reference in another Seam component.


      Well I guess it would be easy enough to prove this by doing a em.contains() in each SFSB and see if a particular entity is contained in more than one SFSB/PC or not...

        • 1. Re: Web Beans RI and equivalent (if any) to SMPC?
          gonorrhea

          Ok, I have a better understanding after reading pg. 356 of SiA (DAllen):



          What sets the Seam-managed persistence context apart from its
          container-managed counterpart is that it’s stored directly in the conversation, making
          it a first-class citizen of the application, rather than being bound to the lifetime of a
          single component. Consider that if an SFSB hosting an extended persistence context is
          removed, the persistence context goes along with it. In contrast, a Seam-managed persistence
          context remains available as long as the conversation is active, regardless of
          which components come and go.
          The best part is that you can share the persistence
          context between Java EE and non–Java EE components alike without having to worry
          about complex (and tricky) propagation rules. Although the extended persistence
          context in EJB 3 is a good start, Seam is better at handling this task.

          Was SMPC (or SMPC equivalent: WBPC?) considered as part of 299?  If no, why?

          • 2. Re: Web Beans RI and equivalent (if any) to SMPC?
            gavin.king

            Does the Web Beans RI have an equivalent to Seam-managed persistence context? (I have a feeling the answer to this is no but Seam 3 does).

            Exactly. Seam3 will provide a portable extension that lets you write:


            @Produces @ConversationScoped @PersistenceContext(type=EXTENDED)
            EntityManager myConversationScopedEntityManager;



            And then inject the conversation-scoped PC like this:


            @Current EntityManager theConversationScopedEntityManager;

            • 3. Re: Web Beans RI and equivalent (if any) to SMPC?
              gonorrhea

              So you're saying we now would have to do a double-injection of two different EntityManager instances in the same SFSB?

              • 4. Re: Web Beans RI and equivalent (if any) to SMPC?
                gavin.king

                So you're saying we now would have to do a double-injection of two different EntityManager instances in the same SFSB?

                No, of course not. Please check the spec if you want to understand this stuff properly.

                • 5. Re: Web Beans RI and equivalent (if any) to SMPC?

                  Arbi Sookazian wrote on Jun 05, 2009 08:30:


                  So you're saying we now would have to do a double-injection of two different EntityManager instances in the same SFSB?


                  Double injection?  No... one outjection and many injections, this code:


                  @Produces @ConversationScoped @PersistenceContext(type=EXTENDED)
                  EntityManager myConversationScopedEntityManager;
                  



                  it outjects the EntityManager in to the Conversation scope. Normally you only have to put this in the 1 component that will act as the Producer of EntityManagers (it is kind of like Seam 2 @Factory ) .


                  And this code:


                  
                  @Current EntityManager theConversationScopedEntityManager;
                  
                  




                  it injects it on the component where you want to use one of the Produced EntityManager. It is kind of like @In in Seam 2 .


                  I hope I understood it correctly...


                  • 6. Re: Web Beans RI and equivalent (if any) to SMPC?
                    gonorrhea

                    Makes sense to me.  But not sure why you have to @Produces an instance of EntityManager (we don't need to don't a similar thing in Seam 2) and why they renamed a lot of the Seam-specific annotations...


                    @In ~ @Current
                    @ConversationScoped ~ @Scope(ScopeType.CONVERSATION)
                    @Produces ~ @Out

                    • 7. Re: Web Beans RI and equivalent (if any) to SMPC?
                      gavin.king

                      Right, you got it :)

                      • 8. Re: Web Beans RI and equivalent (if any) to SMPC?
                        gavin.king

                        Huh? You definitely do need to declare any EntityManager you are injecting in Seam! You do it in components.xml.

                        • 9. Re: Web Beans RI and equivalent (if any) to SMPC?
                          gonorrhea

                          You're referring to this most likely:


                          <persistence:managed-persistence-context name="entityManager"
                                                               auto-create="true"
                                                persistence-unit-jndi-name="java:/fooEntityManagerFactory"/> 



                          And I was actually thinking of programmatically, not in XML...


                          But you're definitely correct, if you don't declare like above in components.xml, then you don't have a SMPC to inject via @In EntityManager entityManager in your Seam components...


                          So can we declare WBPC similarly in the web beans equivalent XML?  Or that's unnecessary b/c in Web Beans we simply use @PersistenceContext(type=EXTENDED) or perhaps @Current EntityManager em?

                          • 10. Re: Web Beans RI and equivalent (if any) to SMPC?

                            Arbi Sookazian wrote on Jun 10, 2009 22:03:


                            You're referring to this most likely:

                            <persistence:managed-persistence-context name="entityManager"
                                                                 auto-create="true"
                                                  persistence-unit-jndi-name="java:/fooEntityManagerFactory"/> 



                            And I was actually thinking of programmatically, not in XML...


                            IMO the less XML the better (better refactoring support, better logging support, better debugging... there is no end to advantages of not using XML)




                            But you're definitely correct, if you don't declare like above in components.xml, then you don't have a SMPC to inject via @In EntityManager entityManager in your Seam components...



                            Exactly



                            So can we declare WBPC similarly in the web beans equivalent XML?  Or that's unnecessary b/c in Web Beans we simply use @PersistenceContext(type=EXTENDED) or perhaps @Current EntityManager em?


                            I guess it should be possible to do it with the web beans equivalent XML

                            • 11. Re: Web Beans RI and equivalent (if any) to SMPC?
                              alin.heyoulin.qq.com
                              intergrate with spring transaction and EntityManager. I test in openwebbeans.
                              
                              public class YofcJpaServices implements JPAService
                              {
                                   private Map<String, EntityManagerFactory> factoryCache = new ConcurrentHashMap<String, EntityManagerFactory>();
                                   private Map<String, EntityManager> managerCache = new ConcurrentHashMap<String, EntityManager>();
                                 
                              @Override
                              public EntityManager getPersistenceContext(String unitName, String name) {
                                   if (unitName == null)
                                  {
                                     throw new IllegalArgumentException("unitName is null");
                                  }
                                   if(managerCache.get(unitName) != null)
                                  {
                                      return managerCache.get(unitName);
                                  }
                                   
                                   EntityManagerFactory emf = getPersistenceUnit(unitName);        
                                  EntityManager em = ExtendedEntityManagerCreator.createContainerManagedEntityManager(emf);
                                  managerCache.put(unitName, em);
                                  return em;
                              }
                              
                              
                              
                              
                              @Override
                              public EntityManagerFactory getPersistenceUnit(String unitName) {
                                   if (unitName == null)
                                  {
                                     throw new IllegalArgumentException("unitName is null");
                                  }
                                   if(factoryCache.get(unitName) != null)
                                  {
                                      return factoryCache.get(unitName);
                                  }
                                   
                                   EntityManagerFactory emf = EntityManagerFactoryUtils.findEntityManagerFactory((ListableBeanFactory)findBeanFactory(),unitName);
                                  factoryCache.put(unitName, emf);
                                  return emf;
                              }
                              protected BeanFactory findBeanFactory()
                              {
                                   ServletContext servletContext = ((WarMetaDataDiscoveryImpl)ServiceLoader.getService(MetaDataDiscoveryService.class)).getServletContext();  
                                  return WebApplicationContextUtils.getWebApplicationContext(servletContext);
                              }
                              
                              }
                              
                              
                              
                              
                              
                              
                              @org.springframework.transaction.annotation.Transactional
                              @InterceptorBindingType
                              @Inherited
                              @Target({TYPE, METHOD})
                              @Retention(RUNTIME)
                              public @interface Transactional {
                                   
                                   String value() default "";
                              
                                   
                                   Propagation propagation() default Propagation.REQUIRED;
                              
                                   
                                   @NonBinding Isolation isolation() default Isolation.DEFAULT;
                              
                                   
                                   int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
                              
                                   
                                   boolean readOnly() default false;
                              
                                   
                                   @NonBinding Class<? extends Throwable>[] rollbackFor() default {};
                              
                                   
                                   @NonBinding String[] rollbackForClassName() default {};
                              
                                   
                                   @NonBinding Class<? extends Throwable>[] noRollbackFor() default {};
                              
                                   
                                   @NonBinding String[] noRollbackForClassName() default {};
                                   
                                   
                              }
                              
                              
                              
                              @Interceptor
                              @Transactional
                              public class TransactionalInterceptor
                              {    
                                  @AroundInvoke
                                  public Object aroundInvoke(InvocationContext context) throws Exception
                                  {
                                       ProxyFactory proxyFactory = new ProxyFactory();
                                       proxyFactory.setTarget(context.getTarget());
                                       proxyFactory.addAdvice(new TransactionInterceptor(getPlatformTransactionManager(), new AnnotationTransactionAttributeSource()));       
                                       
                                      try
                                      {
                                           
                                        return context.getMethod().invoke(proxyFactory.getProxy(),context.getParameters());              
                                          
                                      }catch(Exception e)
                                      {            
                                      
                                          throw e;
                                          
                                      }
                                  }
                                  private static final PlatformTransactionManager getPlatformTransactionManager()
                                  {
                                       ServletContext servletContext = ((WarMetaDataDiscoveryImpl)ServiceLoader.getService(MetaDataDiscoveryService.class)).getServletContext();
                                       return (PlatformTransactionManager) WebApplicationContextUtils.getWebApplicationContext(servletContext).getBean("transactionManager");
                                  }
                              
                              }
                              
                              
                              
                              public class EntityManagerUtil
                              {
                                  private @PersistenceContext(unitName="fisPU")
                                  EntityManager entityManager;
                                  
                                  public EntityManagerUtil()
                                  {
                                      
                                  }
                                  
                                  @Produces @Current
                                  public EntityManager createEntityManager()
                                  {        
                                      return entityManager;
                                  }
                                  
                                  //public void dispose(@Disposes @Current EntityManager entityManager)
                                 // {
                                  //    entityManager.close();        
                                 // }
                                  
                              }
                              
                              
                              BWT,you must modify WarMetaDataDiscoveryImpl.java  to get servletContext.
                              
                              
                              Usage:
                              
                              @Named
                              @SessionScoped
                              @Transactional(readOnly=true)
                              public class Game implements Serializable
                              {
                              
                              
                              .......
                              
                              
                              @Transactional(readOnly=true)
                                 public String check() 
                                 {......}
                              
                              
                              }
                              
                              
                              as you can see,it's same as spring.