3 Replies Latest reply on Jan 4, 2008 4:11 AM by Flavio Pompermaier

    One PersistenceUnit, multiple DataSources

    Trond Arve Nordheim Newbie

      Hi

      I'm currently working on a EJB3-based application where I have the following project layout of my EAR:

      -> myproject.ear
       -> api.jar
       -> dao interfaces and ejb entities
       -> ejb.jar
       -> ejb3 implementation of the dao interfaces
       -> persistence.jar
       -> contains persistence.xml and such
      


      This is deployed standalone to JBoss-4.0.5-GA and works as intended. Now, the plan was to have several self-contained webapps (deployed in .wars, or optionally separate .ear's - whatever works), like this:
      -> webapp1.war
      -> webapp2.war
      -> (...)
      


      The wish is that every webapp uses the persistence-manager configured in persistence.xml in persistence.jar, but that each webapp has a separate DataSource so I can let every webapp use the same schema structure and same entity beans, but separate databases. My current persistence.xml looks like this;
      <?xml version="1.0" encoding="UTF-8"?>
      <persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
       <persistence-unit name="em" transaction-type="JTA">
       <jta-data-source>java:/TestDataSource</jta-data-source>
       <jar-file>../api.jar</jar-file>
       <properties>
       <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
       <property name="hibernate.show_sql" value="true" />
       <property name="hibernate.hbm2ddl.auto" value="update" />
       <property name="jboss.entity.manager.jndi.name" value="java:/TestEM" />
       </properties>
       </persistence-unit>
      </persistence>
      


      My DAOs get a hold of their entitymanager like this:
      @Resource(mappedName = "java:/TestEM")
      private EntityManager em;
      


      What I'm trying to achieve is to more or less set up a new web application with the minimal amount of hassle. One possible way of doing it would perhaps be setting up a new persistence-context in persistence.xml for each new website, but that would require rebuilding and redeploying the entire EAR, which I'd really like to avoid.

      I guess one way of getting around this is to deploy the webapp with a "overriding" persistence.xml in a ejb-jar and package it together with the webapp in a separate .ear (though I don't know if this will work either, I haven't tested this yet), but this has some drawbacks as well;
      - I would have to duplicate the persistence-unit-properties and jar-file-properties for each webapp, making maintenance hard if there's a change in the properties there. It would require that each and every webapp is rebuilt and redeployed - not just the EAR.
      - It's a more complex deployment than just dropping in a .war in the deployment folder - though this I can live with.

      There will be a -ds.xml in the deploy/ folder for each webapp, containing information about each application's data source. If there would be some way of "overriding" the jta-data-source for the EntityManager on a site-basis, or injecting a new DataSource into the EntityManager, I guess that would be a way of getting this to work.

      I'm kind of new to JBoss and EJB3 in general, and I'm trying to work out the "best practice" way of doing things to avoid clutter later down the road. If any of the above is a shitty way of solving what I intend to do, do say so.

      Anyways, this separate-db-per-webapp-thing is a requirement for this app, and it's also a requirement that it involves as little work as possible to get a new webapp up and running - e.g. too much rebuilding and redeployment of the application core is out of the question.

      Any pointers on which direction I should go in would be very appreciated.

        • 1. Re: One PersistenceUnit, multiple DataSources
          Trond Arve Nordheim Newbie

          OK, just as an update - I've figured out that bundling the war inside another ear - also containing a jar with a new persistence.xml that maps to the war's datasource works as intended.

          Now bundling the war like this:

          webapp1.ear
           -> webapp1.war
           -> webapp1-persistence.jar
           -> persistence.xml
          


          Though, in my original persistence.xml, I point to the jar files containing my entity beans, but in the webapp-ear I cannot do that as it doesn't seem like you can point on jar files inside another ear - so I instead have to point on every single class inside myproject.ear that acts as an entity-bean.

          This is surely a maintenance-hell when a new entity gets introduced and I need to change all these persistence.xml's in the webapps, rebuild and redeploy.

          Is there any way to be able to point to those jars even if they are inside another EAR?

          Some kind of "inherited persistence.xml" would be damn sexy here :(

          • 2. Re: One PersistenceUnit, multiple DataSources
            Trond Arve Nordheim Newbie

            So, I think I figured out a solution that works for me.

            In my persistence.xml in my original application EAR, I removed the jar-references and instead added this;

            <mapping-file>persistence-mapping-file.xml</mapping-file>
            


            Then, in the persistence.jar within the EAR, I added the persistence-mapping-file.xml containing this;
            <?xml version="1.0" encoding="UTF-8" ?>
            <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
             version="1.0">
            
             <package>myproject.entities</package>
            
             <entity class="myproject.entities.FooEntity" name="FooEntity" />
             <entity class="myproject.entities.BarEntity" name="BarEntity" />
            
            </entity-mappings>
            


            Then I just refer to the same file within the persistence.xmls I deploy in my webapp-EARs and that works more or less as I want.

            Does seem like a bit non-standard use of the mapping-file from what I could gather from reading some forums and stuff - but hey, it works. And it's good enough.

            • 3. Re: One PersistenceUnit, multiple DataSources
              Flavio Pompermaier Newbie

              I tried to do as you adviced but I get the following error on jboss4.2.2-GA

              [Configuration] Reading mappings from resource : persistence-mapping-file.xml
              10:02:10,488 ERROR [AbstractKernelController] Error installing to Start: name=persistence.units:unitName=NewsCrawlerPu state=Create
              javax.persistence.PersistenceException: [PersistenceUnit: NewsCrawlerPu] Unable to find XML mapping file in classpath: ../persistence-mapping-file.xml
              at org.hibernate.ejb.Ejb3Configuration.addClassesToSessionFactory(Ejb3Configuration.java:892)

              I want to deploy a ear file containing a WAR and JAR archives.I inserted the persistence.xml both in the WAR and JAR (under WEB-INF and META-INF respectively), do I have to ass it also to the classpath on the Manifest of the archives?

              Flavio