You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@olingo.apache.org by "Enrique Rodriguez (JIRA)" <ji...@apache.org> on 2016/08/04 11:49:20 UTC

[jira] [Commented] (OLINGO-976) Problem with JTA transactions

    [ https://issues.apache.org/jira/browse/OLINGO-976?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15407609#comment-15407609 ] 

Enrique Rodriguez commented on OLINGO-976:
------------------------------------------

Hi Michael, Alex,

I agree with Alex, and i'm working with olingo using JTA with Bean Managed Transaction on a javaee 6 application server (Websphere 8.5)

First of all, I use CDI to inject dependecies (EntityManager, EntityManagerFactory ans UserTransaction). To do it we need to give the control to the container from the servlet, so I extend ODataServlet to inject the ODataJPAServiceFactory overriding getServiceFactory method

@WebServlet("/OData.svc/*")
public class JtaODataServlet extends ODataServlet{
	
	public JtaODataServlet() {
		super();
	}
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 7405803151288216396L;
	
	@javax.inject.Inject
	private JpaInjectedServiceFactory serviceFactory;
	
	 /**
	   * Get the service factory instance which is used for creation of the
	   * <code>ODataService</code> which handles the processing of the request.
	   * 
	   *
	   * @param request the http request which is processed as an OData request
	   * @return an instance of an ODataServiceFactory
	   */
	  protected ODataServiceFactory getServiceFactory(HttpServletRequest request) {
		  return (ODataJPAServiceFactory)serviceFactory;
	  }

}

The JpaInjectedServiceFactory load all resources it need from container. In also need to modify oDataJpaContext and oDataJpaContextImpl to store userTransaction and TransactionSynchronizationRegistry 

public class JpaInjectedServiceFactory extends ODataJPAServiceFactory {
	public static final String DEFAULT_ENTITY_UNIT_NAME = "Model";

	@PersistenceContext//(unitName = "Model")
	private EntityManager entityManager;
	
	@PersistenceUnit
	private EntityManagerFactory emf;
	
	@Resource 
	UserTransaction userTran;
	
	@Resource
	TransactionSynchronizationRegistry tsr;
	
    public JpaInjectedServiceFactory() {}

	@Override
	public ODataJPAContext initializeODataJPAContext() throws ODataJPARuntimeException {
		ODataJPAContext oDataJPAContext = getODataJPAContext();
		
		//Context ctx;
		try {
		//	ctx = new InitialContext();
		
			
	        // Now get the EntityManager from JNDI
			oDataJPAContext.setEntityManagerFactory(emf);
			oDataJPAContext.setEntityManager(entityManager);
			oDataJPAContext.setPersistenceUnitName(DEFAULT_ENTITY_UNIT_NAME);
			oDataJPAContext.setContainerManaged(true);
			oDataJPAContext.setUserTransaction(userTran, tsr);
			
			return oDataJPAContext;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}
}


OdataJPAContextImpl now manage to create the transaction it needs, ( i think that using callback for this configuration is very complex for most of people.)


  @Override
  public ODataJPATransaction getODataJPATransaction() {
	  if (transaction == null) {
	      transaction = odataContext.getServiceFactory().getCallback(ODataJPATransaction.class);
	      if (transaction == null) {
		      if (containerManaged){
				  transaction = new ODataJPATransactionBeanManaged(userTran, tsr);
			  }else{
		        transaction = new ODataJPATransactionLocalDefault(getEntityManager());
		      }
	      }
	  }
    return transaction;
  }

Finallly ODataJPATransactionBeanManaged control the JTA transaction similar as Local transaction.


public class ODataJPATransactionBeanManaged implements ODataJPATransaction {
	  
  private UserTransaction userTran;
  private TransactionSynchronizationRegistry tsr;
  public ODataJPATransactionBeanManaged(UserTransaction userTran,TransactionSynchronizationRegistry tsr) {
	  this.userTran = userTran;
	  this.tsr = tsr;
	  
  }

    @Override
    public void begin() {
	  	try {
	  		userTran.begin();
	  	} catch (Exception e) {
	  		throw new RuntimeException("error begin transaction", e);
	    }
    }

    @Override
    public void commit() {
  	  	try {
  	  		userTran.commit();
	  	} catch (Exception e) {
	  		throw new RuntimeException("error begin transaction", e);
	    }
    }

    @Override
    public void rollback() {
    	try{    	
    		userTran.rollback();
	    } catch (Exception e) {
	  		throw new RuntimeException("error rollback transaction", e);
	    }
      /** do nothing for CMP */
    }

    @Override
    public boolean isActive() {
    	if (tsr.getTransactionStatus()==Status.STATUS_ACTIVE ){
    		return true;
    	}else {
    		return false;
    	}
    }
}

I made more changes to code to make olingo run with websphere 8.5 using Apache OpenJPA.... but this is for other post.

I hope this comments help, i spend a lot of time making it work.

Enrique.

> Problem with JTA transactions
> -----------------------------
>
>                 Key: OLINGO-976
>                 URL: https://issues.apache.org/jira/browse/OLINGO-976
>             Project: Olingo
>          Issue Type: Bug
>          Components: odata2-jpa
>    Affects Versions: V2 2.0.7
>         Environment: neo-javaee6-wp-sdk (SAP HANA cloud)
>            Reporter: Alex Key
>            Assignee: Michael Bolz
>             Fix For: V2 2.0.7
>
>
> There are still problems with JTA transaction after fixing OLINGO-882.
> At the moment IllegalStateException is thrown by ODataJPATransactionLocalDefault constructor, which has em.getTransaction() call.
> Here's stacktrace:
> {code}
> java.lang.IllegalStateException: A JTA EntityManager can not use the EntityTransaction API.  See JPA 1.0 section 5.5
> 	at org.apache.openejb.persistence.JtaEntityManager.getTransaction(JtaEntityManager.java:349)
> 	at org.apache.olingo.odata2.jpa.processor.core.ODataJPATransactionLocalDefault.<init>(ODataJPATransactionLocalDefault.java:31)
> 	at org.apache.olingo.odata2.jpa.processor.core.ODataJPAContextImpl.getODataJPATransaction(ODataJPAContextImpl.java:178)
> 	at org.apache.olingo.odata2.jpa.processor.core.access.data.JPAProcessorImpl.setTransaction(JPAProcessorImpl.java:451)
> 	at org.apache.olingo.odata2.jpa.processor.core.access.data.JPAProcessorImpl.processCreate(JPAProcessorImpl.java:335)
> 	at org.apache.olingo.odata2.jpa.processor.core.access.data.JPAProcessorImpl.process(JPAProcessorImpl.java:223)
> 	at org.apache.olingo.odata2.jpa.processor.core.ODataJPAProcessorDefault.createEntity(ODataJPAProcessorDefault.java:122)
> 	at org.apache.olingo.odata2.core.Dispatcher.dispatch(Dispatcher.java:79)
> 	at org.apache.olingo.odata2.core.ODataRequestHandler.handle(ODataRequestHandler.java:130)
> 	at org.apache.olingo.odata2.core.rest.ODataSubLocator.handle(ODataSubLocator.java:164)
> 	at org.apache.olingo.odata2.core.rest.ODataSubLocator.handlePost(ODataSubLocator.java:86)
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)