Reputation: 423
i'm trying to learn how to separate java EE components.
i want to separate my jpa entities, ejbs, and web client into different projects
so i developed four different projects and compiled them in their own jars/wars
DomainEntities' jar structure is
DomainEntities
-META-INF
-MANIFEST.MF
-entities
-Student.class
RemoteEJB's jar structure is
RemoteEJB
-META-INF
-MANIFEST.MF
-persistence.xml
-sample
MyStatelessBean.class
The persistence.xml in RemoteEJB is (based on searching the web):
<?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="RemoteEJBPU" transaction-type="JTA"><provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/pwucdb</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<!--<jar-file>DomainEntities.jar</jar-file>-->
</persistence-unit>
</persistence>
the jta datasource is defined in my glassfish server. the exclude-unlisted-classes and jar-file tags are based on my research on separating the jpa entities on a different jar. when i uncomment the jar-file tag, the ejb cannot be deployed to the server,so i comment it.
the servlet that calls uses the ejb is:
@WebServlet(name = "NewServlet", urlPatterns = {"/NewServlet"})
public class NewServlet extends HttpServlet {
@EJB
private MyRemoteInterface myRemoteInterface;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println(myRemoteInterface.getMessage());
out.println("Num of records retrived: " + myRemoteInterface.getStudents().size());
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
when i try to access the servlet i am having this warning/error
WARNING: The collection of metamodel types is empty. Model classes may not have been found during entity search for Java SE and some Java EE container managed persistence units. Please verify that your entity classes are referenced in persistence.xml using either <class> elements or a global <exclude-unlisted-classes>false</exclude-unlisted-classes> element
WARNING: A system exception occurred during an invocation on EJB MyStatelessBean method public java.util.List sample.MyStatelessBean.getStudents()
javax.ejb.EJBException
.....
Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [SELECT s FROM Student s]. Unknown entity type [Student].
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1477)
if i comment out exclude-unlisted-classes tag, uncomment the jar-file tag and deploy. i get this server warning:
a jar-file [DomainEntities.jar] specified in persistence.xml is not found
The server also looked for a file called [...\build\DomainEntities_jar].
Upvotes: 2
Views: 1032
Reputation: 2106
I recommend to bundle that JAR's and WAR's into an EAR-Archive. If you use maven you could add this plugin to the EAR's pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ear-plugin</artifactId>
<version>2.8</version>
<configuration>
<version>6</version>
<encoding>${project.build.sourceEncoding}</encoding>
<defaultLibBundleDir>APP-INF/lib</defaultLibBundleDir>
<fileNameMapping>no-version</fileNameMapping>
<displayName>${project.artifactId}</displayName>
<modules>
<jarModule>
<groupId>${project.groupId}</groupId>
<artifactId>domain</artifactId>
</jarModule>
<ejbModule>
<groupId>${project.groupId}</groupId>
<artifactId>ejb</artifactId>
</ejbModule>
</modules>
</configuration>
</plugin>
Thus all libs of the EAR will be copied into /APP-INF/lib. In this scope its now accessible from the EJB view. Just call it like this:
<jar-file>APP-INF/lib/domain.jar</jar-file>
Note the
<fileNameMapping>no-version</fileNameMapping>
thats really important if you want to change the version of your domain-archive frequently otherwise you have to edit the EJB's persistence.xml all the time ;)
Some additions:
If you bundle everything into an EAR-Archive its not neccessary to use Remote Interfaces anymore. You just need Local Interfaces for that. Thats a good thing because accessing an EJB over Remote Interfaces is much slower than accessing them with Local Interfaces. Thats because Java serializes all objects to send them over the network.
Upvotes: 1