7 Replies Latest reply on Apr 28, 2009 7:47 PM by pedrosena

    Conceptual doubt

    pedrosena

      Hi guys,


      I'm having a strange problem.


      I have a DAO that is a seam stateless component. All my DAOs have a Session-scoped variable injected by seam that determines the database that I need to connect(I have one db-schema per client).


      So far so good, everything is working fine.


      Now I faced a different scenario. I need to connect do two distinct databases in the same method.


      I tried:


      1) Setting the session-variable that determines where I need to connect before using my DAO
      2) Setting(using a method) the hibernate session in my DAO.


      Both 'solutions' pointed to the same database, so I'm really confused now.


      The injected variables are proxies that retrieve the value according to the scope or they inject the real object in creation time?


      I tried the solution (1) based on proxy theory.
      Then I tried the setter way expecting that the seam inject hibernate session was there so that I could change it. It did not work too.


      Could someone explain me how this injection works?


      Thanks,


      Pedro Sena


        • 1. Re: Conceptual doubt
          gonorrhea

          You can inject more than one EntityManager instance (each representing a different db/datasource) into a single component  as follows (note the usage of @In for SMPC rather than @PersistenceContext from JSR220):


          @In
          private EntityManager entityManager1;
                    
          @In 
          private EntityManager entityManager2;



          If you are using SFSB/SLSB with JTA, then beware that if you try to use more than one EntityManager instance in the same business method with REQUIRED tx attribute type (default), then you will see a persistence/tx exception unless you are using XA/2PC datasources.


          Make sure that the EntityManager instance names and casing matches what is configured in components.xml for the SMPCs.


          ex:


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

          • 2. Re: Conceptual doubt
            pedrosena

            Hi Arbi,


            Thanks for your reply.


            Actually my architecture does not allow me to do this way.


            I'm already using Seam-managed entity managers.


            The point is:


            I have one database schema per client. So I create a SessionFactory when my user log in and keep it in session context.


            Based on this session factory, I create hibernate session(automatically done by seam)


            <persistence:managed-hibernate-session name="userSpecificEntityManager" auto-create="false"
                                 scope="CONVERSATION"
                                 session-factory="#{hbmUserSpecificEntityManagerFactory}" />



            hbmUserSpecificEntityManagerFactory is a SessionFactory (created using @Factory) and kept in session context


            And in my DAOs I have:


            @In(required = true, create = true)
                 protected Session userSpecificEntityManager;



            So that way I can connect to user specific database without problems.


            The problem comes when I need to mantain two instances of some DAO.


            I got no exception when managing two DAOs in my method, the point is that both are pointing to same database, that is not the expected behavior.


            Pedro Sena

            • 3. Re: Conceptual doubt
              ztiringer

              AFAIK what you are experiencing IS the expected behavior. As userSpecificEntityManager is conversation scoped, the same Session object is getting injected into your DAOs.


              You need to specify another EntityManager (or probably even one for each DAO, if a DAO can be paired with any other DAO) in components.xml and inject that to your DAO. I'm not sure how well your application would scale, but I guess that just comes from the unusual requirements. 

              • 4. Re: Conceptual doubt
                pedrosena

                Hi Zoltan,


                You are completely right.


                I'm trying to override the annotation but w/o success.


                In my DAO I have:


                @Name("personHome")
                public class PersonHome extends LocalEntityHome<Person> {
                
                @In(required = true, create = true)
                protected Session userSpecificEntityManager;



                Then in my components.xml I did:


                <component name="integrationPersonHome" class="br.com.netsar.infra.persistence.local.PersonHome" scope="stateless">
                          <property name="userSpecificEntityManager">#{integrationSpecificEntityManager}</property>
                     </component>     



                I'm making some tests and my integrationPersonHome still using the userSpecificEntityManager instead of integrationSpecificEntityManager


                My Homes are in an external jar, but I suppose that it would not be a problem, right?


                I'm a little confused about overriding annotation behavior with xml.


                Would appreciate some help,


                Thanks in advance,


                PS


                • 5. Re: Conceptual doubt
                  ztiringer

                  No, you cannot override an already existing EntityManager definition, you need to create a new one with a different name. I would try something like:



                  <persistence:managed-hibernate-session name="userSpecificPersonEntityManager" auto-create="false"
                                       scope="CONVERSATION"
                                       session-factory="#{hbmUserSpecificPersonEntityManagerFactory}" />
                  
                  <persistence:managed-hibernate-session name="userSpecificOtherEntityManager" auto-create="false"
                                       scope="CONVERSATION"
                                       session-factory="#{hbmUserSpecificOtherEntityManagerFactory}" />




                  in components.xml (with all the necessary SessionFactory) and inject these ones.

                  • 6. Re: Conceptual doubt
                    pedrosena

                    Hi Zoltan,


                    Thanks for the quick reply.


                    That is what I'm doing:



                    <persistence:managed-hibernate-session name="integrationSpecificEntityManager" 
                                                     auto-create="false"
                                                     scope="CONVERSATION"
                                                     session-factory="#{integrationSpecificEntityManagerFactory}" />



                    That generates the integrationSpecificEntityManager correctly as expected. I made some tests and it is pointing to correct database as I want.


                    The problem is the variable that is being inject.


                    When I try:


                    <component name="integrationPersonHome" scope="stateless" 
                                               class="br.com.netsar.infra.persistence.local.PersonHome">
                                    <property name="userSpecificEntityManager">#{integrationSpecificEntityManager}</property>
                            </component>



                    It does NOT override the default:


                    @In(required = true, create = true)
                    protected Session userSpecificEntityManager;



                    My integrationPersonHome stills with {userSpecificEntityManager} (using the value from annotation) instead of {integrationSpecificEntityManager} as my components.xml specifies.


                    I was specting that my xml would override the injection made via annotations.


                    I don't know if this is the expected behavior.


                    I'm taking a look at documentation but I did not find anything about it.


                    Still looking.


                    Thanks one more time.



                            

                    • 7. Re: Conceptual doubt
                      pedrosena

                      Well,


                      Found what I was looking for:


                      Seam also resolves an EL expression string prior to assigning the initial value to the bean property of the component. So you can inject some contextual data into your components. 



                      So this clarifies me that problem that I was facing:


                      At deploy time my EL expression was evaluating to null so my home was not poiting to the right database.


                      Would be nice to use an EL expression that would be evaltuated at runtime like seam default components (like session-factory in persistence:managed-hibernate-session).


                      I know that it can be done using ValueExpression in my class, but would be nicer to make all the job in components.xml.


                      Well, I'll post as a JIRA in the near time.


                      Thanks for your time,


                      PS