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