Sharing a persistence unit across components in a .ear file - java

In a Java EE 6 application where I'm using .ear packaging, I'd like to create a persistence unit that can be accessed from components in different .jar files.
However, I'm not sure how to define this persistence unit. With the #PersistenceContext annotation the lookup only succeeds if the name matches a persistence unit defined in the local persistence.xml file.
Is it possible to refer to external persistence units?

Here are the relevant sections of the JPA 2.0 specification:
8.2 Persistence Unit Packaging
...
A persistence unit is defined by a
persistence.xml file. The jar file or
directory whose META-INF directory
contains the persistence.xml file is
termed the root of the persistence
unit. In Java EE environments, the
root of a persistence unit must be one
of the following:
an EJB-JAR file
the WEB-INF/classes directory of a WAR file[80]
a jar file in the WEB-INF/lib directory of a WAR file
a jar file in the EAR library directory
an application client jar file
It is not required that an EJB-JAR or
WAR file containing a persistence unit
be packaged in an EAR unless the
persistence unit contains persistence
classes in addition to those contained
within the EJB-JAR or WAR. See Section
8.2.1.6.
NOTE: Java Persistence 1.0 supported use of a jar file in the root of the
EAR as the root of a persistence unit.
This use is no longer supported.
Portable applications should use the EAR library directory for this case
instead. See [9].
A persistence unit must have a name.
Only one persistence unit of any given
name must be defined within a single
EJB-JAR file, within a single WAR
file, within a single application
client jar, or within an EAR. See
Section 8.2.2, “Persistence Unit
Scope”.
The persistence.xml file may be used
to designate more than one persistence
unit within the same scope.
All persistence classes defined at the
level of the Java EE EAR must be
accessible to all other Java EE
components in the application - i.e.
loaded by the application classloader
- such that if the same entity class is referenced by two different Java EE
components (which may be using
different persistence units), the
referenced class is the same identical
class.
And later:
8.2.2 Persistence Unit Scope
An EJB-JAR, WAR, application client
jar, or EAR can define a persistence
unit.
When referencing a persistence unit
using the unitName annotation
element or persistence-unit-name
deployment descriptor element, the
visibility scope of the persistence
unit is determined by its point of
definition:
A persistence unit that is defined at the level of an EJB-JAR, WAR, or
application client jar is scoped to
that EJB-JAR, WAR, or application jar
respectively and is visible to the
components defined in that jar or war.
A persistence unit that is defined at the level of the EAR is generally
visible to all components in the
application. However, if a persistence
unit of the same name is defined by an
EJB-JAR, WAR, or application jar file
within the EAR, the persistence unit
of that name defined at EAR level will
not be visible to the components
defined by that EJB-JAR, WAR, or
application jar file unless the
persistence unit reference uses the
persistence unit name # syntax to
specify a path name to disambiguate
the reference. When the # syntax is
used, the path name is relative to the
referencing application component jar
file. For example, the syntax
../lib/persistenceUnitRoot.jar#myPersistenceUnit
refers to a persistence unit whose
name, as specified in the name element
of the persistence.xml file, is
myPersistenceUnit and for which the
relative path name of the root of the
persistence unit is
../lib/persistenceUnitRoot.jar. The
# syntax may be used with both the unitName annotation element or
persistence-unit-name deployment
descriptor element to reference a
persistence unit defined at EAR level.
Also you need to include entity classes jar in manifest of pu jar http://wiki.eclipse.org/Packaging_and_Deploying_EclipseLink_JPA_Applications_(ELUG)
To summarize, you should be able to define your entities and the persistence unit at the top level of the EAR and to use them from the other modules.
I'm just not sure to understand what you tried and what problem(s) you faced.

The problem could be solved by placing a persistence.xml in a jar file that is located in the ear's lib directory.
The persistence.xml must contain the jar files which includes the Entities.
I had to give the relative path to the jar files.
My ear irectory structure
|-ear--
|-lib--|... some libs ...
| |--my-persistence-xml.jar
|-ejb-with-entities1.jar
|-ejb-with-entities2.jar
My persistence.xml for jboss 7.1.1
<persistence-unit name="my-pu" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/mypu</jta-data-source>
<jar-file>../ejb-with-entities1.jar</jar-file>
<jar-file>../ejb-with-entities1.jar</jar-file>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
Hope this helps

All you need
EAR +
|- META-INF +
| - persistence.xml
|- ejb1-module.jar
|- ejb2-module.jar
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="my-persistence-unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>MyDataSource</jta-data-source>
<!-- Note: it's relative to `persistence-module.jar` file location in EAR -->
<jar-file>../ejb1-module.jar</jar-file>
<jar-file>../ejb2-module.jar</jar-file>
<properties>
...
</properties>
</persistence-unit>
</persistence>

Example working EAR layout for Glassfish:
EAR +
|- lib +
| |- core-module.jar
| \- persistence-module.jar +
| \- META-INF +
| \- persistence.xml
|- ejb1-module.jar
\- ejb2-module.jar
EJB modules may be either jar archives or exploded directories.
In this case your persistence.xml may be like:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="my-persistence-unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>MyDataSource</jta-data-source>
<!-- Note: it's relative to `persistence-module.jar` file location in EAR -->
<jar-file>../ejb1-module.jar</jar-file>
<jar-file>../ejb2-module.jar</jar-file>
<properties>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
You have to update <jar-file> references if you use module versioning (e.g. ejb1-module-1.0-SNAPSHOT.jar).
Abstract objects with #MappedSuperclass annotation and EntityManager injection may be placed in any external jar. This jar does not require to be mentioned in persistence.xml. For example, you can create core-module.jar with PersistableEntity.java:
public class PersistableEntity {
#Id
#GeneratedValue
private Long id;
public Long getId() { return id; }
public Integer getVersion() { return version; }
}
And PersistableEntityManager.java:
public class PersistableEntityManager<T extends PersistableEntity> {
#PersistenceContext
protected EntityManager em;
}
This core-module.jar could be used by all your projects with different persistence units.
You just inherit your Entities and EJBs and avoid boilerplate.
Check out example bilionix-core on github.

Try with this:
Configure EAR application.xml file in this way:
http://xmlns.jcp.org/xml/ns/javaee/application_7.xsd"
version="7">
YourEEApplication
<initialize-in-order>true</initialize-in-order> <!-- This is the most important thing -->
<module>
<ejb>YourEJBModule1.jar</ejb>
</module>
<module>
<ejb>YourEJBModule2.jar</ejb>
</module>
......
<module>
<ejb>YourEJBModuleX.jar</ejb>
</module>
<module>
<web>
<web-uri>YourWebModule.war</web-uri>
<context-root>YourWebModule</context-root>
</web>
</module>
In your EJB projects YourEJBModule1, YourEJBModule2... and YourEJBModuleX:
Inject Persistence Context whitout the unitName property:
#PersistenceContext(type=PersistenceContextType.TRANSACTION)
private EntityManager em; // get & set
For each EJB module persistence.xml file:
YourEJBModule1:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PersistenceUnit1"
transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/YourDataSource</jta-data-source>
<class>com.example.Foo1</class>
<!-- Other properties -->
</persistence-unit>
</persistence>
YourEJBModule2:
<?xml version="1.0" encoding="UTF-8"?>
...
<persistence-unit name="PersistenceUnit2"
transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/YourDataSource</jta-data-source>
<jar-file>YourEJBModule1.jar</jar-file>
<class>com.example.Foo2</class>
<!-- Other properties -->
</persistence-unit>
...
YourEJBModuleX:
<?xml version="1.0" encoding="UTF-8"?>
...
<persistence-unit name="PersistenceUnitX"
transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/YourDataSource</jta-data-source>
<jar-file>YourEJBModule1.jar</jar-file>
<jar-file>YourEJBModule2.jar</jar-file>
......
<class>com.example.FooX</class>
<!-- Other properties -->
</persistence-unit>
...
In the database can exists various schemas, one per EJB module, access them through jta-data-source
(Deployed in Glassfish 4)

Here's what I did.
1) Package the persistence configuration files in a jar file. The jar file will contain:
META-INF/persistence.xml (and orm.xml if you use one)
Create a "lib" folder under the EAR project and stick the jar in there
2) Package the associated entity classes in another jar:
Put this jar file in your GlassFish domain/lib folder (or whatever lib folder equiv in other servers)
I initially bundled the jar in the EAR's "lib" folder but classes were not found
If anyone knows a better way to handle this please explain
The Persistence Context should now be accessible to all EJB and Web Apps bundled in your Enterprise Application.

I wanted to achieve shared persistance EJB module without EAR project.
This is possible by
moving all persistance entities to separate EJB project (do not move persistance.xml to new project, only classes are needed
compiling this EJB project
sending project to GlassFish server using
scpAsSudo ~/NetbeansProjects/UnifyEntities/dist/UnifyEntities.jar remoteUsername#192.168.0.1:/opt/glassfish3/domains/domain1/lib/ext
Have fun!

Related

Referencing entities from other jars in EAR

I'm trying to create a layered web proyect with an EAR. I divided the Entities from the DataAccess in order to only allow DataAccess to be called by BusinessLogic.
I'm actually getting this exception:
Object: co.edu.icesi.i2trading.entities.Statetype#21397ba0 is not a known entity type.
And I found here that I need to create a persistence.xml in the EAR, but I can't really understand how.
Sharing a persistence unit across components in a .ear file
I tried placing the XML file in the Configuration Files:
And referencing the jar with <jar-files> in the persistence.xml;
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="I2TradingDataAccessPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/I2DataSource</jta-data-source>
<jar-file>../I2TradingEntities.jar</jar-file>
<jar-file>../../I2TradingEntities.jar</jar-file>
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<property name="eclipselink.target-server" value="None"/>
<!-- <property name="eclipselink.logging.level" value="ALL"/> -->
<property name="eclipselink.logging.level" value="WARNING"/>
</properties>
</persistence-unit>
</persistence>
With no success. Any idea why? I'm very new to Web Developing and this is getting to my nerves.
I'm also getting this WARNING in the persistence.xml's DESIGN tab:
I believe that the instruction jar-file interprets any path from the file that holds the persistence.xml... So, your configuration specifies that the Entities JAR are siblings of your EAR file.
The best (and easy) solution for your problem is to put the given persistence.xmlat the META-INF folder of your I2TradingEntities.jar and remove the <jar-file> instructions from it ... This will instruct the Application Server to create a PersistenceContext called "I2TradingDataAccessPU" and to detect any #Entity Class contained in that JAR.

JPA persistence.xml properties in glassfish JDBC Resource

I have an application running on Glassfish 4.1 that uses a JDBC Resource. In the application itself I have a persistence.xml file that lists all the entities and tells the container which JDBC Resource to use. I have defined some properties to log the SQL it executes. It looks something like this:
<persistence version="2.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_2_0.xsd">
<persistence-unit name="MyResource_PU" transaction-type="JTA">
<jta-data-source>jdbc/my_resource</jta-data-source>
<class>com.example.entities.EntityOne</class>
<class>com.example.entities.EntityTwo</class>
<class>com.example.entities.EntityThree</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
</properties>
</persistence-unit>
</persistence>
Now when this application goes to production, I don't want the SQL to be logged. So every time I do a release, I need to remind myself to change the eclipselink.logging properties.
I thought, there should be a better way to handle this. So I went to the Glassfish admin console, to JDBC Resources and added the 2 properties there, but that doesn't work.
Is there any way to remove the "environment specific" values out of the persistence.xml file and into the Glassfish configuration? I have googled for a while now, but don't seem to find the correct sollution. What I did find is that Hibernate has the option to specify a "configuration file", but I haven't found this for EclipseLink.
We used maintain property files for each environment such as DEV,QA,PROD,UAT etc in different files and copy one of them during build.
Ant build
<property environment="env" />
<!-- ***** COMMAND LINE ARGUMENTS DEMOED HERE -->
<property name="build_type" value= "${env.build_type}"/>
<copy todir="deploy">
<fileset dir="src_dir"/>
<globmapper from=${env.build_type}".persistence.xml" to="persistence.xml"/>
</copy>
Run build like this
ant -Denv.build_type=PROD
This will copy PROD.persistence.xml to persistence.xml
ant -Denv.build_type=DEV
This will copy DEV.persistence.xml to persistence.xml
As per glassfish documentation, persistence.xml settings are meant to take precedence over global settings, so I wouldn't recommend anything in a persistence.xml file that you would want to override later.
That said, EclipseLink server integration can make use of a server log, allowing external control over settings. See this for a description of setting logging properties in glassfish that should control the log file EclipseLink writes to. Otherwise, you can define a different log mechanism in your peristence.xml file, such as log4J or a custom one that you can control how you wish as touched on here

Persistence unit name issue during deployment WildFly

Stuck with some issue with my persistence module.
getting error like "Unexpected problem gathering statistics: java.lang.IllegalStateException: JBAS011477: Persistence unit 'EAR_FileName.ear/EJB_Module_Persistence.jar#MyPersistenceUnit' is not available"
my persistence.xml file is located as highlighted below. please correct me if i am wrong - as per packaging structure persistence unit name starting with EAR file name then my persistence module name then #unit name, which is absolutely right. and i am injecting my persistence unit in another ejb using PersistenceContext.
#PersistenceContext(unitName="MyPersistenceUnit")
private EntityManager em;
could anyone suggest me what wrong i am doing here. i would appreciate any input/help you could provide on this.
here is below module structure of my project
EAR_FileName.ear
|
|---EJB_Module1.jar
|
|---EJB_Module_Persistence.jar
|
|---META-INF
|
|---persistence.xml
Here is my persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="MyPersistenceUnit" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MyTransactionDS</jta-data-source>
<class>all class</class>
<properties>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
</properties>
</persistence-unit>
</persistence>
P.S. using WildFly 8.1 as an application server.
thanks in advance.
It looks that there is already a defect at the Wildfly-Tracker for this problem:
WFLY-4908: Redeploy dependent ear fails with duplicate resource error for persistence unit
There is as well a post at the Jboss-Forum:
JBoss-Dev: Redeploy dependent ear fails with duplicate resource error for persistence unit
According to the defect description, the issue is fixed with Wildfly 10.1.0.CR1.

No Entity metadata found for the class

I'm back with the same problem ...
I'm trying to uses queries in my Cassandra DB with Kundera (Cassandra ORM), this queries work in an others project but when I try to do it in webapp (using tomcat 6.0), I got this error :
com.impetus.kundera.metadata.KunderaMetadataManager - No Entity metadata found for the class
=> JavaNullPointerException.
But when I leave the persistence.xml from my project I got an other error. (NoPersistence.xml found or something ... )
So, my project found Persistence.xml, but not my Entity class : fileCassandra.
You can see my persistence.xml :
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_2_0.xsd"
version="2.0">
<!-- 192.168.3.107 -->
<persistence-unit name="cassandra_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<class>net.***.common.db.***.FileCassandra</class>
<properties>
<property name="kundera.nodes" value="localhost"/>
<property name="kundera.port" value="9160"/>
<property name="kundera.keyspace" value="KunderaExamples"/>
<property name="kundera.dialect" value="cassandra"/>
<property name="kundera.client.lookup.class" value="com.impetus.client.cassandra.pelops.PelopsClientFactory" />
<property name="kundera.cache.provider.class" value="com.impetus.kundera.cache.ehcache.EhCacheProvider"/>
<!-- <property name="kundera.cache.config.resource" value="/ehcache-test.xml"/> -->
</properties>
</persistence-unit>
</persistence>
net..common.db..FileCassandra I must replace by * because it's name from my companie ;)
The same methods (include EntityManager) works in junit on other project, when I build my project in Tomcat, this error appears ...
This happens when you have multiple entries of the same class in your classpath.
The ideal place to have your entities is closest to the same class loader which loads kundera core and client(HBase, Cassandra etc.).
For example, if these kundera files are under WEB-INF/lib, you'd rather have your entities under the application where as if kundera files are on the applications lib folder, better bundle your entities in a jar and put them there (and remove the entities in your app).
Only issue which i can see is classes and persistence.xml location.
try to place persistence.xml within /WEB-INF/classes/META-INF/, Provided that your entity definitions are within classes folder!
-Vivek

Entities not mapped after moving them into external jar package

In my Java/Seam/JbossAS app, I decided to externalize my Model classes (hibernate entities) and moved them into another project. The project produces model.jar, which is then used by the main app. The model.jar dependency is resolved by Ivy.
Building the main app with Ant works without problems. Then I copy manually the model.jar into 'mainapp.ear/lib' directory. Afterwards I deploy the app and there are no problems (although I notice that there are is no log info about found mappings). But when I want to login, I get the exception:
javax.el.ELException: javax.ejb.EJBTransactionRolledbackException:
org.hibernate.hql.ast.QuerySyntaxException: AppUser is not
mapped [select u from AppUser u where u.userName = :usernamePar]
There were no code changes in the meantime, just externalizing some of the classes into a jar. Does this mean, that I need the source code of the Model classes when compiling the main app?
The EntityManagerFactory is built for scanning entities only from the jar that has a /META-INF/persistence.xml file into.
In order to scan other jars you have to use <jar-file>:
<persistence 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_2_0.xsd"
version="2.0">
<persistence-unit name="manager1" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/DefaultDS</jta-data-source>
<mapping-file>ormap.xml</mapping-file>
<jar-file>MyApp.jar</jar-file>
<class>org.acme.Employee</class>
<class>org.acme.Person</class>
<class>org.acme.Address</class>
<shared-cache-mode>ENABLE_SELECTOVE</shared-cache-mode>
<validation-mode>CALLBACK</validation-mode>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>
See 2.2.1 Packaging in Hibernate doc.
Also check if your hibernate mappings are correctly placed wrt hibernate config file. Note that hibernate mapping resources or classes are relative to the location of hibernate.cfg.xml file.

Categories