One solution is to use some lightweight container such as Spring instead of real Containers, but this project was so simple that i needn't to complex the Dev process (and introduce many jars ....)
I went with using Java Daynaic Proxy to centralize the code/control of the JPA; here's the code of the proxy:
package com.forat.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import com.forat.service.exceptions.DAOException;
/**
* Example of usage :
* <pre>
* OnlineFromService onfromService =
* (OnlineFromService) DAOProxy.newInstance(new OnlineFormServiceImpl());
* try {
* Student s = new Student();
* s.setName("Mohammed");
* s.setNationalNumber("123456");
* onfromService.addStudent(s);
* }catch (Exception ex) {
* System.out.println(ex.getMessage());
* }
*</pre>
* @author mohammed hewedy
*
*/
public class DAOProxy implements InvocationHandler{
private Object object;
private Logger logger = Logger.getLogger(this.getClass().getSimpleName());
private DAOProxy(Object object) {
this.object = object;
}
public static Object newInstance(Object object) {
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), new DAOProxy(object));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
EntityManagerFactory emf = null;
EntityManager em = null;
EntityTransaction et = null;
Object result = null;
try {
emf = Persistence.createEntityManagerFactory(Constants.UNIT_NAME);
em = emf.createEntityManager();;
Method entityManagerSetter = object.getClass().
getDeclaredMethod(Constants.ENTITY_MANAGER_SETTER_METHOD, EntityManager.class);
entityManagerSetter.invoke(object, em);
et = em.getTransaction();
et.begin();
result = method.invoke(object, args);
et.commit();
return result;
}catch (InvocationTargetException ex) { // Exception in Called code
// Any exception that occur in the invoked method body can be got by ex.getCause();
// you can rollback transaction here
}catch (Exception ex) {// Exception in Proxy code
et.rollback();
Throwable cause = ex.getCause();
logger.log(Level.SEVERE, cause.getMessage());
if (cause instanceof DAOException)
throw new DAOException(cause.getMessage(), cause);
else
throw new RuntimeException(cause.getMessage(), cause);
}finally {
em.close();
emf.close();
}
}
}
Here's the service Interface "OnlineFromService":
package com.forat.service;
import java.util.Set;
import com.forat.model.Student;
import com.forat.service.exceptions.StudentNotFoundException;
public interface OnlineFromService {
public void fillFaculties(String[] facultiesNames);
public void addFaculty(String facultyName);
public void fillGovernrates(String[] GovernratesNames);
public void addGovernrate(String GovernrateName);
public void addStudent(Student student);
public Student findStudent(String nationalNumber) throws StudentNotFoundException;
public void updateStudent(Student student);
public Set<Student> getAllStudents();
}
And here's the Service Implementation:
import java.util.Set;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import com.forat.model.Student;
import com.forat.service.exceptions.StudentNotFoundException;
/**
* This class should be called through {@link DAOProxy} as it injects the {@link EntityManager} and other JPA staff
* and takes care of the transactions (commiting/rollbacking) , etc...
* @see DAOProxy
* @author mohammed
*/
public class OnlineFormServiceImpl implements OnlineFromService {
private Logger logger = Logger.getLogger(this.getClass().getSimpleName());
private EntityManager em;
public OnlineFormServiceImpl() {
}
public void setEntityManager(EntityManager em) {
this.em = em;
}
// the code has been minimized, the code that is responsalbe of working with JPA staff has moved to the proxy class
// we we do here just use the EntityManager (as if we were in a managed environment)
public void addStudent(Student student) {
em.persist(student);
}
// other interface methods goes here ...
}
The idea is to centralize the control of the persistence code, and this implementation is a basic implementation that may contains errors.
Also, this code my includes performance impact, as I used reflections to invoke service methods, but for sure its performance impact will be more less than of application servers!
1 comment:
Here's a valuable reply from
ewernli
from StackOverflow
Post a Comment