Search code examples
jpajava-ee-6earjtawebsphere-8

WebSphere 8.5.5: No active transaction for PuId


I'm working on a JaveEE6 web application running on WebSphere 8.5.5. For accessing the database I use CDI to inject @Stateless EJBs into my backing beans. Querying the database works fine, but when trying to persist entities the following exception is thrown:

javax.persistence.TransactionRequiredException: No active transaction for PuId=...

The application is packaged in an EAR that contains four modules (EAR setup):

  • A Utility Module containing JPA entities and EJBs for interacting with the database
  • A Utility Module containing Primefaces 5.2
  • A JAX-RS web service using the DB Utility Module
  • A JSF web application using the DB Utility Module

Transactions work fine in the web service module or when combining database classes and web application into a single module (I'd really like to avoid that though).

I've tried to apply some of the solutions presented in answers posted to similar questions, but so far had no luck resolving the problem. Any help is much appreciated.

Thanks,
Karl

persistence.xml

<?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="hcms" transaction-type="JTA">
        <jta-data-source>jdbc/hcms</jta-data-source>
    </persistence-unit>
</persistence>

Example Snippet of EJB:

@Stateless
public class CommunityAddressDao extends Dao<CommunityAddressEntity, Integer> {
    @PersistenceContext(unitName="hcms")
    private EntityManager em;


    public CommunityAddressDao() {
        super(CommunityAddressEntity.class);
    }


    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    ...

}

Working example from web service:

@Stateless
@Path("/addresses")
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed({"user"})
    public class CommunityAddressService {  
    @Inject
    private CommunityAddressDao addressDao;

    ...

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public CommunityAddressDto registerAddress(CommunityAddressDto address) throws DuplicateAddressException, ManagedAddressException, BadRequestException {
        // Validation

        CommunityAddressEntity entity = new CommunityAddressEntity();
        entity.setCommunityUuid(address.getCommunityUuid());
        ...

        addressDao.persist(entity);

        return new CommunityAddressDto(entity);
    }
}

Problematic example from web application:

@ViewScoped
@Named("addressBean")
public class CommunityAddressBean implements Serializable {
     private static final long serialVersionUID = -1685666287294618708L;

    @Inject
    private CommunityAddressDao addressDao;

    private List<CommunityAddressEntity> addresses;

    ...

    @PostConstruct
    private void init() {
        // Retrieve first 10 addresses - Works fine
        addresses = addressDao.findAll(10, 0);
    }

    public void createAddress(ActionEvent event) {
        CommunityAddressEntity entity = new CommunityAddressEntity();
        entity.setCommunityUuid("some UUID");
        ...

        // Throws javax.persistence.TransactionRequiredException: No active transaction for PuId=...
        addressDao.persist(entity);
    }
}

Update (2016-11-02)

All the EJBs used for interacting with the database inherit from an abstract class that provides basic CRUD functionality.

abstract DAO base class:

public abstract class Dao<E, K> {   
    protected Class<E> entityClass; 


    public Dao(Class<E> type) {
        entityClass = type;
    }

    protected abstract EntityManager getEntityManager();
    protected abstract String[] getFilterAttributes();

    ...

    public void persist(E entity) {
        getEntityManager().persist(entity);
    }
    public void merge(E entity) {
        getEntityManager().merge(entity);
    }
    public void remove(E entity) {
        getEntityManager().remove(entity);
    }
    public E findById(K id) {
        return getEntityManager().find(entityClass, id);
    }
}

Full stack trace:

[err] javax.persistence.TransactionRequiredException: No active transaction for PuId=hcms#de.holistic.hcms.admin.war#hcms
[err]   at com.ibm.ws.jpa.management.JPATxEntityManager.getEMInvocationInfo(JPATxEntityManager.java:230)
[err]   at [internal classes]
[err]   at de.holistic.hcms.data.Dao.persist(Dao.java:84)
[err]   at de.holistic.hcms.admin.beans.CommunityAddressBean.createAddress(CommunityAddressBean.java:38)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err]   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:88)
[err]   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
[err]   at java.lang.reflect.Method.invoke(Method.java:618)
[err]   at org.apache.el.parser.AstValue.invoke(AstValue.java:268)
[err]   at [internal classes]
[err]   at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:78)
[err]   at javax.faces.event.ActionEvent.processListener(ActionEvent.java:51)
[err]   at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:404)
[err]   at javax.faces.component.UICommand.broadcast(UICommand.java:103)
[err]   at javax.faces.component.UIData.broadcast(UIData.java:772)
[err]   at javax.faces.component.UIViewRoot._broadcastAll(UIViewRoot.java:993)
[err]   at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:276)
[err]   at javax.faces.component.UIViewRoot._process(UIViewRoot.java:1305)
[err]   at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:731)
[err]   at org.apache.myfaces.lifecycle.InvokeApplicationExecutor.execute(InvokeApplicationExecutor.java:34)
[err]   at [internal classes]
[err]   at javax.faces.webapp.FacesServlet.service(FacesServlet.java:189)
[err]   at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1287)
[err]   at [internal classes]
[err]   at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:226)
[err]   at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
[err]   at [internal classes]
[err]   at org.ocpsoft.rewrite.servlet.impl.HttpRewriteResultHandler.handleResult(HttpRewriteResultHandler.java:42)
[err]   at org.ocpsoft.rewrite.servlet.RewriteFilter.rewrite(RewriteFilter.java:297)
[err]   at org.ocpsoft.rewrite.servlet.RewriteFilter.doFilter(RewriteFilter.java:198)
[err]   at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
[err]   at [internal classes]
[err]   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156)
[err]   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:626)
[err]   at java.lang.Thread.run(Thread.java:804)

Update 2 (2016-11-02)

Using @EJB instead of @Inject results in an com.ibm.ejs.container.EJBNotFoundException:

CWNEN0030E: The server was unable to obtain an object instance for the java:comp/env/de.holistic.hcms.admin.beans.CommunityAddressBean/addressDao reference.  The exception message was: The EJB reference in the de.holistic.hcms.admin.war module of the hcms application could not be resolved; nested exception is: com.ibm.ejs.container.EJBNotFoundException: EJB with interface de.holistic.hcms.data.CommunityAddressDao not present in application hcms.
[ERROR   ] An error occurred while executing [@PostConstruct.]
java.lang.NullPointerException
[ERROR   ] Error Rendering View[/addresses.xhtml]
java.lang.NullPointerException
[ERROR   ] An exception occurred
java.lang.NullPointerException

So the server is looking for the EJB in the wrong module. I tried using the @EJB annotiation's attributes (lookup, name, etc) to correctly specify my EJB, but had no luck so far. I will do some reading up on this since I'm not very familiar with this topic.

Still, I'm wondering why CDI + transcations are working in the web service but not the web application. :-\


Solution

  • As @Gas mentioned in the comments, it turned out to be a problem with the classpath / the setup of the EAR.

    I was able to get it working with both @EJB and @Inject by:

    1. Converting the DB utility module to an EJB module (Project Facets)
    2. Referencing the EJB Module as such in the EAR's application.xml file (EAR setup)

      application.xml:

      <?xml version="1.0" encoding="UTF-8"?>
      <application xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd" version="6">
          <application-name>hcms</application-name>
          <module id="Module_1473757101927">
              <web>
                  <web-uri>de.holistic.hcms.web.service.war</web-uri>
                  <context-root>hcms</context-root>
              </web>
          </module>
          <module id="Module_1476173932514">
              <web>
                  <web-uri>de.holistic.hcms.admin.war</web-uri>
                  <context-root>hcms/admin</context-root>
              </web>
          </module>
          <module id="Module_1478169092726">
              <ejb>de.holistic.hcms.data.jar</ejb>
          </module>
      
      </application>
      
    3. And referencing the module in the manifest of my WARs

      MANIFEST.MF:

      Manifest-Version: 1.0
      Class-Path: de.holistic.hcms.data.jar