4 Replies Latest reply on Dec 27, 2007 2:14 PM by mjhammel

    Getting rebooted:  migration from Middlegen to Hibernate/EJB

    mjhammel

      Though I've delivered a product with JBOSS already, I'm still confused enough about the whole web services world that I have to consider these beginner questions. Confused enough that I'm not sure exactly what questions to ask, so that's why I'm in here. Please forgive the long winded post.

      What I've currently got is a JBOSS based web services product that uses Middlegen to generate (based on the MySQL schema I defined) what I believe are EJB2.1 Local and Home classes that handle db access for me. I have server side code that calls those classes that is instantiated via a web services (actually two) IMPL class. The IMPL classes are accessed via remote stand-alone Java clients (not browsers) using WSDL interfaces (and JAX-RPC) that are generated for me using java2wsdl and wsdl2java. All this works and actually works quite well. The product is a grid system (poorly architected) for the government. The next version (much better grid architecture) is about to begin development.

      The problem for me is that the build system (partially inherited) generates code for me. I come from C/Linux/Unix and have never had anything generate code for me. I hate it cuz I don't understand what it's generating, even if I do understand how to use the generated code. This becomes more of an issue now as I try to migrate off of Middlegen - which I understand is being abandoned and does not support EJB3, correct? - and move to Hibernate - which I understand offers similar functionality but for EJB3.

      I guess the first question would be do I really want to migrate from Middlegen to Hibernate? It would seem I do if I want EJB3, which it would seem I need to keep up with current technologies (I already deteremined that EJB's are *necessary* based on the criteria in the JBOSS@Work text). So will Hibernate generate classes for me like Middlegen did? I've read a few dozen web sites and a bunch of books and I'm still not sure how to map the Home/Local api's to whatever Hibernate's generated classes will provide. I sort of know *how* to use Hibernate (a legacy snippet of code in the Ant build that existed before I inherited this project points me in that direction), but I'm not really sure *what* hibernate will do when I use it. I'm also concerned that I'll have to rewrite all the Home/Local code to use a new API for EJB3, but that's mostly busy work once I learn the API.

      WSDL is another problem. It's a bunch of XML configuration stuff that defines how I can pass data via the RPC calls I use. At the moment, since it's generated for me, it's limited to the shape of the db schema. I can't, for example, define a new class that lets me embed multiple rows from different tables and pass it in a single call (which would save roundtrip transfers). I know it *can* be done. I just don't know how to do it. I'm also wondering if WSDL will be of much use if I switch to asynchronous communication using only JMS since many of the requests posted to the server from the clients can take a long time to complete, including things like file transfers. JMS (directly, or possibly via Mule) is expected play a much bigger role in the next version of the product.

      I'm coming to grips with terminology though it seems "framework" is heavily overused and poorly defined. I can build JARs, WARs (which we no longer need since we don't provide a browser based interface) and EARs. RARs popped up recently and I'm trying to figure out why those need their own format. I'm completely comfortable using Javadoc API documentation and taught myself Java, Ant and SWT (for the clients) enough to build both ends of the product. (Side note: I use cscope and vi for development - IDEs give me a headache). I'm still trying to find documentation on which parts of the stock JBOSS distribution I *should* remove (there are lots of examples that I don't think I should be shipping with the product, right?) when packaging thought that's slowly getting clearer to me. XML configuration is a pain - not because of the format but because there is far too much configuration before you can even get applications running (the WSDL stuff is probably the worst example). I guess writing config files doesn't seem like writing code to me. I'll get over that eventually. It would appear that EJB3 is supposed to address some of that issue.

      Another thing: Spring. This seems to be very popular and I'm wondering if I should consider it. I don't know what part of our current product Spring would replace (if any). It appears to work with EJB3 and Hibernate. So if it works *with* them, then what does it provide that they don't? Apparently it's not an alternative to either. I have a lot more reading to do in this area.

      I'm currently going through the EJB3.0 Trailblazer pages. This is helpful and fairly easy to follow but it's not really telling me how to get from A to B (middlegen to hibernate, for example).

      I know that's a lot of rambling and I appreciate anyone who reads through it all. Any pointers, big or small, on how to keep moving forward will be greatly appreciated.



        • 1. Re: Getting rebooted:  migration from Middlegen to Hibernate
          mjhammel

          Lacking any help from the masses, I'll post my own follow ups for those in a similar situation as myself. Maybe someone else will find this useful.

          I found two pieces of information that helped me get past the migration from Middlegen to Hibernate. The first is the O'Reilly text "Enterprise Java Bean 3.0", (http://www.oreilly.com/catalog/entjbeans5/) which (to me, and I'm an author myself) is the easiest to follow text I've found so far. Mixed with the online chapter for Hibernate (http://www.manning.com/bauer2/), I was able to migrate my build system from Middlegen to Hibernate using reverse-engineering (as they call it - that means something a little different from the world I come from) techniques on our existing MySQL database.

          First I generate an XML mapping file using HibernateToolTask:

          <taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="hclasspath"/>
           <target name="-genConfig" if="db.init.Required" description="Produces XML mapping files in src directory">
           <hibernatetool destdir="${build.hibernate.dir}">
           <classpath>
           <pathelement location="${config.hibernate.dir}"/>
           </classpath>
           <jdbcconfiguration propertyfile="${config.hibernate.dir}/db.properties"
           revengfile="${config.hibernate.dir}/reveng.xml"/>
           <hbm2hbmxml/> <!-- Export Hibernate XML files -->
           <hbm2cfgxml ejb3="true"/> <!-- Export a hibernate.cfg.xml file -->
           </hibernatetool>
           </target>


          Then I generate the Entity Beans, DAO templates and Entity Bean documentation from the mapping files:

          <target name="-genPojos" depends="-genConfig" if="db.init.Required"
           description="Produces Java classes from XML mappings">
           <hibernatetool destdir="${build.hibernate.dir}/src">
           <configuration propertyfile="${config.hibernate.dir}/db.properties" >
           <fileset dir="${build.hibernate.dir}">
           <include name="**/*.hbm.xml"/>
           </fileset>
           </configuration>
          
           <!-- Generate Entity Beans -->
           <hbm2java jdk5="true" ejb3="true"/>
          
           <!-- Generate DAO (Data Access Object's) for entity beans. -->
           <hbm2dao/>
          
           <!-- Generate Entity Bean documentation. -->
           <hbm2doc destdir="${build.docs.dir}/hibernate" />
          
           </hibernatetool>
           </target>


          Finally, I compile these into the classes that will be used by my server side code to work with the database:

           <target name="-genRun" depends="-genPojos" if="db.init.Required"
           description="Compiles entity bean code generated by Hibernate">
           <javac srcdir="${build.hibernate.dir}/src"
           destdir="${build.hibernate.classes.dir}"
           debug="on"
           deprecation="on"
           optimize="off"
           includes="**/*.java">
           <classpath refid="hc.classpath"/>
           </javac>
           </target>


          So now I have the Entity Beans generated. The next step was to write some Session Beans that would act as my WebServices interfaces. The EJB3.0 book from OReilly explained how to do this (chapter 19, but be certain you understand what Session Beans and Remote interfaces are before you read this chapter). With those written, I could use slightly modified code from the old build to generate the WSDL interfaces for both the server and client sides, along with their Java classes (email me if you want to see that code - they use the java2wsdl and wsdl2java Ant tasks from the Apache Axis project).

          Our project doesn't have a Web browser interface (no JSP or similar) so I left out the web.war file from the application ear file, but this turned out to be a mistake. I had to put the web.war file in the ear along with some configuration information (security constraints, etc. from the web.xml) into the ear before it would deploy. I have a feeling I could still leave out the web.war as long as the proper config files were included in the ear, but I'm not sure which config files to leave in.

          As an added problem, I'm doing all this with a migration from JBOSS 4.0.5GA to 4.2.2GA. One minor issue I found with this is that with 4.0.5GA I could deploy a *-login-config-service.xml to the server/default/deploy directory and the associated *-login-config.xml to server/default/conf. With 4.2.2GA these both have to go in server/default/conf. Where is the documentation that says that? It's not with the DynamicLoginConfig documentation I found on the JBOSS web site.

          The deployment is still not complete, however, as I now have some problem with my DataSourceBinding. I believe this to be a configuration error as I changed from one naming scheme for the old project to a new one for the new version of the project. If anyone is interested (and might have a pointer for where to look for this problem), these are the messages I get on the JBOSS console at deploy time:
          10:17:11,403 INFO [EARDeployer] Init J2EE application: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/Crunch.ear
          10:17:11,548 INFO [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.entity.PersistenceUnitDeployment
          10:17:11,554 INFO [JmxKernelAbstraction] installing MBean: persistence.units:ear=Crunch.ear,unitName=crunch with dependencies:
          10:17:11,554 INFO [JmxKernelAbstraction] jboss.jca:name=CrunchDS,service=DataSourceBinding
          10:17:11,557 INFO [EJB3Deployer] Deployed: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/tmp/deploy/tmp26596Crunch.ear-contents/crunch-ejb.jar
          10:17:11,565 INFO [EARDeployer] Started J2EE application: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/Crunch.ear
          10:17:11,566 ERROR [URLDeploymentScanner] Incomplete Deployment listing:
          
          --- Packages waiting for a deployer ---
          org.jboss.deployment.DeploymentInfo@51a7c24d { url=file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/crunch-login-config.xml }
           deployer: null
           status: null
           state: INIT_WAITING_DEPLOYER
           watch: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/crunch-login-config.xml
           altDD: null
           lastDeployed: 1198773984468
           lastModified: 1198773984000
           mbeans:
          
          --- Incompletely deployed packages ---
          org.jboss.deployment.DeploymentInfo@83ba23ed { url=file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/Crunch.ear }
           deployer: org.jboss.deployment.EARDeployer@18baf36
           status: null
           state: FAILED
           watch: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/Crunch.ear
           altDD: null
           lastDeployed: 1198771941640
           lastModified: 1198771941000
           mbeans:
          
          org.jboss.deployment.DeploymentInfo@51a7c24d { url=file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/crunch-login-config.xml }
           deployer: null
           status: null
           state: INIT_WAITING_DEPLOYER
           watch: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/crunch-login-config.xml
           altDD: null
           lastDeployed: 1198773984468
           lastModified: 1198773984000
           mbeans:
          
          --- MBeans waiting for other MBeans ---
          ObjectName: persistence.units:ear=Crunch.ear,unitName=crunch
           State: NOTYETINSTALLED
           I Depend On:
           jboss.jca:name=CrunchDS,service=DataSourceBinding
          
          --- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
          ObjectName: jboss.jca:name=CrunchDS,service=DataSourceBinding
           State: NOTYETINSTALLED
           Depends On Me:
           persistence.units:ear=Crunch.ear,unitName=crunch
          


          When I get all this deployed I still have a major task of rewriting all my original server side code to talk with the database, but this version is a complete rewrite anyway so most of what I'm doing now is just learning how the build system will use newer technologies (like Hibernate and EJB3) as part of the larger project. Once the build is autogenerating whatever code needs to be autogenerated (and deployed) then I can start to focus on the meat of the project rewrite.


          • 2. Re: Getting rebooted:  migration from Middlegen to Hibernate
            mjhammel

            The DataSourceBinding problem turned out to be another config file location change between 4.0.5GA and 4.2.2GA. In 4.0.5GA the mysql-ds.xml file was copied to server/default/conf. In 4.2.2GA it needs to go into server/default/deploy. Once I made this change, I got further along - now I'm being told I need to specify the Hibernate dialect. I already did this for the build in the db.properties file, but now I need to find out where to specify it in the deploy.

            My db.properties:

            mjhammel(tty2)$ cat config/hibernate/db.properties
            hibernate.dialect = org.hibernate.dialect.MySQLDialect
            hibernate.connection.driver_class = com.mysql.jdbc.Driver
            hibernate.connection.url = jdbc:mysql://localhost/crunch
            hibernate.connection.username = root
            


            I'm guessing I need to specify the dialect in the mysql-ds.xml file, though I'm not sure of that yet and I don't know the syntax for specifying the syntax. Time for more googling....

            The latest error messages from the JBOSS console:
            --- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM ---
            ObjectName: persistence.units:ear=Crunch.ear,unitName=crunch
             State: FAILED
             Reason: javax.persistence.PersistenceException: org.hibernate.HibernateException: Hibernate Dialect must be explicitly set
             I Depend On:
             jboss.jca:service=DataSourceBinding,name=CrunchDS
            



            • 3. Re: Getting rebooted:  migration from Middlegen to Hibernate
              mjhammel

              Well, that one was easy, thanks to this post:
              https://www.manning-sandbox.com/message.jspa?messageID=56075

              I just added the configuration to my persistence.xml file:

              <persistence>
               <persistence-unit name="crunch">
               <jta-data-source>java:/CrunchDS</jta-data-source>
               <properties>
               <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
               <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
               <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
               <property name="hibernate.connection.url" value="jdbc:mysql://localhost/crunch"/>
               <property name="hibernate.connection.username" value="blah"/>
               </properties>
               </persistence-unit>
              </persistence>


              The EAR is now deployed, albeit with a huge number of exceptions. I think the problem now is that the location of the mysql-connector jar file (mysql-connector-java-5.0.5-bin.jar) needs to be changed. I used to put it in server/default/lib but I get these errors on the deploy:

              11:38:11,319 INFO [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:service=DataSourceBinding,name=CrunchDS' to JNDI name 'java:CrunchDS'
              11:38:11,339 INFO [EARDeployer] Init J2EE application: file:/home/mjhammel/src/cei/jboss-4.2.2.GA-cei/server/default/deploy/Crunch.ear
              11:38:11,422 INFO [JmxKernelAbstraction] creating wrapper delegate for: org.jboss.ejb3.entity.PersistenceUnitDeployment
              11:38:11,423 INFO [JmxKernelAbstraction] installing MBean: persistence.units:ear=Crunch.ear,unitName=crunch with dependencies:
              11:38:11,423 INFO [JmxKernelAbstraction] jboss.jca:name=CrunchDS,service=DataSourceBinding
              11:38:11,425 INFO [PersistenceUnitDeployment] Starting persistence unit persistence.units:ear=Crunch.ear,unitName=crunch
              11:38:11,436 INFO [Configuration] Reading mappings from resource : META-INF/orm.xml
              11:38:11,437 INFO [Ejb3Configuration] [PersistenceUnit: crunch] no META-INF/orm.xml found
              11:38:11,443 INFO [ConnectionProviderFactory] Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
              11:38:11,444 INFO [InjectedDataSourceConnectionProvider] Using provided datasource
              11:38:11,447 WARN [JBossManagedConnectionPool] Throwable while attempting to get a new connection: null
              org.jboss.resource.JBossResourceException: Could not create connection; - nested throwable: (org.jboss.resource.JBossResourceException: Failed to register driver for: com.mysql.jdbc.Driver; - nested throwable: (java.lang.ClassNotFoundException: No ClassLoaders found for: com.mysql.jdbc.Driver))


              The HSQL jar files all seem to be in server/default/lib, so my gut feeling is that the mysql-connector jar file is also supposed to go here. If so, then this problem is not about the connector.

              More googling....



              • 4. Re: Getting rebooted:  migration from Middlegen to Hibernate
                mjhammel

                Finally - success.

                There were two problems. The first was a brain fart on my part. I wasn't calling the Ant task that checked if the mysql-connector was installed. Once called, the connector was properly installed to server/default/lib, which is the correct location (at least it works for my situation).

                The second problem is that the connector must be installed before JBOSS is started. It can't be hot deployed. So after copying in the connector I restarted JBOSS. Then I deployed my ear file. And it worked.

                Well, at least there are no errors on deployment.

                So, now, all the config stuff is in place. Enough so that I can start looking at writing meaningful server code once again. I still need to write a sample client to make sure I can get to the initial web services interface. That would be the last infrastructure check, I think. After that it's back to server meat and new features, like implementing a cron-like system using the Timer Service.