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