2 Replies Latest reply on Mar 16, 2010 5:20 PM by sepan77

    Legacy app as a service POJO, using EJB3, Hibernate and BMT...

      Hello,

      I need to wrap a legacy application to be run within a JBoss Container (4.2.2). The application follows the "chain of responsibility" pattern (XML messages received from a remote webservice are processed and the extracted data is stored in a database). This workflow needs to be customizable and the configuration is read from the database on startup of the application. Hibernate is used to access the database. Each processing step must be performed as a single transaction, so that if one processing step fails, the previous steps are not compromised.

      For that reason, I need to use bean managed transactions. Since the application reads its workflow configuration from the database at startup, I need a single instance. Because of that and because it came convenient to me, I exposed the main methods of the application as a Service Pojo MBean which holds the single instance of the legacy application.

      So far, so good. Everything seems to work fine, but sometimes the database transactions are not committed. This is actually very strange and happens most of the time when the application server is under load, but this behaviour is rather irrational to me.

      Here are a few extracts of the code:

       

      Service Pojo:

      @Service(objectName = MyAppService.SERVICE_NAME, xmbean = "resource:META-INF/myappservice-xmbean.xml")
      @Local(MyAppServiceLocal.class)
      @Remote(MyAppServiceRemote.class)
      @TransactionManagement(TransactionManagementType.BEAN)
      public class MyAppService implements MyAppServiceLocal, MyAppServiceRemote {
          public static final String SERVICE_NAME = "at.xyz.myapp:service=MyAppService";
          
          private MyApp appInstance;   // <-- application instance
         @PersistenceUnit SessionFactory factory;  // <--- injected session factory, since app uses hibernate
      
         // lazy initialization of application
         private MyApp getAppInstance() {
            if (appInstance == null) {
               appInstance = new MyApp();
               Session session = factory.openSession();
               try {
                 appInstance.configureFromDb(session);
               } catch (Exception ex) {
                 ...
               } finally {
                  try { session.close(); } catch (Exception ex) {}
               }
            }
            return appInstance;
         }
      
      
         // business method of application exposed to MBean
          @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
          public void fetchMessages() {
              Session session = factory.openSession();
              try {
                  getAppInstance().fetchMessages(session);
              } catch (Exception ex) {
                  ...
              } finally {
                  try { session.close(); } catch (Exception ex) { ... }
              }
          }
      
         // another business method of application exposed to MBean
          @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
          public void processMessage(long id) {
              Session session = factory.openSession();
              try {
                  getAppInstance().processMessage(session, id);
              } catch (Exception ex) {
                  ...
              } finally {
                  try { session.close(); } catch (Exception ex) { ... }
              }
          }
      }
      
      
      
      
      

       

      An the application itself (just showing the example for fetchMessages):

       

      public void fetchMessages(Session session) {
        // this is just for illustration. the single processing steps are contained within single classes using a command pattern.
      
        // processing step 1
        Transaction tx = session.beginTransaction();
        try {
          // do some work: load/save entities from database, perform queries
          tx.commit();
        } catch (HibernateException ex) {
          try {
            tx.rollback();
          } catch (HibernateException ex2) {}
        }
      
        // processing step 2
        Transaction tx = session.beginTransaction();
        try {
          // do some work: load/save entities from database, perform queries
          tx.commit();
        } catch (HibernateException ex) {
          try {
            tx.rollback();
          } catch (HibernateException ex2) {}
        }
      }
      

       

      The persistence unit is configured using JTA, so it should be ok:

      <?xml version="1.0" encoding="UTF-8"?>
      <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
          <persistence-unit name="emcs" transaction-type="JTA">
              <provider>org.hibernate.ejb.HibernatePersistence</provider>
              <jta-data-source>java:/MYAPPDS</jta-data-source>
      
              <!-- legacy application containing business logic and entities -->
              <jar-file> ../lib/myapp.jar </jar-file>
      
              <properties>
                  <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
                  <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
                  <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
                  <property name="hibernate.current_session_context_class" value="jta"/>
              </properties>
          </persistence-unit>
      </persistence>
      

       

      What am I doing wrong here? Is this combination supported? Does anybody know how to achieve this in a better way?

        • 1. Re: Legacy app as a service POJO, using EJB3, Hibernate and BMT...
          jaikiran

          sepan77 wrote:

           


          So far, so good. Everything seems to work fine, but sometimes the database transactions are not committed. This is actually very strange and happens most of the time when the application server is under load, but this behaviour is rather irrational to me.

          It's hard to say what might be wrong, with the limited data.

           

          sepan77 wrote:

           


          
             @PersistenceUnit SessionFactory factory;  // <--- injected session factory, since app uses hibernate
           
             // lazy initialization of application
             private MyApp getAppInstance() {
                if (appInstance == null) {
                   appInstance = new MyApp();
                   Session session = factory.openSession();
                   try {
                     appInstance.configureFromDb(session);
                   } catch (Exception ex) {
                     ...
                   } finally {
                      try { session.close(); } catch (Exception ex) {}
                   }
                }
                return appInstance;
             }
           
           
          

          Why are you using a sessionfactory (a.k.a PersistenceUnit) instead of a container managed @PersistenceContext (a.k.a EntityManager)?

           

          By the way, you might want to use the latest stable AS 5.1.0 since there have been a lot of changes in EJB3 between 4.2.x and AS-5

          • 2. Re: Legacy app as a service POJO, using EJB3, Hibernate and BMT...

            The application uses the code example as proposed by the hibernate website http://docs.jboss.org/hibernate/stable/core/reference/en/html/transactions.html#transactions-basics (11.2.1. Non-managed  environment), so that the code can run in both managed and non-managed enviroment. Therefore I need a sessionFactory, which is injected using @PersistenceUnit.

            I can't switch to JBoss 5, since my customer uses JBoss 4.2.