Technology(Java EE 6 with Glassfish 3.1, Netbeans 7.0)
I have an application client that access a db via JPA. No EJB
is involved. Now I need to add an web interface for this application client. So I will choose to use JSF 2.x
. I have some concern about design here, and I hope the community would help me out. So thanks to BalusC, I am able to use JPA in a stand alone client application by specify transaction-type=RESOURCE_LOCAL
in the persistence.xml. Below are demonstration:
EDIT the below codes has been edited base on BalusC suggestion
Here is my App 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 Client DAO
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 the 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 JTA
transaction type, so I create an EAR project call foo
with foo_ejb
and foo_war
in it. So my EJB look 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 unit name with JTA
transaction type. I also add my app client jar file to the foo_ejb
package. When I deploy I got this message Invalid ejb jar [foo-ejb.jar]: it contains zero ejb.
It is because of this @Stateless public class CoreEJB implements EntityDAO
. If I take the implements EntityDAO
out then it is deploy, but I need the EJB to be implements EntityDAO
so that in my managed bean I can do this
@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 this correctly? Please help
I know I might be asking too much here, but if you can base on my structure above, show me how to add a web module in, I would greatly appreciate it. Some codes would be awesome. I am still learning, so if my design is flaw, feel free to rip it, I will redesign everything if I am convince there are better way to accomplish this. Bottom line is, there are a set of business logic, and I want to access those via both application client
and web interface
. Like how glassfishv3 have web interface and admin console
Can you guys tell me where should I put/create another persistence.xml with transaction-type="JTA"? Inside my web module, or create a separate EJB?
It's not different. It still needs to go in a /META-INF/persistence.xml
file. If your project represents a WAR, put it in web project. Or if it represents an EAR, put it in EJB project.
In JSF, I use Managed Bean, how would my managed bean invoke method from EntityUtil? I ask this question because usually I have a EJB somewhere, so if I want my Managed bean to access it, I inject EJB using @EJB annotation. Since EntityUtil is not annotated to be EJB, how I can access it from Managed Bean?
In theory, you could just create a new EJB which composes/delegates EntityUtil
and in turn inject this EJB in 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
is not threadsafe. Everything in your EntityUtil
is static
. A Java EE web application is a heavily multithreaded environment. Mutiple concurrent users use the same codebase simultaneously. All publicitly exposed static variables are shared among all users. When an user calls close()
on your EntityUtil
, it will affect all current users of the webapp. So the ones who are busy with a transaction will get an exception.
Regardless of it's a client or a web application, you should create the EntityManagerFactory
only once on application's startup, reuse the same instance throughout the application's lifetime and close it only on application's shutdown. The EntityManager
needs to be created only once per transaction or session and be closed by end of transaction or session. In Java EE 6 with JTA transaction type the transactions are fully managed by the container. But in a client app with resource local transaction type you need to manage the transactions yourself.
I'd suggest to rewrite your EntityUtil
to a DAO-like interface which is intented to have different implementations for the client app and the web app.
public interface SomeDAO {
public void save(Some some);
// ...
}
Here's how you would implement it for the 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's how you would 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);
}
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With