Skip to main content

Using WS-AtomicTransactions from a standalone java client

No replies
JFK9
Offline
Joined: 2011-03-30
Points: 0

Is it possible to to control the transaction boundary from a standalone java (7) client when calling a web service in glassfish (4.0) which is implemented to participate in WS-AtomicTransaction.

The webservice is defined as follows;

@WebService
@Stateless
@Transactional(value = Transactional.TransactionFlowType.SUPPORTS,
version = com.sun.xml.ws.api.tx.at.Transactional.Version.WSAT10)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Bean1 {

@Resource(mappedName = "java:appserver/TransactionManager")
private TransactionManager txManager;
    /**
     * Default constructor.
     */
    public Bean1() {
        // TODO Auto-generated constructor stub
    }
   
    private static String getTxStatus(int status)
    {
    switch(status)
    {
    case Status.STATUS_ACTIVE:
    return "Active";
    case Status.STATUS_COMMITTED:
    return "Committed";
    case Status.STATUS_COMMITTING:
    return "Committing";
    case Status.STATUS_MARKED_ROLLBACK:
    return "Marked for rollback";
    case Status.STATUS_NO_TRANSACTION:
    return "No Transaction";
    case Status.STATUS_PREPARED:
    return "Prepared";
    case Status.STATUS_PREPARING:
    return "Preparing";
    case Status.STATUS_ROLLEDBACK:
    return "Rolledback";
    case Status.STATUS_ROLLING_BACK:
    return "Rollingback";
    case Status.STATUS_UNKNOWN:
    return "Status set to STATUS_UNKNOWN";
    }
    return "Unknown Status " + status;
    }
   
    private String getTxName()
    {
    try {
if(txManager==null)
{
return "No Transaction Manager";
}
else
{
if(txManager.getTransaction() == null)
{
return "No Transaction";
}
else
{
return "A Transaction: status=" + getTxStatus(txManager.getTransaction().getStatus()) + ". {Transaction: " + txManager.getTransaction() +"}";
}
}
} catch (SystemException e) {
return "Error getting TxName: " + e;
}
    }

    @WebMethod
    public String hello(String tag)
    {
    return tag + " you!" + getTxName();
    }
}

The client code uses the wsimport generated client stubs;

Bean1 proxy = new Bean1Service().getBean1Port();
System.out.println(proxy.hello("Hello"));

This works fine as is.
But suppose I wish to control the transaction from the java client in a manner similar to that described in the metro tutorial chap 18; Is there anyway that can work? I am quite happy to use the TransactionManager from the local glassfish to provide the UserTransaction and coordinate, but I would need the transaction to 'flow back in' on the web method and be externally controllable...

import java.rmi.RemoteException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.junit.Test;

import uk.co.his.ejbproject1.Bean1;
import uk.co.his.ejbproject1.Bean1Service;

import com.sun.xml.ws.api.tx.at.Transactional.TransactionFlowType;
import com.sun.xml.ws.api.tx.at.Transactional.Version;
import com.sun.xml.ws.api.tx.at.TransactionalFeature;

public class TestClient {

@Test
public void test() throws RemoteException, NamingException,
SecurityException, IllegalStateException, RollbackException,
HeuristicMixedException, HeuristicRollbackException,
SystemException, NotSupportedException {

UserTransaction utx = null;

try {
InitialContext ctx = new InitialContext();
utx = (UserTransaction) ctx.lookup("javax.transaction"
+ ".UserTransaction");
utx.setTransactionTimeout(900);
} catch (java.lang.Exception e) {
e.printStackTrace();
}

TransactionalFeature feature = new TransactionalFeature();
feature.setFlowType(TransactionFlowType.MANDATORY);
feature.setVersion(Version.WSAT10);

Bean1 proxy = new Bean1Service().getBean1Port();

utx.begin();
System.out.println(proxy.hello("Hello"));
utx.commit();
}

}

It would seem this is never possible because the Metro runtimes are looking for a local transaction manager which includes transaction log file directory information.

So when I run with the following container setup...

	@Test
public void test3() throws Exception, UserError
{
TargetServer server = new TargetServer("localhost", 4848);
TargetServer[] servers = { server };
// Get a builder to set up the ACC
AppClientContainer.Builder builder = AppClientContainer.newBuilder(servers);
AppClientContainer acc = builder.newContainer(TestClient.class);
acc.startClient(new String[0]);
}


public static void main(String[] args) throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException
{
UserTransaction utx = null;
try {
    InitialContext ctx = new InitialContext();
   
    utx = (UserTransaction)ctx.lookup("java:comp/UserTransaction");
        utx.setTransactionTimeout(900);

       

      
    } catch (java.lang.Exception e) {
        e.printStackTrace();
    }
   
TransactionalFeature feature = new TransactionalFeature();
        feature.setFlowType(TransactionFlowType.MANDATORY);
        feature.setVersion(Version.WSAT10);


Bean1 proxy = new Bean1Service().getBean1Port(feature);

        utx.begin();
/*System.out.println(proxy.hello("Hello"));
ComplexData1 data = new ComplexData1();
data.setName("Fred");
data.getChildData().addAll(createComplexData2(10));
printOutComplexData("before", data);
ComplexData1 result = proxy.processData(data, "World!");
data.setName("No longer Fred");
printOutComplexData("after", result);*/
utx.commit();
        System.out.println("Dones");
}

I get the following;
Jul 08, 2013 7:12:23 PM [com.sun.xml.ws.tx.at.common.TransactionImportManager]  <init>
INFO: Missing required extension methods detected on 'javax.transaction.TransactionManager' implementation 'com.sun.enterprise.transaction.TransactionManagerHelper':
getTxLogLocation

Jul 08, 2013 7:12:27 PM [com.sun.xml.ws.tx.at.internal.WSATGatewayRM]  setTxLogDirs
INFO: txlogdir isnull

The com.sun.enterprise.transaction.TransactionManagerHelper is a wrapper around the JNDI lookup for java:appserver/TransactionManager which presumably could be local or remote and might or might not (NOT in the case of a 'standalone' client) have access to the tx logging dirs...
thanks