You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomee.apache.org by Alexander Saint Croix <sa...@gmail.com> on 2007/12/17 07:32:13 UTC

Configuring DataSources in a managed environment

Hello.

I apologize in advance for the very long e-mail.  Hopefully more info helps.

I'm getting a rather strange error and I'm at a loss at how to proceed.  I'm
trying to build a collection of entity component jars that fulfill different
aspects of a business model.  I will eventually have upwards of 100 classes
and so have broken the model down into about 10 different libraries.  Each
library's components inherit their most basic common traits from a single
class, which is kept in a "base" jar.  My goal is to be able to have
components in other jars inherit from this @MappedSuperclass object.

So far, I have been successful in creating a first entity bean that inherits
from this MappedSuperclass INSIDE of the base JAR.  I am now turning my
attention to getting a second entity bean in a different JAR to inherit from
the MappedSuperclass in the base jar.

I am deploying in an embedded OpenEJB environment in Tomcat.  I have a
single servlet, in which I instantiate both the FirstEntity class and the
Second Entity class.  Each of these beans is then sent to a Stateless
Session Bean to be persisted into the Database.  This code is shown here:

    // inside of my servlet class:
    @EJB
    private BeanManager mgr;

    ...
        // inside of the doGet(...) method:

        FirstEntity ent1 = new FirstEntity();
        ent1.setName("Entity name");
        ent1.setDescription("Entity description");
        ent1.setType("Entity type");

        mgr.persist(ent1);

        SecondEntity ent2 = new SecondEntity();
        ent2.setName("Entity name 2");
        ent2.setDescription("Entity description 2");
        ent2.setSecondType("Entity type 2");

        mgr.persist(ent2);

        ...

I'm using a stateless session bean at this point, because servlet's aren't
transactional and my understanding is that manually wiring into entity
managers directly from the servlet requires that the entity components are
pre-cooked by OpenJPA.  However, if the entity persistence is managed inside
of a session bean, OpenEJB can do more of that preparation work.  After a
short discussion with Dain earlier, I set up my program to reference the
persistence units from inside of this stateless session bean and let OpenEJB
take care of obtaining the persistence context. The implementation of my
BeanManager interface is shown here:

@Stateless
public class DefaultBeanManager implements BeanManager {

    @PersistenceUnit(unitName="corm-base")
    EntityManagerFactory emf;

    @PersistenceUnit(unitName="corm-party")
    EntityManagerFactory emf2;

    public void persist(FirstEntity a) {

        System.setProperty("openjpa.ConnectionDriverName", "
com.mysql.jdbc.Driver");
        System.setProperty("openjpa.ConnectionURL",
"jdbc:mysql://localhost/corm");
        System.setProperty("openjpa.jdbc.SynchronizeMappings",
"buildSchema");
        System.setProperty("openjpa.ConnectionUserName", "root");
        System.setProperty("openjpa.ConnectionPassword", "n00p455wyrd");

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.persist(a);
        em.getTransaction().commit();
        em.close();

    }

    public void persist(SecondEntity a) {

        System.setProperty("openjpa.ConnectionDriverName", "
com.mysql.jdbc.Driver");
        System.setProperty("openjpa.ConnectionURL",
"jdbc:mysql://localhost/corm");
        System.setProperty("openjpa.jdbc.SynchronizeMappings",
"buildSchema");
        System.setProperty("openjpa.ConnectionUserName", "root");
        System.setProperty("openjpa.ConnectionPassword", "n00p455wyrd");

        EntityManager em = emf2.createEntityManager();
        em.getTransaction().begin();
        em.persist(a);
        em.getTransaction().commit();
        em.close();
    }
}

My problem is that I am now getting the following error:
<openjpa-1.0.0-r420667:568756 fatal user error>
org.apache.openjpa.persistence.ArgumentException: A JDBC Driver or
DataSource class name must be specified in the ConnectionDriverName
property.

This is very confusing because when I was only using the first entity bean
and its mapped superclass inside of a single JAR and persistence unit, (the
first of the two methods in the BeanManager implementation above), the
persistence was working fine.

My two entity beans and their mapped superclass are shown here:

@MappedSuperclass
public class Archetype implements Serializable {

    private String name = "";
    private String description = "";

    public Archetype() {}

    public String getName(){
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription(){
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class FirstEntity extends Archetype {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
}

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class SecondEntity extends Archetype {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    private String secondType;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getSecondType() {
        return secondType;
    }

    public void setSecondType(String secondType) {
        this.secondType = secondType;
    }
}

Finally, the persistence.xml files for each component jar are identical with
the exception of their persistence-unit name.  I'll post one of them here.
The other is named "corm-base":

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="corm-party" transaction-type="RESOURCE_LOCAL">
    </persistence-unit>
</persistence>

How should I correctly configure the ConnectionDriverName property for
multiple persistence units so that these component jars can cooperate?

Any help is appreciated,
--
Alex

Re: Configuring DataSources in a managed environment

Posted by Dain Sundstrom <da...@iq80.com>.
I'd start by putting every thing in a single jar with a  
persistence.xml.  Once you get that working, then you can attempt to  
split it up.

As for actually splitting it up, I think there are two ways to go  
about it, although I've never tried either.

1) One persistence-unit with code spread amongst several dependent  
jars.  I'm not sure if OpenJPA will scan the whole class path or just  
the one jar containing the persistence.xml file, so you may have to  
explicitly list your persistent classes in the persistence.xml file.

2) Multiple persistence-units.  This will only work if the multiple  
units are island meaning they don't have relationships between  
entities in separate units.

I think the one persistence-unit option will be the best, as keeping  
to one persistence-unit means you have one JPA instance managing  
everything.  This way guarantees you only get one cache and one  
database connection used.  In OpenEJB we have code to detect multiple  
connections to the same database in one transaction and coalesce them  
into a single connection, but not all JEE servers do this.  If you do  
end up with multiple database connections, you will need a database  
that supports XA transactions (last time I checked mySQL didn't).  It  
is possible that a smart JPA implementation will recognize that is  
has two persistence-units to the same database and automagically  
configures itself to use a single DB connection, but I wouldn't count  
on it from any implementation except OpenJPA.

Anyway, I'd sick everything in one unit and optimize the packaging at  
the end of development.

-dain

On Dec 17, 2007, at 7:19 AM, Alexander Saint Croix wrote:

> Thanks for the help, David.
>
> I broke up the component library to make it modular, as there are  
> presently
> between 70-100 entities total.  I'm really REALLY not interested in
> combining those JARs, and have been operating on a couple of  
> assumptions
> about persistence units and how they must be packaged.
>
> I thought that each component JAR needed to include its own  
> persistence.xmlfile.
>
> The spec says:
>
>> A persistence unit may be packaged within one or more jar files  
>> contained
>> within a WAR
>>
>
> But also:
>
>> Only one persistence unit of any given name may be defined
>> within a single EJB-JAR file, within a single WAR file, within a  
>> single
>> application client jar, or within
>> an EAR (in the EAR root or lib directory).
>>
>
> Do my component JARs need to have persistence.xml files at all?   
> None of
> them are the root of the persistence unit--that seems to be the WAR.
> Shouldn't I define the persistence.xml file in the web app and  
> reference the
> JARs from there?  It would certainly simplify matters.
>
> Also, in which file do I configure my DataSource in embedded OpenEJB?
>
> Regards,
> --
> Alex
>
>
>
>
>
> On Dec 17, 2007 2:13 AM, David Blevins <da...@visi.com> wrote:
>
>> On Dec 16, 2007, at 10:32 PM, Alexander Saint Croix wrote:
>>
>>> I am deploying in an embedded OpenEJB environment in Tomcat.
>>
>>
>>>    ...
>>>        // inside of the doGet(...) method:
>>>
>>>        FirstEntity ent1 = new FirstEntity();
>>>        ent1.setName("Entity name");
>>>        ent1.setDescription("Entity description");
>>>        ent1.setType("Entity type");
>>>
>>>        mgr.persist(ent1);
>>>
>>>        SecondEntity ent2 = new SecondEntity();
>>>        ent2.setName("Entity name 2");
>>>        ent2.setDescription("Entity description 2");
>>>        ent2.setSecondType("Entity type 2");
>>>
>>>        mgr.persist(ent2);
>>
>>
>>> @Stateless
>>> public class DefaultBeanManager implements BeanManager {
>>>
>>>    @PersistenceUnit(unitName="corm-base")
>>>    EntityManagerFactory emf;
>>>
>>>    @PersistenceUnit(unitName="corm-party")
>>>    EntityManagerFactory emf2;
>>>
>>>    public void persist(FirstEntity a) {
>>>
>>>        System.setProperty("openjpa.ConnectionDriverName", "
>>> com.mysql.jdbc.Driver");
>>>        System.setProperty("openjpa.ConnectionURL",
>>> "jdbc:mysql://localhost/corm");
>>>        System.setProperty("openjpa.jdbc.SynchronizeMappings",
>>> "buildSchema");
>>>        System.setProperty("openjpa.ConnectionUserName", "root");
>>>        System.setProperty("openjpa.ConnectionPassword",
>>> "n00p455wyrd");
>>>
>>>        EntityManager em = emf.createEntityManager();
>>>        em.getTransaction().begin();
>>>        em.persist(a);
>>>        em.getTransaction().commit();
>>>        em.close();
>>>
>>>    }
>>>
>>>    public void persist(SecondEntity a) {
>>>
>>>        System.setProperty("openjpa.ConnectionDriverName", "
>>> com.mysql.jdbc.Driver");
>>>        System.setProperty("openjpa.ConnectionURL",
>>> "jdbc:mysql://localhost/corm");
>>>        System.setProperty("openjpa.jdbc.SynchronizeMappings",
>>> "buildSchema");
>>>        System.setProperty("openjpa.ConnectionUserName", "root");
>>>        System.setProperty("openjpa.ConnectionPassword",
>>> "n00p455wyrd");
>>>
>>>        EntityManager em = emf2.createEntityManager();
>>>        em.getTransaction().begin();
>>>        em.persist(a);
>>>        em.getTransaction().commit();
>>>        em.close();
>>>    }
>>> }
>>
>>
>>> <persistence xmlns="http://java.sun.com/xml/ns/persistence"
>>> version="1.0">
>>>    <persistence-unit name="corm-party" transaction-
>>> type="RESOURCE_LOCAL">
>>>    </persistence-unit>
>>> </persistence>
>>>
>>> How should I correctly configure the ConnectionDriverName  
>>> property for
>>> multiple persistence units so that these component jars can  
>>> cooperate?
>>
>> Definitely do not set ConnectionDriverName at all, likewise for  
>> any of
>> the OpenJPA properties that smell of "let us make the datasource for
>> you".  You need to configure your datasource in Tomcat or OpenEJB
>> (either is fine as we sync the environments together), then you  
>> *must*
>> either a) set these two system properties:
>>
>>  javax.persistence.jtaDataSource=java:openejb/Resource/myDataSource
>>  javax.persistence.nonJtaDataSource=java:openejb/Resource/
>> myNonJtaDataSource
>>
>> or b) set them in each persistence.xml via:
>>    <persistence-unit name="corm-party">
>>      <jta-data-source>java:openejb/Resource/myDataSource</jta-data-
>> source>
>>      <non-jta-data-source>=java:openejb/Resource/myNonJtaDataSource</
>> non-jta-data-source>
>>    </persistence-unit>
>>
>> The second and more important.  Why do you want to split these Entity
>> beans up into so many persitence-units.  Is this a packaging concern
>> or is it really your intent to have several completely separate
>> caches, each with it's own connection to the database, and each
>> managing it's own transaction with no cooperation and visibility to
>> the other?  I suspect the answer is no as you have attempted to point
>> them all at the same database.  If you start sharing data between  
>> them
>> you could wind up with some serious data integrity issues.
>>
>> I can recommend a better approach once I better understand your
>> motivation.
>>
>> -David
>>
>>


Re: Configuring DataSources in a managed environment

Posted by David Blevins <da...@visi.com>.
On Dec 17, 2007, at 7:19 AM, Alexander Saint Croix wrote:

> Thanks for the help, David.
>
> I broke up the component library to make it modular, as there are  
> presently
> between 70-100 entities total.

Ok, just to be clear though, you cannot have managed relationships to  
entities outside your unit.  Forgetting all things packaging, a unit  
is one cache of data managed by the Provider.  The provider cannot see  
or manage data (including relationships) outside the unit (i.e. its  
cache).  It's fine to break your units up just as long as you're doing  
it consciously and deliberately with that in mind.

> Do my component JARs need to have persistence.xml files at all?   
> None of
> them are the root of the persistence unit--that seems to be the WAR.
> Shouldn't I define the persistence.xml file in the web app and  
> reference the
> JARs from there?  It would certainly simplify matters.

If you put your persistence.xml in the webapp and listed your 70-100  
persistent classes in it, you could spread the classes into as many  
WEB-INF/lib jars as you like.  Doing this is essentially feeding the  
provider all the class names it should make persistent and not relying  
on the jar searching for the @Entity annotation.  There might be a  
better option, but that is one approach I know should work.

> Also, in which file do I configure my DataSource in embedded OpenEJB?

In your openejb.xml via:

   <Resource id="myJtaDatasource" type="DataSource">
      JdbcDriver  = com.mysql.jdbc.Driver
      JdbcUrl     = jdbc:mysql://localhost/corm
      UserName    = root
      Password    = n00p455wyrd
   </Resource>

   <Resource id="myNonJtaDatasource" type="DataSource">
      JdbcDriver  = com.mysql.jdbc.Driver
      JdbcUrl     = jdbc:mysql://localhost/corm
      UserName    = root
      Password    = n00p455wyrd
      JtaManaged  = false
   </Resource>

Note that JtaManaged only works in trunk, so if you're using beta 1  
you'll need to declare myNonJtaDatasource as follows:

   <Resource id="myNonJtaDatasource" type="DataSource"  
provider="Default Unmanaged JDBC Database">
      JdbcDriver  = com.mysql.jdbc.Driver
      JdbcUrl     = jdbc:mysql://localhost/corm
      UserName    = root
      Password    = n00p455wyrd
   </Resource>


-David


Re: Configuring DataSources in a managed environment

Posted by Alexander Saint Croix <sa...@gmail.com>.
Thanks for the help, David.

I broke up the component library to make it modular, as there are presently
between 70-100 entities total.  I'm really REALLY not interested in
combining those JARs, and have been operating on a couple of assumptions
about persistence units and how they must be packaged.

I thought that each component JAR needed to include its own persistence.xmlfile.

The spec says:

> A persistence unit may be packaged within one or more jar files contained
> within a WAR
>

But also:

> Only one persistence unit of any given name may be defined
> within a single EJB-JAR file, within a single WAR file, within a single
> application client jar, or within
> an EAR (in the EAR root or lib directory).
>

Do my component JARs need to have persistence.xml files at all?  None of
them are the root of the persistence unit--that seems to be the WAR.
Shouldn't I define the persistence.xml file in the web app and reference the
JARs from there?  It would certainly simplify matters.

Also, in which file do I configure my DataSource in embedded OpenEJB?

Regards,
--
Alex





On Dec 17, 2007 2:13 AM, David Blevins <da...@visi.com> wrote:

> On Dec 16, 2007, at 10:32 PM, Alexander Saint Croix wrote:
>
> > I am deploying in an embedded OpenEJB environment in Tomcat.
>
>
> >    ...
> >        // inside of the doGet(...) method:
> >
> >        FirstEntity ent1 = new FirstEntity();
> >        ent1.setName("Entity name");
> >        ent1.setDescription("Entity description");
> >        ent1.setType("Entity type");
> >
> >        mgr.persist(ent1);
> >
> >        SecondEntity ent2 = new SecondEntity();
> >        ent2.setName("Entity name 2");
> >        ent2.setDescription("Entity description 2");
> >        ent2.setSecondType("Entity type 2");
> >
> >        mgr.persist(ent2);
>
>
> > @Stateless
> > public class DefaultBeanManager implements BeanManager {
> >
> >    @PersistenceUnit(unitName="corm-base")
> >    EntityManagerFactory emf;
> >
> >    @PersistenceUnit(unitName="corm-party")
> >    EntityManagerFactory emf2;
> >
> >    public void persist(FirstEntity a) {
> >
> >        System.setProperty("openjpa.ConnectionDriverName", "
> > com.mysql.jdbc.Driver");
> >        System.setProperty("openjpa.ConnectionURL",
> > "jdbc:mysql://localhost/corm");
> >        System.setProperty("openjpa.jdbc.SynchronizeMappings",
> > "buildSchema");
> >        System.setProperty("openjpa.ConnectionUserName", "root");
> >        System.setProperty("openjpa.ConnectionPassword",
> > "n00p455wyrd");
> >
> >        EntityManager em = emf.createEntityManager();
> >        em.getTransaction().begin();
> >        em.persist(a);
> >        em.getTransaction().commit();
> >        em.close();
> >
> >    }
> >
> >    public void persist(SecondEntity a) {
> >
> >        System.setProperty("openjpa.ConnectionDriverName", "
> > com.mysql.jdbc.Driver");
> >        System.setProperty("openjpa.ConnectionURL",
> > "jdbc:mysql://localhost/corm");
> >        System.setProperty("openjpa.jdbc.SynchronizeMappings",
> > "buildSchema");
> >        System.setProperty("openjpa.ConnectionUserName", "root");
> >        System.setProperty("openjpa.ConnectionPassword",
> > "n00p455wyrd");
> >
> >        EntityManager em = emf2.createEntityManager();
> >        em.getTransaction().begin();
> >        em.persist(a);
> >        em.getTransaction().commit();
> >        em.close();
> >    }
> > }
>
>
> > <persistence xmlns="http://java.sun.com/xml/ns/persistence"
> > version="1.0">
> >    <persistence-unit name="corm-party" transaction-
> > type="RESOURCE_LOCAL">
> >    </persistence-unit>
> > </persistence>
> >
> > How should I correctly configure the ConnectionDriverName property for
> > multiple persistence units so that these component jars can cooperate?
>
> Definitely do not set ConnectionDriverName at all, likewise for any of
> the OpenJPA properties that smell of "let us make the datasource for
> you".  You need to configure your datasource in Tomcat or OpenEJB
> (either is fine as we sync the environments together), then you *must*
> either a) set these two system properties:
>
>  javax.persistence.jtaDataSource=java:openejb/Resource/myDataSource
>  javax.persistence.nonJtaDataSource=java:openejb/Resource/
> myNonJtaDataSource
>
> or b) set them in each persistence.xml via:
>    <persistence-unit name="corm-party">
>      <jta-data-source>java:openejb/Resource/myDataSource</jta-data-
> source>
>      <non-jta-data-source>=java:openejb/Resource/myNonJtaDataSource</
> non-jta-data-source>
>    </persistence-unit>
>
> The second and more important.  Why do you want to split these Entity
> beans up into so many persitence-units.  Is this a packaging concern
> or is it really your intent to have several completely separate
> caches, each with it's own connection to the database, and each
> managing it's own transaction with no cooperation and visibility to
> the other?  I suspect the answer is no as you have attempted to point
> them all at the same database.  If you start sharing data between them
> you could wind up with some serious data integrity issues.
>
> I can recommend a better approach once I better understand your
> motivation.
>
> -David
>
>

Re: Configuring DataSources in a managed environment

Posted by David Blevins <da...@visi.com>.
On Dec 16, 2007, at 10:32 PM, Alexander Saint Croix wrote:

> I am deploying in an embedded OpenEJB environment in Tomcat.


>    ...
>        // inside of the doGet(...) method:
>
>        FirstEntity ent1 = new FirstEntity();
>        ent1.setName("Entity name");
>        ent1.setDescription("Entity description");
>        ent1.setType("Entity type");
>
>        mgr.persist(ent1);
>
>        SecondEntity ent2 = new SecondEntity();
>        ent2.setName("Entity name 2");
>        ent2.setDescription("Entity description 2");
>        ent2.setSecondType("Entity type 2");
>
>        mgr.persist(ent2);


> @Stateless
> public class DefaultBeanManager implements BeanManager {
>
>    @PersistenceUnit(unitName="corm-base")
>    EntityManagerFactory emf;
>
>    @PersistenceUnit(unitName="corm-party")
>    EntityManagerFactory emf2;
>
>    public void persist(FirstEntity a) {
>
>        System.setProperty("openjpa.ConnectionDriverName", "
> com.mysql.jdbc.Driver");
>        System.setProperty("openjpa.ConnectionURL",
> "jdbc:mysql://localhost/corm");
>        System.setProperty("openjpa.jdbc.SynchronizeMappings",
> "buildSchema");
>        System.setProperty("openjpa.ConnectionUserName", "root");
>        System.setProperty("openjpa.ConnectionPassword",  
> "n00p455wyrd");
>
>        EntityManager em = emf.createEntityManager();
>        em.getTransaction().begin();
>        em.persist(a);
>        em.getTransaction().commit();
>        em.close();
>
>    }
>
>    public void persist(SecondEntity a) {
>
>        System.setProperty("openjpa.ConnectionDriverName", "
> com.mysql.jdbc.Driver");
>        System.setProperty("openjpa.ConnectionURL",
> "jdbc:mysql://localhost/corm");
>        System.setProperty("openjpa.jdbc.SynchronizeMappings",
> "buildSchema");
>        System.setProperty("openjpa.ConnectionUserName", "root");
>        System.setProperty("openjpa.ConnectionPassword",  
> "n00p455wyrd");
>
>        EntityManager em = emf2.createEntityManager();
>        em.getTransaction().begin();
>        em.persist(a);
>        em.getTransaction().commit();
>        em.close();
>    }
> }


> <persistence xmlns="http://java.sun.com/xml/ns/persistence"  
> version="1.0">
>    <persistence-unit name="corm-party" transaction- 
> type="RESOURCE_LOCAL">
>    </persistence-unit>
> </persistence>
>
> How should I correctly configure the ConnectionDriverName property for
> multiple persistence units so that these component jars can cooperate?

Definitely do not set ConnectionDriverName at all, likewise for any of  
the OpenJPA properties that smell of "let us make the datasource for  
you".  You need to configure your datasource in Tomcat or OpenEJB  
(either is fine as we sync the environments together), then you *must*  
either a) set these two system properties:

  javax.persistence.jtaDataSource=java:openejb/Resource/myDataSource
  javax.persistence.nonJtaDataSource=java:openejb/Resource/ 
myNonJtaDataSource

or b) set them in each persistence.xml via:
    <persistence-unit name="corm-party">
      <jta-data-source>java:openejb/Resource/myDataSource</jta-data- 
source>
      <non-jta-data-source>=java:openejb/Resource/myNonJtaDataSource</ 
non-jta-data-source>
    </persistence-unit>

The second and more important.  Why do you want to split these Entity  
beans up into so many persitence-units.  Is this a packaging concern  
or is it really your intent to have several completely separate  
caches, each with it's own connection to the database, and each  
managing it's own transaction with no cooperation and visibility to  
the other?  I suspect the answer is no as you have attempted to point  
them all at the same database.  If you start sharing data between them  
you could wind up with some serious data integrity issues.

I can recommend a better approach once I better understand your  
motivation.

-David