#Remote EJB which uses #RequestScoped CDI bean - java

I have an application which has a #Remote #Singleton EJB which injects a #RequestScoped entity manager produced by CDI. Another application on the same server (wildfly 9)/JVM will use this EJB to get a result fetched from the entity manager.
The first invocation of the EJB will return the expected result. It produces the entity manager, fetches the data and disposes the entity manager again when the invocation returns. Each subsequent invocation of that EJB will throw an error because of a closed entity manager. No produce / dispose for a new entity manager is made.
Is this the expected bahavior? Do I have an error in my code?
IFrameworkResourceManager framework = _applicationContext.getFrameworkResourceManager();
final User resolvedUser = framework.resolveUser(username, domain);
// ...
final Rights resolvedRights = framework.resolveRights(resolvedUser.getGuid(), applicationId);
// ...
This piece of code is executed in a CDI producer which again is executed as soon as a new http session is created for an user. Nothing changes if I call getFramworkResourceManager again before invoking resolveRights.
public IFrameworkResourceManager getFrameworkResourceManager() {
return IFrameworkResourceManager frm = (IFrameworkResourceManager) ctx
.lookup("java:global/WebFramework/WebFrameworkImpl!my.package.IWebFramework");
}
It doesn't matter if I use a direct JNDI lookup or #EJB injection. The returned instance is reported (toString()) as Proxy for remote EJB StatelessEJBLocator for "/WebFramework/WebFrameworkImpl", view is interface my.package.IWebFramework, affinity is None
#LocalBean
#Singleton
public class WebFrameworkImpl implements IWebFramework, Serializable {
#Inject
private EntityManager _entityManager;
#Override
public User resolveUser(String username, String domain) {
System.out.println(_entityManager + " || " + _entityManager.isOpen());
// execute query using QueryDSL and the injected entityManager
}
#Override
public Rights resolveRights(String guidUser, int applicationId) {
System.out.println(_entityManager + " || " + _entityManager.isOpen());
// execute query using QueryDSL and the injected entityManager
}
}
#Remote
public interface IWebFramework extends IFrameworkResourceManager {
// some methods...
}
public interface IFrameworkResourceManager {
public User resolveUser(String username, String domain);
public Rights resolveRights(String guidUser, int applicationId);
}
Sysout of resolveUser: org.hibernate.jpa.internal.EntityManagerImpl#379e882b || true
Sysout of resolveRights: org.hibernate.jpa.internal.EntityManagerImpl#379e882b || false
Edit 20.11.2015 13:43: Persistence unit is of type RESOURCE_LOCAL. Additionally all #ResourceScoped beans are affected. #PostConstruct and #PreDestroy are only invoked for the first EJB invocation. Each subsequent invocation uses the previous instance of the resource scoped bean which is not correct.
Edit 20.11.2015 13:55: Everything works as expected if the EJB is invoked from within the same application that provides the EJB. This behavior only appears for invocations from other applications.
Edit 20.11.2015 15:24: JBoss AS 7.1.3.Final, Wildfly 9.0.0.Final and Wildfly 10.0.0.CR4 are all effected. But according to the CDI spec (1.0 to 1.2) chapter 6.7.4 this should work. I've filled a bug report (WFLY-5716).

When using RESOURCE_LOCAL, you shoud create youe EntityManager from EntityManagerFacgtory and handle it by yourself, like:
private EntityManagerFactory factory = Persistence.createEntityManagerFactory("unit-name");
public void someMethod(){
EntityManager em = emf.createEntityManager();
EntityTransaction tx = null;
try {
tx = em.getTransaction();
tx.begin();
// do some work
tx.commit();
}
catch (RuntimeException e) {
if ( tx != null && tx.isActive() )
tx.rollback();
throw e; // or display error message
}
finally {
em.close();
}
}

Bugfix for this wired behavior is already merged in the WELD repository:
WFLY-5716
WELD-2069

Related

calling EJB3 session bean from a webservice EJB3 session bean causing entity manager null

Ok I have a scenario here, and I want a standard solution, basically I have exposed EJBsession3 beans as my webservice on the server side and they further call the EJBsession3 bean to execute DAO methods. see below is the sample Code.
//This is a EJB3 session bean and I am using container managed jta transactions
#Stateless
public class datatypes implements datatypesRemote {
#PersistenceContext(unitName = "EJBtest")
EntityManager entityManager;
public List<Datatype> retrieveAllDatatypes(int targetSystemId,EntityManager ent)
throws RuntimeException {
String q = "SELECT oneDatatype from " + Datatype.class.getName()
+ " oneDatatype "
+ "where oneDatatype.targetSystem.targetSystemId = "
+ targetSystemId;
//entityManager=ent;
Query query = entityManager.createQuery(q);
System.out.println("Query retrieveAll" + q);
#SuppressWarnings("unchecked")
List<Datatype> templates = query.getResultList();
return templates;
}
}
The class above is basically my DAO class that will handle queries now below is my web services class
#WebService(serviceName="backend")
#Stateless
public class backEndForm implements backEndFormRemote {
//#PersistenceContext(name = "EJBtest")
//EntityManager entityManager;
private datatypesRemote data= new datatypes();
public List<Datatype> retrieveAllDatatypes(int id){
//entityManager.clear();
data=new datatypes();
return data.retrieveAllDatatypes(id,null);
}
}
Now the Issue is like this my web client calls my web service method and that method further calls the DAO methods that will fetch the data from data base and return to the web service and web service will return data to the requesting client
But when I execute my SQL query the entity manager is null I don't know why so a non standard solution I developed is to pass the entity manager from the web services class to the DAO class, as you can see in the sample code which is commented out.
So my question, is there any other Standard way to do it ? why the entity manager is null in the second ejb3 bean and not in the first ejb3 bean ?
Injection does not happen when you create objects with the new operator. You need to let your container create the datatypes bean and inject it into your backEndForm:
#WebService(serviceName="backend")
#Stateless
public class backEndForm implements backEndFormRemote {
#EJB
private datatypesRemote data;
public List<Datatype> retrieveAllDatatypes(int id){
return data.retrieveAllDatatypes(id,null);
}
}

Injected EntityManager's scope/lifecycle in a Stateless bean

Can someone explain the lifecycle of an injected EntityManager in a stateless bean? If a stateless bean has an injected EntityManager associated with a specific PersistenceContext, what happens to that association the second time the bean is used?
For example, I have the following:
#Stateless
public class TimeStepsBean
{
#PersistenceContext(unitName="DynamicDB")
private EntityManager em;
public List<TimeStep> timeSteps = new ArrayList<TimeStep>();
private void init()
{
if (timeSteps.isEmpty())
{
TypedQuery<TimeStep> query = em.createQuery("SELECT t FROM TimeStep t", TimeStep.class);
timeSteps = query.getResultList();.
}
}
public void refreshSteps()
{
init();
em.flush();
em.refresh(timeSteps.get(0));
}
}
When refreshSteps is called the second time the bean is used (a second transaction), I get a "java.lang.IllegalArgumentException: Entity not managed". The entityManager was injected, so I am assuming that it is always part of the current persistence context. Is that true?
Adding em.merge(timeSteps.get(0)) before the refresh still generates the same exception.
Your timeSteps is a state. Your class is annotated as stateless. It's a misuse of the framework.

Pass Injected EntityManager to a web session persisted object

Is it secure to pass a Injected EntityManager created on an EJB, to a method that will return an Object, and after, persist that Object on a Web Session for web clients use it?
Like in this example:
the EJB
#Stateless(mappedName = "MyService")
#LocalBean
public class MyService implements MyServiceLocal {
#PersistenceContext(unitName="primary")
private EntityManager em;
/**
* Default constructor.
*/
public MyService() {
}
#Override
public Service newServiceX(User user) {
return new ServiceX(user,em); // here, passing the EntityManager
}
}
After, I persist this Service in a web client (using struts):
The base action
public class YAction extends ActionSupport implements SessionAware{
#Inject
private MyServiceLocal service;
public String execute(){
Service x = service.newServiceX();
persistInCookie("ServiceX",x);
}
public void persistInCookie(String, Object){
// persist
}
}
And after, using another Action:
// another Action that
class XAction{
public String useService(){
getService().doSomething();
}
protected Service getService(){
Service service = (Service) getSessionMap().get("ServiceX");
return service;
}
}
the POJO class ServiceX using the EntityManager:
public class ServiceX extends Service{
EntityManager em;
public ServiceX(User user, EntityManager em){
this.em = em;
}
public void doSomething(){
// do something with the EntityManager passed by the EJB
}
}
First, the action that would be call is the Y action to persist the Service on the Session, next, the X action will return the Service persisted on the Session and try to use it.
I believe that the EJB Stateless Session Bean can close My EntityManager and this ServiceX POJO class can't use it. This can happen? I found similar question HERE, but in this question, the EntityManager is passed to a helper class. In my case is different because I want to persist this Object on a session cookie, and use later.
I don't think It is a good idea to store a EntityManager in SessionMap. What is more, I don't even think that it is a good idea to perform EntityManager operations outside the EJB container.
Have read about transaction-boundaries in JPA?
By default, EJB container is using CMT (Container Managed Transactions). In this case, container uses entitymanager-per-request pattern which means that the transaction begins and ends when one of the business methods of MyService starts and ends (transaction is committed or rollbacked in case of RuntimeException). For whole transaction time, EntityManager is connected with the same PersistenceContext. After the transaction is ended the container closes EntityManager which means that the EntityManager is disconnected with recent PersistenceContext:
// transaction begins
Service x = service.newServiceX();
// transaction ends
This might be crucial if you were going to do some update/insert operations outside the transaction.
Now, when you call EntityManager operation (like find) outside the transaction, for every each operation the EntityManager will create new PersistentContext. This may cause some issues, as two entities that represent the same record will be treated as different entities:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
Some more articles to read:
Persistent Context
Transactions and Concurrency
Entity Lifecycle Management

is it possible to use #transactional annotation with a transaction opened by hand (spring/hibernate)

I have a spring application which works with hibernate and annotations.
I open a session by hand which is done like in this How do I manually open a hibernate session? stack overflow answer.
Now i want to use a method of a service in the method that opens the session itself. This service however is annotated with the transactional statement. Is it possible to tell the method to use the transaction i just opened by hand?
e.g.
#Transactional("TransactionManager")
class Service1 {
public LazyObject someMethod();
}
class MetaService {
#Autowired
SessionFactory sf;
Service1 s1;
public someMethod() {
Session s = sf.openSession();
s.beginTransaction();
// tell this method to use s's transaction
// without annotating someMethod() with #transactional
LazyObject lo = s1.someMethod();
for ( LazyAtt la : lo.getLazyAtt() ) {
la.doSomething();
}
s.flush();
s.getTransaction().commit();
s.close();
}
}
For those wondering why I want to do it, check this question:
https://stackoverflow.com/questions/29363634/how-to-open-two-sessions-in-one-function-in-hibernate-spring

Statefull Ejb and Session scoped Managed bean Inject null pointer

Could anyone help me? There is a SessionScoped Managed Bean and one Stateless Ejb and one other Stateful Ejb..
The serachCustomer() method in the MB call the injected DaoEjbTst searcCustomer() method which return with an instance of BCus entity object. I injected in to Stateless DaoEjbTst Ejb the other Stateful CustomerSession EJB and when the entity instance is ready in the DaoEjbTst EJB i call the CustomerSession EJB setActualCustomer method and i give as paramter the entity instance for this method and try to store it... Then when i try to get this "stored" entity instance with another showTstDate() method in the ManagedBean it's throws NullPointer Exception.. And i dont know why.. Why doesn't exist the public BCus actualCustomer paramter in the stateful ejb? I tryed to create #PreDestroy and #PrePassivate and #Remove methods in the Stateful Ejb to check if the container remove it but this methods never invoked by the container.. So i'm sure the ejb exist.. but inspite of this i can't access it :( I don't use interfaces.
Here is my managedbean:
#EJB
private DaoEjbTst daoEjb;
#EJB
private CustomerSession customerSession;
public void serachCustomer() throws IOException {
FacesContext ctx = FacesContext.getCurrentInstance();
if (daoEjb.searcCustomer(custNo)) {
ctx.getExternalContext().redirect("showCustomer.xhtml");
}
else {
ctx.getExternalContext().redirect("test.xhtml");
}
}
public String showTstDate() {
log.info("MB EJB EXIST: " + customerSession);
return "Test: " + customerSession.getActualCustomer().getCustName();
}
Here is my DaoEjbTst:
#Stateless
public class DaoEjbTst {
private final Logger log = Logger.getLogger("DaoEjbTst.class");
#EJB
private CustomerSession customerSession;
public CustomerSession getCustomerSession() {
return customerSession;
}
public void setCustomerSession(CustomerSession customerSession) {
this.customerSession = customerSession;
}
#PersistenceContext(unitName = "TestAppPU")
private EntityManager em;
public boolean searcCustomer(String custNo) {
try {
BCus cus = (BCus) em.createNamedQuery("BCus.findByCustomerno").setParameter("customerno", custNo).getSingleResult();
log.info("DAOEJB: " + cus);
customerSession.setActualCustomer(cus);
return true;
}
catch (NoResultException e) {
log.info(e.getMessage());
return false;
}
}
And here is my CustomerSession EJb:
#Stateful
public class CustomerSession {
public BCus actualCustomer;
private final Logger log = Logger.getLogger("CustomerSession.class");
public BCus getActualCustomer() {
return actualCustomer;
}
public void setActualCustomer(BCus actualCustomer) {
this.actualCustomer = actualCustomer;
checkTst();
}
public CustomerSession() {
}
}
I think that CustomerSession bean injected in ManagedBean isn't the same bean instance that is injected in DaoEjbTst. So invoking:
customerSession.getActualCustomer()
in ManagedBean simply returns null because ActualCustomer field was not set for this particular bean instance. It was set in DaoEjbTest but this is different instance of CustomerSession. So:
DaoEjbTst.getCustomerSession().equals(ManagedBean.getCustomerSession())
gives false.
When you look into specification EJB 3.1 (section 3.4.7.1) you see:
A stateful session object has a unique identity that is assigned by the container at the time the object is
created.
Basically what you should do is to setActualCustomer for the instance of CustomerSession bean in ManagedBean with value that is found in DAO's searcCustomer() method. However storing stateful session bean inside stateless bean is a very bad idea and I suggest you to rethink your architecture.

Categories

Resources