user3308224
user3308224

Reputation: 423

Separating Java EE components in different projects

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

  1. DomainEntities - contains my JPA entities
  2. RemoteInterface - contains remote interfaces (i'm trying to separate the implementation)
  3. RemoteEJB - implements the interface from RemoteInterface (project 2)
  4. WebApp Client (i have a servlet that calls RemoteInterface to test if the ejb is working)

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

Answers (1)

Yser
Yser

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

Related Questions