Java EE 6: how to add a web module on top of a client application

Technology(Java EE 6 with Glassfish 3.1, Netbeans 7.0)

I have an application client that accesses DB through JPA. No EJB . Now I need to add a web interface for this application. Therefore, I will use JSF 2.x I have some concerns about the design here, and I hope the community helps me. So thanks BalusC, I can use JPA in a separate client application by specifying transaction-type=RESOURCE_LOCAL in the persistence.xml file. Below are the demos:

EDIT that the codes below have been edited based on BalusC's suggestion

Here is my application client main

 public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("CoreInPU"); EntityManager em = emf.createEntityManager(); EntityDAO entityDAOClient = new EntityDAOClient(em); Main pgm = new Main(); try { process(entityDAOClient); } catch (Exception e) { logger.fatal("", e); }finally{ em.close(); emf.close(); } } public void process(EntityDAO entityDAO){ validatePDF(List<pdfFiles>); processPDF(List<pdfFiles>, entityDAO); createPrintJob(List<pdfFiles>, entityDAO); } public void processPDF(List<pdfFiles>, EntityDAO entityDAO){ for(File file : pdfFiles){ entityDAO.create(file); } } 

Here is my DAO interface class in my App Client

 public interface EntityDAO { public <T> T create(T t); public <T> T find(Class<T> type, Object id); public List findWithNamedQuery(String queryName); public List findWithNamedQuery(String queryName, int resultLimit); } 

Here is the App DAO Client

 public class EntityDAOClient implements EntityDAO { private EntityManager em; private static Logger logger = Logger.getLogger(EntityDAOClient.class); public EntityDAOClient(EntityManager em) { this.em = em; } @Override public <T> T create(T t){ em.getTransaction().begin(); em.persist(t); em.getTransaction().commit(); return t; } @Override public <T> T find(Class<T> type, Object id){ em.getTransaction().begin(); T t = em.find(type, id); em.getTransaction().commit(); return t; } ... } 

And here is persistence.xml

 <persistence-unit name="CoreInPU" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>com.wf.docsys.core.entity.Acknowledgement</class> <class>com.wf.docsys.core.entity.PackageLog</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/core"/> <property name="javax.persistence.jdbc.password" value="root"/> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="javax.persistence.jdbc.user" value="xxxx"/> <property name="eclipselink.ddl-generation" value="create-tables"/> </properties> </persistence-unit> 

Now I need to add a web module on top of this. I know I need a JTA transaction type, so I am creating an EAR project project foo with foo_ejb and foo_war in it. So my EJB looks like this.

 @Stateless @LocalBean public class CoreEJB implements EntityDAO{ @PersistenceContext(unitName = "CoreInWeb-ejbPU") private EntityManager em; //@Override public <T> T create(T t) { em.persist(t); return t; } //@Override public <T> T find(Class<T> type, Object id) { return em.find(type, id); } ... } 

Note that CoreInWeb-ejbPU is the new persistence.xml object name with the JTA transaction type. I also add the jar file of the application file to the foo_ejb package. When deploying, I received this Invalid ejb jar [foo-ejb.jar]: it contains zero ejb. It is because of this that the @Stateless public class CoreEJB implements EntityDAO . If I take implements EntityDAO , then it will be deployed, but I need EJB to implement EntityDAO so that I can do it in my managed bean

 @ManagedBean @RequestScoped public class Bean { @EJB private CoreEJB coreEJB; public Bean() { } public void runAppClientMainProcess() { //The web interface can also kick off the same process as the app client process(coreEJB); } // ... } 

How can I do it right? Please, help

I know that I could ask too much here, but if you can build on my structure above, show me how to add a web module, I would really appreciate it. Some codes would be great. I am still involved, so if my design is a flaw, feel free to break it, I will redesign everything if I run away that there is a better way to achieve this. The bottom line is a set of business logic, and I want to access them through the application client and web interface . Like glassfishv3, there is a web interface and admin console

+7
source share
4 answers

I want to apologize for my late reply. I was on schedule for another project, so I don’t have time to write the correct answer to the answers of BalusC and kiran .

kiran ask me: Case 2 - Web Module - You have used(want to use) jsf for presentation , CoreEJB for persistence -- i am not clear where you intend to put business logic, for now ill take is as another ejb class.

The answer . Hi, kiran, in the end I want the same set of logics to be available both on the client side and on the web module side. As an application server for glass fish. You have a command line version and a web module version, access to the same resources.

BalusC suggestion to use RESOURCE_LOCAL works fine if I just use the application client. However, as soon as I add the web module on top of it, I cannot get it to work, even though BalusC tried to work with me. You guys can read BalusC's answer and my implementation of his idea above (the code from the original post is my implementation of the BalusC idea). If I add the App Client to the Java EE (EAR) class path, it will not get a compilation error when I try to access the logic from the App Client, but when I run the web module, it throws an Exception saying that it does not see the class / method that I am trying to get from the App Client. So I decided to port all my logic to EJB and make my App Client very thin. Logic will be opened for the App Client application through the javax.ejb.Remote interface and will be opened through the web module through the javax.ejb.Local interface. So, here is my general outline of this idea.

This is my thin application client (main)

 public class Main { @EJB private static CoreMainEJBRemote coreEJBRemote; private static Logger logger = Logger.getLogger(Main.class); /** * @param args the command line arguments */ public static void main(String[] args) { coreEJBRemote.process(args[0]); } } 

So, on my side of the EJB, in the package inside the Java EE project (EAR), which contains the EJB and the web module, I have

 @Stateless public class CoreMainEJB implements CoreMainEJBRemote, CoreMainEJBLocal { @EJB private PackageProcessor packageProcessor; @Override public void process(String configFileName) { ... //Process config File packageProcessor.validatePDF(); packageProcessor.processPDF(); ... } } 

Note that since all the logic is inside the EJB, I can use the JTA transaction type that is managed by the container. I like it better than managing it myself.

Some people suggest exposing business logic through RESTful. Since I don't know RESTful very well, I will stay with this implementation for now. Thank you for your help BalusC and kiran .

0
source

Can you guys tell me where to put / create another persistence.xml with transaction type = "JTA"? Inside my web module or create a separate EJB?

This is not true. It should still be in the /META-INF/persistence.xml file. If your project is a WAR, put it in a web project. Or, if it represents an EAR, put it in an EJB project.


In JSF, I use a Managed Bean, how is my managed bean method called from EntityUtil? I ask this question because, as a rule, I have an EJB somewhere, so if I want my Managed bean to access it, I insert the EJB using the @EJB annotation. Since EntityUtil is not annotated as an EJB, how can I access it from a Managed Bean?

In theory, you can simply create a new EJB that combines / delegates EntityUtil and, in turn, injects this EJB into a managed bean.

 @Stateless public class SomeEJB { @PersistenceUnit(unitName="someWebPU") private EntityManagerFactory emf; @PostConstruct public void init() { EntityUtil.newInstance(emf); } public void create(Some some) { EntityUtil.create(some); } // ... } 

However ... Your EntityUtil not thread safe . Everything in your EntityUtil static . The Java EE web application is a multi-threaded environment. Simultaneous users use the same code base. All public static variables are shared among all users. When a user calls close() on your EntityUtil , this will affect all current webapp users. Thus, those who are engaged in a transaction will get an exception.

Regardless of this, the client or the web application, you must create the EntityManagerFactory only once when the application starts, reuse the same instance throughout the life of the application and close it only when the application terminates. EntityManager needs to be created only once per transaction or session and be closed at the end of the transaction or session. In Java EE 6 with a JTA transaction type, transactions are fully container-controlled. But in a client application with a local type of resource transactions, you need to manage transactions yourself.

I would suggest rewriting your EntityUtil to a DAO-like interface that intends to have different implementations for the client application and the web application.

 public interface SomeDAO { public void save(Some some); // ... } 

Here you can implement it for a client application:

 public class SomeDAOClient implements SomeDAO { private EntityManager em; public SomeDAO(EntityManager em) { this.em = em; } public void save(Some some) { em.getTransaction().begin(); em.persist(some); em.getTransaction().commit(); } // ... } 

and use it as follows:

 public static void main(String[] args) throws Exception { EntityManagerFactory emf = Persistence.createEntityManagerFactory("someClientPU"); EntityManager em = emf.createEntityManager(); SomeDAO someDAO = new SomeDAOClient(em); try { Some some = new Some(); some.setFoo("foo"); someDAO.save(some); } finally { em.close(); emf.close(); } } 

Here you can implement it for a web application:

 @Stateless public class SomeDAOEJB implements SomeDAO { @PersistenceContext(unitName="someWebPU") private EntityManager em; public void save(Some some) { em.persist(some); } // ... } 

and use it as follows

 @ManagedBean @RequestScoped public class Bean { @EJB private SomeDAO someDAO; private Some some; public Bean() { some = new Some(); } public void save() { someDAO.save(some); } // ... } 
+6
source

@Harry You are discussing three levels: 1) Presentation 2) Business 3) Persistence

Case 1 - Application Client. You used the main class for presentation, validatePDF, processPDF, createPrintJob is your business level. 3) EntityDAOClient and JPA - your persistence level.

Case 2 - Web module - you used (want to use) jsf for presentation, CoreEJB for perseverance - I don't know where you intend to put business logic, since now a bad take is another ejb class.

The main problem in this approach is "Using two different approaches for the level of business logic." Case 1 is a simple Java variant of Case 2 Ejb.

When you use plain java, you lose the luxury of dependency injection, tx control, concurrency control, interceptors, etc.

When you use EJB, you lose the flexibility to exchange code with the application client.

The solution is to use CDI. With CDI, you can integrate both of your use cases. It works like a bridge between three layers. Provide all the capabilities of dependency injection, interceptors, decorators for the application client.

Effectively there will be zero changes in the level of your business level and the code of the save level in the client application, as well as in JavaEE.

I mentioned in the CDI programming model that you do not need to use @managed. All pojo are CDI beans.

In CDI you do not need to write a main class. Start writing business logic below

<to> //This class works as is in both javaEE and client. //There is no need of managedbean in CDI. //This class can be accessed in jsf using EL #businessProcessor @Singleton @Named public class BusinessProcessor { private @Inject EntityDAO entityDAO; // CDI will inject an implementation of EntityDao. //In our case there is only one impl for client as well as JavaEE //This class works as is in both javaEE and client. //There is no need of managedbean in CDI. //This class can be accessed in jsf using EL #businessProcessor @Singleton @Named public class BusinessProcessor { private @Inject EntityDAO entityDAO; // CDI will inject an implementation of EntityDao. //In our case there is only one impl for client as well as JavaEE

// CDI will invoke below method on startup. Not used in JavaEE. // In JavaEE JSF will execute process () directly using Expression Language public void init (@Observes ContainerInitialized event, @Parameters List parameters) {process (entityDAO); }

public void process (@Inject EntityDAO entityDAO) {validatePDF (List); processPDF (List, entityDAO); createPrintJob (List, entityDAO); }

public void processPDF (List, EntityDAO entityDAO) {for (File file: pdfFiles) {entityDAO.create (file); }}}

<Preview> // this class is same for both JavaEE and Client public class EntityDAOClient implements EntityDAO {

private @Inject EntityManager em;

private static Logger logger = Logger.getLogger (EntityDAOClient.class); @Override public T create (T t) {em.getTransaction (). Begin (); em.persist (t); em.getTransaction (). commit (); return t; }

@Override public T find (Class type, Object id) {em.getTransaction (). Begin (); T t = em.find (type, id); em.getTransaction (). commit (); return t; } ...}

To start the application client <Preview> java org.jboss.weld.environment.se.StartMain For more meat, check www.seamframework.org

+2
source

You can make some small sample projects with netbeans and see how it works. NetBeans generates all these β€œsad” things for you, so you can explore it and do it yourself.

0
source

All Articles