Rename transaction package
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 22 Jun 2022 05:07:49 +0000 (07:07 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 22 Jun 2022 05:07:49 +0000 (07:07 +0200)
32 files changed:
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UiAdminUtils.java
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java
eclipse/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserBatchUpdateWizard.java
jcr/org.argeo.cms.jcr/src/org/argeo/maintenance/AbstractMaintenanceService.java
jcr/org.argeo.cms.jcr/src/org/argeo/maintenance/SimpleRoleRegistration.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java
org.argeo.cms/src/org/argeo/cms/runtime/StaticCms.java
org.argeo.util/src/org/argeo/osgi/transaction/JtaStatusAdapter.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/SimpleRollbackException.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransaction.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransactionManager.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/UuidXid.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/WorkContext.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/WorkControl.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/WorkTransaction.java [deleted file]
org.argeo.util/src/org/argeo/osgi/transaction/package-info.java [deleted file]
org.argeo.util/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java
org.argeo.util/src/org/argeo/osgi/useradmin/UserDirectory.java
org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/UuidXid.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/WorkContext.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/WorkControl.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java [new file with mode: 0644]
org.argeo.util/src/org/argeo/util/transaction/package-info.java [new file with mode: 0644]

index 0ecd0a155dbe4051de15c0814c9c0d893a887f84..a6cdcf620af3e25f94376c11c5524c58405d37bf 100644 (file)
@@ -17,7 +17,7 @@ import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.security.CryptoKeyring;
 import org.argeo.cms.swt.dialogs.CmsMessageDialog;
 import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
-import org.argeo.osgi.transaction.WorkTransaction;
+import org.argeo.util.transaction.WorkTransaction;
 import org.eclipse.e4.core.di.annotations.Execute;
 import org.eclipse.e4.core.di.annotations.Optional;
 import org.eclipse.jface.dialogs.Dialog;
index a011c5f62c19c45fcdeca8ce4644ed732fe539f6..d54f8bc388803ba40c4aa10eab33256aea48fcfa 100644 (file)
@@ -32,8 +32,8 @@ import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.argeo.eclipse.ui.parts.LdifUsersTable;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.transaction.WorkTransaction;
 import org.eclipse.e4.ui.workbench.modeling.EPartService;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.ToolBarManager;
index f856492601cf26a9fa8bc64f1412f2bc7240e8ce..fb48a47c3a42cc305f1f18397980271995e1dd0f 100644 (file)
@@ -1,6 +1,6 @@
 package org.argeo.cms.e4.users;
 
-import org.argeo.osgi.transaction.WorkTransaction;
+import org.argeo.util.transaction.WorkTransaction;
 
 /** First effort to centralize back end methods used by the user admin UI */
 public class UiAdminUtils {
index 934b880cd106da27dec592f9ec86fd822512489f..cd8d4d7dc79e949a0f0a3e8704fb89adee195c46 100644 (file)
@@ -10,9 +10,9 @@ import java.util.Map;
 
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.cms.CmsException;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.service.useradmin.UserAdmin;
 import org.osgi.service.useradmin.UserAdminEvent;
 import org.osgi.service.useradmin.UserAdminListener;
index a38d171ef70f67b86d7d6e0dff8eab13abc8bad4..01ccc7d73221d7732f4ccf26bb106ec9067ce36f 100644 (file)
@@ -17,9 +17,9 @@ import org.argeo.cms.e4.users.providers.UserNameLP;
 import org.argeo.eclipse.ui.ColumnDefinition;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.argeo.eclipse.ui.parts.LdifUsersTable;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.util.naming.LdapAttrs;
 import org.argeo.util.naming.LdapObjs;
+import org.argeo.util.transaction.WorkTransaction;
 import org.eclipse.jface.dialogs.IPageChangeProvider;
 import org.eclipse.jface.dialogs.IPageChangedListener;
 import org.eclipse.jface.dialogs.MessageDialog;
index 3c8f296c4c9243b9b9a0ce7ebfe297744b669ffd..8e2ac896080ece0c9b4e37cdde3fa8b6e09a0112 100644 (file)
@@ -14,8 +14,8 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.jcr.CmsJcrUtils;
 import org.argeo.jcr.Jcr;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.util.naming.Distinguished;
+import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.service.useradmin.Group;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.UserAdmin;
index ebb8c534da0e125220216012cad35331430496f9..e65e46a4eb3b154df233426f2377dd94a8f5a29e 100644 (file)
@@ -8,7 +8,7 @@ import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 
 import org.argeo.api.cms.CmsLog;
-import org.argeo.osgi.transaction.WorkTransaction;
+import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.UserAdmin;
 
index e69cda64459ac05058058b2a96d9ab317da149ae..9b7a2ed423c1331bcf7c8d05dcd0fb0a03fe923c 100644 (file)
@@ -31,13 +31,13 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.CmsUserManager;
 import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.auth.UserAdminUtils;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.osgi.useradmin.TokenUtils;
 import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.osgi.useradmin.UserDirectory;
 import org.argeo.util.naming.LdapAttrs;
 import org.argeo.util.naming.NamingUtils;
 import org.argeo.util.naming.SharedSecret;
+import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Group;
index 10cb98dd342bd2d3a05025ced87ad1d864840a6d..965330237c6e7226ac19f0d6db79136ad74bf2da 100644 (file)
@@ -33,8 +33,6 @@ import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.cms.internal.http.client.HttpCredentialProvider;
 import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
-import org.argeo.osgi.transaction.WorkControl;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.osgi.useradmin.AggregatingUserAdmin;
 import org.argeo.osgi.useradmin.LdapUserAdmin;
 import org.argeo.osgi.useradmin.LdifUserAdmin;
@@ -42,6 +40,8 @@ import org.argeo.osgi.useradmin.OsUserDirectory;
 import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.osgi.useradmin.UserDirectory;
 import org.argeo.util.naming.dns.DnsBrowser;
+import org.argeo.util.transaction.WorkControl;
+import org.argeo.util.transaction.WorkTransaction;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
index a44c5d4fdade72c495ed52e430ae033716ffbf1c..a1b8c54010b89828b9d72244a91dcdd96d39b6ad 100644 (file)
@@ -21,12 +21,12 @@ import org.argeo.cms.internal.runtime.CmsDeploymentImpl;
 import org.argeo.cms.internal.runtime.CmsStateImpl;
 import org.argeo.cms.internal.runtime.CmsUserAdmin;
 import org.argeo.cms.internal.runtime.DeployedContentRepository;
-import org.argeo.osgi.transaction.SimpleTransactionManager;
-import org.argeo.osgi.transaction.WorkControl;
-import org.argeo.osgi.transaction.WorkTransaction;
 import org.argeo.osgi.useradmin.UserDirectory;
 import org.argeo.util.register.Component;
 import org.argeo.util.register.SimpleRegister;
+import org.argeo.util.transaction.SimpleTransactionManager;
+import org.argeo.util.transaction.WorkControl;
+import org.argeo.util.transaction.WorkTransaction;
 import org.osgi.service.useradmin.UserAdmin;
 
 /**
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/JtaStatusAdapter.java b/org.argeo.util/src/org/argeo/osgi/transaction/JtaStatusAdapter.java
deleted file mode 100644 (file)
index 2dd94c6..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-package org.argeo.osgi.transaction;
-
-/** JTA transaction status. */
-public class JtaStatusAdapter implements TransactionStatusAdapter<Integer> {
-       private static final Integer STATUS_ACTIVE = 0;
-       private static final Integer STATUS_COMMITTED = 3;
-       private static final Integer STATUS_COMMITTING = 8;
-       private static final Integer STATUS_MARKED_ROLLBACK = 1;
-       private static final Integer STATUS_NO_TRANSACTION = 6;
-       private static final Integer STATUS_PREPARED = 2;
-       private static final Integer STATUS_PREPARING = 7;
-       private static final Integer STATUS_ROLLEDBACK = 4;
-       private static final Integer STATUS_ROLLING_BACK = 9;
-//     private static final Integer STATUS_UNKNOWN = 5;
-
-       @Override
-       public Integer getActiveStatus() {
-               return STATUS_ACTIVE;
-       }
-
-       @Override
-       public Integer getPreparingStatus() {
-               return STATUS_PREPARING;
-       }
-
-       @Override
-       public Integer getMarkedRollbackStatus() {
-               return STATUS_MARKED_ROLLBACK;
-       }
-
-       @Override
-       public Integer getPreparedStatus() {
-               return STATUS_PREPARED;
-       }
-
-       @Override
-       public Integer getCommittingStatus() {
-               return STATUS_COMMITTING;
-       }
-
-       @Override
-       public Integer getCommittedStatus() {
-               return STATUS_COMMITTED;
-       }
-
-       @Override
-       public Integer getRollingBackStatus() {
-               return STATUS_ROLLING_BACK;
-       }
-
-       @Override
-       public Integer getRolledBackStatus() {
-               return STATUS_ROLLEDBACK;
-       }
-
-       @Override
-       public Integer getNoTransactionStatus() {
-               return STATUS_NO_TRANSACTION;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/SimpleRollbackException.java b/org.argeo.util/src/org/argeo/osgi/transaction/SimpleRollbackException.java
deleted file mode 100644 (file)
index cf8a80b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.osgi.transaction;
-
-/** Internal unchecked rollback exception. */
-class SimpleRollbackException extends RuntimeException {
-       private static final long serialVersionUID = 8055601819719780566L;
-
-       public SimpleRollbackException() {
-               super();
-       }
-
-       public SimpleRollbackException(Throwable cause) {
-               super(cause);
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransaction.java b/org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransaction.java
deleted file mode 100644 (file)
index e668b31..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.argeo.osgi.transaction;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.Xid;
-
-/** Simple implementation of an XA transaction. */
-class SimpleTransaction<T>
-//implements Transaction, Status 
-{
-       private final Xid xid;
-       private T status;
-       private final List<XAResource> xaResources = new ArrayList<XAResource>();
-
-       private final SimpleTransactionManager transactionManager;
-       private TransactionStatusAdapter<T> tsa;
-
-       public SimpleTransaction(SimpleTransactionManager transactionManager, TransactionStatusAdapter<T> tsa) {
-               this.tsa = tsa;
-               this.status = tsa.getActiveStatus();
-               this.xid = new UuidXid();
-               this.transactionManager = transactionManager;
-       }
-
-       public synchronized void commit()
-//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
-//                     SecurityException, IllegalStateException, SystemException 
-       {
-               status = tsa.getPreparingStatus();
-               for (XAResource xaRes : xaResources) {
-                       if (status.equals(tsa.getMarkedRollbackStatus()))
-                               break;
-                       try {
-                               xaRes.prepare(xid);
-                       } catch (XAException e) {
-                               status = tsa.getMarkedRollbackStatus();
-                               error("Cannot prepare " + xaRes + " for " + xid, e);
-                       }
-               }
-               if (status.equals(tsa.getMarkedRollbackStatus())) {
-                       rollback();
-                       throw new SimpleRollbackException();
-               }
-               status = tsa.getPreparedStatus();
-
-               status = tsa.getCommittingStatus();
-               for (XAResource xaRes : xaResources) {
-                       if (status.equals(tsa.getMarkedRollbackStatus()))
-                               break;
-                       try {
-                               xaRes.commit(xid, false);
-                       } catch (XAException e) {
-                               status = tsa.getMarkedRollbackStatus();
-                               error("Cannot prepare " + xaRes + " for " + xid, e);
-                       }
-               }
-               if (status.equals(tsa.getMarkedRollbackStatus())) {
-                       rollback();
-                       throw new SimpleRollbackException();
-               }
-
-               // complete
-               status = tsa.getCommittedStatus();
-               clearResources(XAResource.TMSUCCESS);
-               transactionManager.unregister(xid);
-       }
-
-       public synchronized void rollback()
-//                     throws IllegalStateException, SystemException 
-       {
-               status = tsa.getRollingBackStatus();
-               for (XAResource xaRes : xaResources) {
-                       try {
-                               xaRes.rollback(xid);
-                       } catch (XAException e) {
-                               error("Cannot rollback " + xaRes + " for " + xid, e);
-                       }
-               }
-
-               // complete
-               status = tsa.getRolledBackStatus();
-               clearResources(XAResource.TMFAIL);
-               transactionManager.unregister(xid);
-       }
-
-       public synchronized boolean enlistResource(XAResource xaRes)
-//                     throws RollbackException, IllegalStateException, SystemException 
-       {
-               if (xaResources.add(xaRes)) {
-                       try {
-                               xaRes.start(getXid(), XAResource.TMNOFLAGS);
-                               return true;
-                       } catch (XAException e) {
-                               error("Cannot enlist " + xaRes, e);
-                               return false;
-                       }
-               } else
-                       return false;
-       }
-
-       public synchronized boolean delistResource(XAResource xaRes, int flag)
-//                     throws IllegalStateException, SystemException 
-       {
-               if (xaResources.remove(xaRes)) {
-                       try {
-                               xaRes.end(getXid(), flag);
-                       } catch (XAException e) {
-                               error("Cannot delist " + xaRes, e);
-                               return false;
-                       }
-                       return true;
-               } else
-                       return false;
-       }
-
-       protected void clearResources(int flag) {
-               for (XAResource xaRes : xaResources)
-                       try {
-                               xaRes.end(getXid(), flag);
-                       } catch (XAException e) {
-                               error("Cannot end " + xaRes, e);
-                       }
-               xaResources.clear();
-       }
-
-       protected void error(Object obj, Exception e) {
-               System.err.println(obj);
-               e.printStackTrace();
-       }
-
-       public synchronized T getStatus()
-//                     throws SystemException 
-       {
-               return status;
-       }
-
-//     public void registerSynchronization(Synchronization sync)
-//                     throws RollbackException, IllegalStateException, SystemException {
-//             throw new UnsupportedOperationException();
-//     }
-
-       public void setRollbackOnly()
-//                     throws IllegalStateException, SystemException 
-       {
-               status = tsa.getMarkedRollbackStatus();
-       }
-
-       @Override
-       public int hashCode() {
-               return xid.hashCode();
-       }
-
-       Xid getXid() {
-               return xid;
-       }
-
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransactionManager.java b/org.argeo.util/src/org/argeo/osgi/transaction/SimpleTransactionManager.java
deleted file mode 100644 (file)
index 3d4edfd..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-package org.argeo.osgi.transaction;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.Xid;
-
-/**
- * Simple implementation of an XA transaction manager.
- */
-public class SimpleTransactionManager
-// implements TransactionManager, UserTransaction 
-               implements WorkControl, WorkTransaction {
-       private ThreadLocal<SimpleTransaction<Integer>> current = new ThreadLocal<SimpleTransaction<Integer>>();
-
-       private Map<Xid, SimpleTransaction<Integer>> knownTransactions = Collections
-                       .synchronizedMap(new HashMap<Xid, SimpleTransaction<Integer>>());
-       private TransactionStatusAdapter<Integer> tsa = new JtaStatusAdapter();
-//     private SyncRegistry syncRegistry = new SyncRegistry();
-
-       /*
-        * WORK IMPLEMENTATION
-        */
-       @Override
-       public <T> T required(Callable<T> work) {
-               T res;
-               begin();
-               try {
-                       res = work.call();
-                       commit();
-               } catch (Exception e) {
-                       rollback();
-                       throw new SimpleRollbackException(e);
-               }
-               return res;
-       }
-
-       @Override
-       public WorkContext getWorkContext() {
-               return new WorkContext() {
-
-                       @Override
-                       public void registerXAResource(XAResource resource, String recoveryId) {
-                               getTransaction().enlistResource(resource);
-                       }
-               };
-       }
-
-       /*
-        * WORK TRANSACTION IMPLEMENTATION
-        */
-
-       @Override
-       public boolean isNoTransactionStatus() {
-               return tsa.getNoTransactionStatus().equals(getStatus());
-       }
-
-       /*
-        * JTA IMPLEMENTATION
-        */
-
-       public void begin()
-//                     throws NotSupportedException, SystemException 
-       {
-               if (getCurrent() != null)
-                       throw new UnsupportedOperationException("Nested transactions are not supported");
-               SimpleTransaction<Integer> transaction = new SimpleTransaction<Integer>(this, tsa);
-               knownTransactions.put(transaction.getXid(), transaction);
-               current.set(transaction);
-       }
-
-       public void commit()
-//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
-//                     SecurityException, IllegalStateException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().commit();
-       }
-
-       public int getStatus()
-//                     throws SystemException
-       {
-               if (getCurrent() == null)
-                       return tsa.getNoTransactionStatus();
-               return getTransaction().getStatus();
-       }
-
-       public SimpleTransaction<Integer> getTransaction()
-//                     throws SystemException 
-       {
-               return getCurrent();
-       }
-
-       protected SimpleTransaction<Integer> getCurrent()
-//                     throws SystemException 
-       {
-               SimpleTransaction<Integer> transaction = current.get();
-               if (transaction == null)
-                       return null;
-               Integer status = transaction.getStatus();
-               if (status.equals(tsa.getCommittedStatus()) || status.equals(tsa.getRolledBackStatus())) {
-                       current.remove();
-                       return null;
-               }
-               return transaction;
-       }
-
-       void unregister(Xid xid) {
-               knownTransactions.remove(xid);
-       }
-
-       public void resume(SimpleTransaction<Integer> tobj)
-//                     throws InvalidTransactionException, IllegalStateException, SystemException 
-       {
-               if (getCurrent() != null)
-                       throw new IllegalStateException("Transaction " + current.get() + " already registered");
-               current.set(tobj);
-       }
-
-       public void rollback()
-//                     throws IllegalStateException, SecurityException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().rollback();
-       }
-
-       public void setRollbackOnly()
-//                     throws IllegalStateException, SystemException 
-       {
-               if (getCurrent() == null)
-                       throw new IllegalStateException("No transaction registered with the current thread.");
-               getCurrent().setRollbackOnly();
-       }
-
-       public void setTransactionTimeout(int seconds)
-//                     throws SystemException
-       {
-               throw new UnsupportedOperationException();
-       }
-
-       public SimpleTransaction<Integer> suspend()
-//                     throws SystemException
-       {
-               SimpleTransaction<Integer> transaction = getCurrent();
-               current.remove();
-               return transaction;
-       }
-
-//     public TransactionSynchronizationRegistry getTsr() {
-//             return syncRegistry;
-//     }
-//
-//     private class SyncRegistry implements TransactionSynchronizationRegistry {
-//             @Override
-//             public Object getTransactionKey() {
-//                     try {
-//                             SimpleTransaction transaction = getCurrent();
-//                             if (transaction == null)
-//                                     return null;
-//                             return getCurrent().getXid();
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get transaction key", e);
-//                     }
-//             }
-//
-//             @Override
-//             public void putResource(Object key, Object value) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public Object getResource(Object key) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public void registerInterposedSynchronization(Synchronization sync) {
-//                     throw new UnsupportedOperationException();
-//             }
-//
-//             @Override
-//             public int getTransactionStatus() {
-//                     try {
-//                             return getStatus();
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get status", e);
-//                     }
-//             }
-//
-//             @Override
-//             public boolean getRollbackOnly() {
-//                     try {
-//                             return getStatus() == Status.STATUS_MARKED_ROLLBACK;
-//                     } catch (SystemException e) {
-//                             throw new IllegalStateException("Cannot get status", e);
-//                     }
-//             }
-//
-//             @Override
-//             public void setRollbackOnly() {
-//                     try {
-//                             getCurrent().setRollbackOnly();
-//                     } catch (Exception e) {
-//                             throw new IllegalStateException("Cannot set rollback only", e);
-//                     }
-//             }
-//
-//     }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java b/org.argeo.util/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java
deleted file mode 100644 (file)
index 87abceb..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.argeo.osgi.transaction;
-
-/** Abstract the various approaches to represent transaction status. */
-public interface TransactionStatusAdapter<T> {
-       T getActiveStatus();
-
-       T getPreparingStatus();
-
-       T getMarkedRollbackStatus();
-
-       T getPreparedStatus();
-
-       T getCommittingStatus();
-
-       T getCommittedStatus();
-
-       T getRollingBackStatus();
-
-       T getRolledBackStatus();
-
-       T getNoTransactionStatus();
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/UuidXid.java b/org.argeo.util/src/org/argeo/osgi/transaction/UuidXid.java
deleted file mode 100644 (file)
index 729aef8..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.argeo.osgi.transaction;
-
-import java.io.Serializable;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-import java.util.UUID;
-
-import javax.transaction.xa.Xid;
-
-/**
- * Implementation of {@link Xid} based on {@link UUID}, using max significant
- * bits as global transaction id, and least significant bits as branch
- * qualifier.
- */
-public class UuidXid implements Xid, Serializable {
-       private static final long serialVersionUID = -5380531989917886819L;
-       public final static int FORMAT = (int) serialVersionUID;
-
-       private final static int BYTES_PER_LONG = Long.SIZE / Byte.SIZE;
-
-       private final int format;
-       private final byte[] globalTransactionId;
-       private final byte[] branchQualifier;
-       private final String uuid;
-       private final int hashCode;
-
-       public UuidXid() {
-               this(UUID.randomUUID());
-       }
-
-       public UuidXid(UUID uuid) {
-               this.format = FORMAT;
-               this.globalTransactionId = uuidToBytes(uuid.getMostSignificantBits());
-               this.branchQualifier = uuidToBytes(uuid.getLeastSignificantBits());
-               this.uuid = uuid.toString();
-               this.hashCode = uuid.hashCode();
-       }
-
-       public UuidXid(Xid xid) {
-               this(xid.getFormatId(), xid.getGlobalTransactionId(), xid
-                               .getBranchQualifier());
-       }
-
-       private UuidXid(int format, byte[] globalTransactionId,
-                       byte[] branchQualifier) {
-               this.format = format;
-               this.globalTransactionId = globalTransactionId;
-               this.branchQualifier = branchQualifier;
-               this.uuid = bytesToUUID(globalTransactionId, branchQualifier)
-                               .toString();
-               this.hashCode = uuid.hashCode();
-       }
-
-       @Override
-       public int getFormatId() {
-               return format;
-       }
-
-       @Override
-       public byte[] getGlobalTransactionId() {
-               return Arrays.copyOf(globalTransactionId, globalTransactionId.length);
-       }
-
-       @Override
-       public byte[] getBranchQualifier() {
-               return Arrays.copyOf(branchQualifier, branchQualifier.length);
-       }
-
-       @Override
-       public int hashCode() {
-               return hashCode;
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (this == obj)
-                       return true;
-               if (obj instanceof UuidXid) {
-                       UuidXid that = (UuidXid) obj;
-                       return Arrays.equals(globalTransactionId, that.globalTransactionId)
-                                       && Arrays.equals(branchQualifier, that.branchQualifier);
-               }
-               if (obj instanceof Xid) {
-                       Xid that = (Xid) obj;
-                       return Arrays.equals(globalTransactionId,
-                                       that.getGlobalTransactionId())
-                                       && Arrays
-                                                       .equals(branchQualifier, that.getBranchQualifier());
-               }
-               return uuid.equals(obj.toString());
-       }
-
-       @Override
-       protected Object clone() throws CloneNotSupportedException {
-               return new UuidXid(format, globalTransactionId, branchQualifier);
-       }
-
-       @Override
-       public String toString() {
-               return uuid;
-       }
-
-       public UUID asUuid() {
-               return bytesToUUID(globalTransactionId, branchQualifier);
-       }
-
-       public static byte[] uuidToBytes(long bits) {
-               ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_LONG);
-               buffer.putLong(0, bits);
-               return buffer.array();
-       }
-
-       public static UUID bytesToUUID(byte[] most, byte[] least) {
-               if (most.length < BYTES_PER_LONG)
-                       most = Arrays.copyOf(most, BYTES_PER_LONG);
-               if (least.length < BYTES_PER_LONG)
-                       least = Arrays.copyOf(least, BYTES_PER_LONG);
-               ByteBuffer buffer = ByteBuffer.allocate(2 * BYTES_PER_LONG);
-               buffer.put(most, 0, BYTES_PER_LONG);
-               buffer.put(least, 0, BYTES_PER_LONG);
-               buffer.flip();
-               return new UUID(buffer.getLong(), buffer.getLong());
-       }
-
-       // public static void main(String[] args) {
-       // UUID uuid = UUID.randomUUID();
-       // System.out.println(uuid);
-       // uuid = bytesToUUID(uuidToBytes(uuid.getMostSignificantBits()),
-       // uuidToBytes(uuid.getLeastSignificantBits()));
-       // System.out.println(uuid);
-       // }
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/WorkContext.java b/org.argeo.util/src/org/argeo/osgi/transaction/WorkContext.java
deleted file mode 100644 (file)
index f50f208..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.argeo.osgi.transaction;
-
-import javax.transaction.xa.XAResource;
-
-/**
- * A minimalistic interface similar to OSGi transaction context in order to
- * register XA resources.
- */
-public interface WorkContext {
-       void registerXAResource(XAResource resource, String recoveryId);
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/WorkControl.java b/org.argeo.util/src/org/argeo/osgi/transaction/WorkControl.java
deleted file mode 100644 (file)
index 7668095..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.osgi.transaction;
-
-import java.util.concurrent.Callable;
-
-/**
- * A minimalistic interface inspired by OSGi transaction control in order to
- * commit units of work externally.
- */
-public interface WorkControl {
-       <T> T required(Callable<T> work);
-
-       void setRollbackOnly();
-
-       WorkContext getWorkContext();
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/WorkTransaction.java b/org.argeo.util/src/org/argeo/osgi/transaction/WorkTransaction.java
deleted file mode 100644 (file)
index 6533909..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.argeo.osgi.transaction;
-
-/**
- * A minimalistic interface inspired by JTA user transaction in order to commit
- * units of work externally.
- */
-public interface WorkTransaction {
-       void begin();
-
-       void commit();
-
-       void rollback();
-
-       boolean isNoTransactionStatus();
-}
diff --git a/org.argeo.util/src/org/argeo/osgi/transaction/package-info.java b/org.argeo.util/src/org/argeo/osgi/transaction/package-info.java
deleted file mode 100644 (file)
index 3d37562..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Minimalistic and partial XA transaction manager implementation. */
-package org.argeo.osgi.transaction;
\ No newline at end of file
index dde39e0abd287fa0ddcb3f69cf6927574f1c26c0..e5576b91d31e3c1b44a3f76986137a007f057c09 100644 (file)
@@ -31,9 +31,9 @@ import javax.naming.directory.BasicAttributes;
 import javax.naming.ldap.LdapName;
 import javax.naming.ldap.Rdn;
 
-import org.argeo.osgi.transaction.WorkControl;
 import org.argeo.util.naming.LdapAttrs;
 import org.argeo.util.naming.LdapObjs;
+import org.argeo.util.transaction.WorkControl;
 import org.osgi.framework.Filter;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
index 18bb1a0a6eb6987e08c11c34633362f8aa2e7e57..2c070d66d53a720561eade2f854f6ed83aa54230 100644 (file)
@@ -2,7 +2,7 @@ package org.argeo.osgi.useradmin;
 
 import java.util.Optional;
 
-import org.argeo.osgi.transaction.WorkControl;
+import org.argeo.util.transaction.WorkControl;
 import org.osgi.service.useradmin.Role;
 
 /** Information about a user directory. */
diff --git a/org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java b/org.argeo.util/src/org/argeo/util/transaction/JtaStatusAdapter.java
new file mode 100644 (file)
index 0000000..bd97706
--- /dev/null
@@ -0,0 +1,61 @@
+package org.argeo.util.transaction;
+
+/** JTA transaction status. */
+public class JtaStatusAdapter implements TransactionStatusAdapter<Integer> {
+       private static final Integer STATUS_ACTIVE = 0;
+       private static final Integer STATUS_COMMITTED = 3;
+       private static final Integer STATUS_COMMITTING = 8;
+       private static final Integer STATUS_MARKED_ROLLBACK = 1;
+       private static final Integer STATUS_NO_TRANSACTION = 6;
+       private static final Integer STATUS_PREPARED = 2;
+       private static final Integer STATUS_PREPARING = 7;
+       private static final Integer STATUS_ROLLEDBACK = 4;
+       private static final Integer STATUS_ROLLING_BACK = 9;
+//     private static final Integer STATUS_UNKNOWN = 5;
+
+       @Override
+       public Integer getActiveStatus() {
+               return STATUS_ACTIVE;
+       }
+
+       @Override
+       public Integer getPreparingStatus() {
+               return STATUS_PREPARING;
+       }
+
+       @Override
+       public Integer getMarkedRollbackStatus() {
+               return STATUS_MARKED_ROLLBACK;
+       }
+
+       @Override
+       public Integer getPreparedStatus() {
+               return STATUS_PREPARED;
+       }
+
+       @Override
+       public Integer getCommittingStatus() {
+               return STATUS_COMMITTING;
+       }
+
+       @Override
+       public Integer getCommittedStatus() {
+               return STATUS_COMMITTED;
+       }
+
+       @Override
+       public Integer getRollingBackStatus() {
+               return STATUS_ROLLING_BACK;
+       }
+
+       @Override
+       public Integer getRolledBackStatus() {
+               return STATUS_ROLLEDBACK;
+       }
+
+       @Override
+       public Integer getNoTransactionStatus() {
+               return STATUS_NO_TRANSACTION;
+       }
+
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleRollbackException.java
new file mode 100644 (file)
index 0000000..010b549
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.util.transaction;
+
+/** Internal unchecked rollback exception. */
+class SimpleRollbackException extends RuntimeException {
+       private static final long serialVersionUID = 8055601819719780566L;
+
+       public SimpleRollbackException() {
+               super();
+       }
+
+       public SimpleRollbackException(Throwable cause) {
+               super(cause);
+       }
+
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleTransaction.java
new file mode 100644 (file)
index 0000000..56ef063
--- /dev/null
@@ -0,0 +1,160 @@
+package org.argeo.util.transaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/** Simple implementation of an XA transaction. */
+class SimpleTransaction<T>
+//implements Transaction, Status 
+{
+       private final Xid xid;
+       private T status;
+       private final List<XAResource> xaResources = new ArrayList<XAResource>();
+
+       private final SimpleTransactionManager transactionManager;
+       private TransactionStatusAdapter<T> tsa;
+
+       public SimpleTransaction(SimpleTransactionManager transactionManager, TransactionStatusAdapter<T> tsa) {
+               this.tsa = tsa;
+               this.status = tsa.getActiveStatus();
+               this.xid = new UuidXid();
+               this.transactionManager = transactionManager;
+       }
+
+       public synchronized void commit()
+//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+//                     SecurityException, IllegalStateException, SystemException 
+       {
+               status = tsa.getPreparingStatus();
+               for (XAResource xaRes : xaResources) {
+                       if (status.equals(tsa.getMarkedRollbackStatus()))
+                               break;
+                       try {
+                               xaRes.prepare(xid);
+                       } catch (XAException e) {
+                               status = tsa.getMarkedRollbackStatus();
+                               error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status.equals(tsa.getMarkedRollbackStatus())) {
+                       rollback();
+                       throw new SimpleRollbackException();
+               }
+               status = tsa.getPreparedStatus();
+
+               status = tsa.getCommittingStatus();
+               for (XAResource xaRes : xaResources) {
+                       if (status.equals(tsa.getMarkedRollbackStatus()))
+                               break;
+                       try {
+                               xaRes.commit(xid, false);
+                       } catch (XAException e) {
+                               status = tsa.getMarkedRollbackStatus();
+                               error("Cannot prepare " + xaRes + " for " + xid, e);
+                       }
+               }
+               if (status.equals(tsa.getMarkedRollbackStatus())) {
+                       rollback();
+                       throw new SimpleRollbackException();
+               }
+
+               // complete
+               status = tsa.getCommittedStatus();
+               clearResources(XAResource.TMSUCCESS);
+               transactionManager.unregister(xid);
+       }
+
+       public synchronized void rollback()
+//                     throws IllegalStateException, SystemException 
+       {
+               status = tsa.getRollingBackStatus();
+               for (XAResource xaRes : xaResources) {
+                       try {
+                               xaRes.rollback(xid);
+                       } catch (XAException e) {
+                               error("Cannot rollback " + xaRes + " for " + xid, e);
+                       }
+               }
+
+               // complete
+               status = tsa.getRolledBackStatus();
+               clearResources(XAResource.TMFAIL);
+               transactionManager.unregister(xid);
+       }
+
+       public synchronized boolean enlistResource(XAResource xaRes)
+//                     throws RollbackException, IllegalStateException, SystemException 
+       {
+               if (xaResources.add(xaRes)) {
+                       try {
+                               xaRes.start(getXid(), XAResource.TMNOFLAGS);
+                               return true;
+                       } catch (XAException e) {
+                               error("Cannot enlist " + xaRes, e);
+                               return false;
+                       }
+               } else
+                       return false;
+       }
+
+       public synchronized boolean delistResource(XAResource xaRes, int flag)
+//                     throws IllegalStateException, SystemException 
+       {
+               if (xaResources.remove(xaRes)) {
+                       try {
+                               xaRes.end(getXid(), flag);
+                       } catch (XAException e) {
+                               error("Cannot delist " + xaRes, e);
+                               return false;
+                       }
+                       return true;
+               } else
+                       return false;
+       }
+
+       protected void clearResources(int flag) {
+               for (XAResource xaRes : xaResources)
+                       try {
+                               xaRes.end(getXid(), flag);
+                       } catch (XAException e) {
+                               error("Cannot end " + xaRes, e);
+                       }
+               xaResources.clear();
+       }
+
+       protected void error(Object obj, Exception e) {
+               System.err.println(obj);
+               e.printStackTrace();
+       }
+
+       public synchronized T getStatus()
+//                     throws SystemException 
+       {
+               return status;
+       }
+
+//     public void registerSynchronization(Synchronization sync)
+//                     throws RollbackException, IllegalStateException, SystemException {
+//             throw new UnsupportedOperationException();
+//     }
+
+       public void setRollbackOnly()
+//                     throws IllegalStateException, SystemException 
+       {
+               status = tsa.getMarkedRollbackStatus();
+       }
+
+       @Override
+       public int hashCode() {
+               return xid.hashCode();
+       }
+
+       Xid getXid() {
+               return xid;
+       }
+
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java b/org.argeo.util/src/org/argeo/util/transaction/SimpleTransactionManager.java
new file mode 100644 (file)
index 0000000..f5be7c8
--- /dev/null
@@ -0,0 +1,214 @@
+package org.argeo.util.transaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/**
+ * Simple implementation of an XA transaction manager.
+ */
+public class SimpleTransactionManager
+// implements TransactionManager, UserTransaction 
+               implements WorkControl, WorkTransaction {
+       private ThreadLocal<SimpleTransaction<Integer>> current = new ThreadLocal<SimpleTransaction<Integer>>();
+
+       private Map<Xid, SimpleTransaction<Integer>> knownTransactions = Collections
+                       .synchronizedMap(new HashMap<Xid, SimpleTransaction<Integer>>());
+       private TransactionStatusAdapter<Integer> tsa = new JtaStatusAdapter();
+//     private SyncRegistry syncRegistry = new SyncRegistry();
+
+       /*
+        * WORK IMPLEMENTATION
+        */
+       @Override
+       public <T> T required(Callable<T> work) {
+               T res;
+               begin();
+               try {
+                       res = work.call();
+                       commit();
+               } catch (Exception e) {
+                       rollback();
+                       throw new SimpleRollbackException(e);
+               }
+               return res;
+       }
+
+       @Override
+       public WorkContext getWorkContext() {
+               return new WorkContext() {
+
+                       @Override
+                       public void registerXAResource(XAResource resource, String recoveryId) {
+                               getTransaction().enlistResource(resource);
+                       }
+               };
+       }
+
+       /*
+        * WORK TRANSACTION IMPLEMENTATION
+        */
+
+       @Override
+       public boolean isNoTransactionStatus() {
+               return tsa.getNoTransactionStatus().equals(getStatus());
+       }
+
+       /*
+        * JTA IMPLEMENTATION
+        */
+
+       public void begin()
+//                     throws NotSupportedException, SystemException 
+       {
+               if (getCurrent() != null)
+                       throw new UnsupportedOperationException("Nested transactions are not supported");
+               SimpleTransaction<Integer> transaction = new SimpleTransaction<Integer>(this, tsa);
+               knownTransactions.put(transaction.getXid(), transaction);
+               current.set(transaction);
+       }
+
+       public void commit()
+//                     throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+//                     SecurityException, IllegalStateException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().commit();
+       }
+
+       public int getStatus()
+//                     throws SystemException
+       {
+               if (getCurrent() == null)
+                       return tsa.getNoTransactionStatus();
+               return getTransaction().getStatus();
+       }
+
+       public SimpleTransaction<Integer> getTransaction()
+//                     throws SystemException 
+       {
+               return getCurrent();
+       }
+
+       protected SimpleTransaction<Integer> getCurrent()
+//                     throws SystemException 
+       {
+               SimpleTransaction<Integer> transaction = current.get();
+               if (transaction == null)
+                       return null;
+               Integer status = transaction.getStatus();
+               if (status.equals(tsa.getCommittedStatus()) || status.equals(tsa.getRolledBackStatus())) {
+                       current.remove();
+                       return null;
+               }
+               return transaction;
+       }
+
+       void unregister(Xid xid) {
+               knownTransactions.remove(xid);
+       }
+
+       public void resume(SimpleTransaction<Integer> tobj)
+//                     throws InvalidTransactionException, IllegalStateException, SystemException 
+       {
+               if (getCurrent() != null)
+                       throw new IllegalStateException("Transaction " + current.get() + " already registered");
+               current.set(tobj);
+       }
+
+       public void rollback()
+//                     throws IllegalStateException, SecurityException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().rollback();
+       }
+
+       public void setRollbackOnly()
+//                     throws IllegalStateException, SystemException 
+       {
+               if (getCurrent() == null)
+                       throw new IllegalStateException("No transaction registered with the current thread.");
+               getCurrent().setRollbackOnly();
+       }
+
+       public void setTransactionTimeout(int seconds)
+//                     throws SystemException
+       {
+               throw new UnsupportedOperationException();
+       }
+
+       public SimpleTransaction<Integer> suspend()
+//                     throws SystemException
+       {
+               SimpleTransaction<Integer> transaction = getCurrent();
+               current.remove();
+               return transaction;
+       }
+
+//     public TransactionSynchronizationRegistry getTsr() {
+//             return syncRegistry;
+//     }
+//
+//     private class SyncRegistry implements TransactionSynchronizationRegistry {
+//             @Override
+//             public Object getTransactionKey() {
+//                     try {
+//                             SimpleTransaction transaction = getCurrent();
+//                             if (transaction == null)
+//                                     return null;
+//                             return getCurrent().getXid();
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get transaction key", e);
+//                     }
+//             }
+//
+//             @Override
+//             public void putResource(Object key, Object value) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public Object getResource(Object key) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public void registerInterposedSynchronization(Synchronization sync) {
+//                     throw new UnsupportedOperationException();
+//             }
+//
+//             @Override
+//             public int getTransactionStatus() {
+//                     try {
+//                             return getStatus();
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get status", e);
+//                     }
+//             }
+//
+//             @Override
+//             public boolean getRollbackOnly() {
+//                     try {
+//                             return getStatus() == Status.STATUS_MARKED_ROLLBACK;
+//                     } catch (SystemException e) {
+//                             throw new IllegalStateException("Cannot get status", e);
+//                     }
+//             }
+//
+//             @Override
+//             public void setRollbackOnly() {
+//                     try {
+//                             getCurrent().setRollbackOnly();
+//                     } catch (Exception e) {
+//                             throw new IllegalStateException("Cannot set rollback only", e);
+//                     }
+//             }
+//
+//     }
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java b/org.argeo.util/src/org/argeo/util/transaction/TransactionStatusAdapter.java
new file mode 100644 (file)
index 0000000..a74fef1
--- /dev/null
@@ -0,0 +1,22 @@
+package org.argeo.util.transaction;
+
+/** Abstract the various approaches to represent transaction status. */
+public interface TransactionStatusAdapter<T> {
+       T getActiveStatus();
+
+       T getPreparingStatus();
+
+       T getMarkedRollbackStatus();
+
+       T getPreparedStatus();
+
+       T getCommittingStatus();
+
+       T getCommittedStatus();
+
+       T getRollingBackStatus();
+
+       T getRolledBackStatus();
+
+       T getNoTransactionStatus();
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/UuidXid.java b/org.argeo.util/src/org/argeo/util/transaction/UuidXid.java
new file mode 100644 (file)
index 0000000..b6acebe
--- /dev/null
@@ -0,0 +1,132 @@
+package org.argeo.util.transaction;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * Implementation of {@link Xid} based on {@link UUID}, using max significant
+ * bits as global transaction id, and least significant bits as branch
+ * qualifier.
+ */
+public class UuidXid implements Xid, Serializable {
+       private static final long serialVersionUID = -5380531989917886819L;
+       public final static int FORMAT = (int) serialVersionUID;
+
+       private final static int BYTES_PER_LONG = Long.SIZE / Byte.SIZE;
+
+       private final int format;
+       private final byte[] globalTransactionId;
+       private final byte[] branchQualifier;
+       private final String uuid;
+       private final int hashCode;
+
+       public UuidXid() {
+               this(UUID.randomUUID());
+       }
+
+       public UuidXid(UUID uuid) {
+               this.format = FORMAT;
+               this.globalTransactionId = uuidToBytes(uuid.getMostSignificantBits());
+               this.branchQualifier = uuidToBytes(uuid.getLeastSignificantBits());
+               this.uuid = uuid.toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       public UuidXid(Xid xid) {
+               this(xid.getFormatId(), xid.getGlobalTransactionId(), xid
+                               .getBranchQualifier());
+       }
+
+       private UuidXid(int format, byte[] globalTransactionId,
+                       byte[] branchQualifier) {
+               this.format = format;
+               this.globalTransactionId = globalTransactionId;
+               this.branchQualifier = branchQualifier;
+               this.uuid = bytesToUUID(globalTransactionId, branchQualifier)
+                               .toString();
+               this.hashCode = uuid.hashCode();
+       }
+
+       @Override
+       public int getFormatId() {
+               return format;
+       }
+
+       @Override
+       public byte[] getGlobalTransactionId() {
+               return Arrays.copyOf(globalTransactionId, globalTransactionId.length);
+       }
+
+       @Override
+       public byte[] getBranchQualifier() {
+               return Arrays.copyOf(branchQualifier, branchQualifier.length);
+       }
+
+       @Override
+       public int hashCode() {
+               return hashCode;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj instanceof UuidXid) {
+                       UuidXid that = (UuidXid) obj;
+                       return Arrays.equals(globalTransactionId, that.globalTransactionId)
+                                       && Arrays.equals(branchQualifier, that.branchQualifier);
+               }
+               if (obj instanceof Xid) {
+                       Xid that = (Xid) obj;
+                       return Arrays.equals(globalTransactionId,
+                                       that.getGlobalTransactionId())
+                                       && Arrays
+                                                       .equals(branchQualifier, that.getBranchQualifier());
+               }
+               return uuid.equals(obj.toString());
+       }
+
+       @Override
+       protected Object clone() throws CloneNotSupportedException {
+               return new UuidXid(format, globalTransactionId, branchQualifier);
+       }
+
+       @Override
+       public String toString() {
+               return uuid;
+       }
+
+       public UUID asUuid() {
+               return bytesToUUID(globalTransactionId, branchQualifier);
+       }
+
+       public static byte[] uuidToBytes(long bits) {
+               ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_LONG);
+               buffer.putLong(0, bits);
+               return buffer.array();
+       }
+
+       public static UUID bytesToUUID(byte[] most, byte[] least) {
+               if (most.length < BYTES_PER_LONG)
+                       most = Arrays.copyOf(most, BYTES_PER_LONG);
+               if (least.length < BYTES_PER_LONG)
+                       least = Arrays.copyOf(least, BYTES_PER_LONG);
+               ByteBuffer buffer = ByteBuffer.allocate(2 * BYTES_PER_LONG);
+               buffer.put(most, 0, BYTES_PER_LONG);
+               buffer.put(least, 0, BYTES_PER_LONG);
+               buffer.flip();
+               return new UUID(buffer.getLong(), buffer.getLong());
+       }
+
+       // public static void main(String[] args) {
+       // UUID uuid = UUID.randomUUID();
+       // System.out.println(uuid);
+       // uuid = bytesToUUID(uuidToBytes(uuid.getMostSignificantBits()),
+       // uuidToBytes(uuid.getLeastSignificantBits()));
+       // System.out.println(uuid);
+       // }
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkContext.java b/org.argeo.util/src/org/argeo/util/transaction/WorkContext.java
new file mode 100644 (file)
index 0000000..e818b83
--- /dev/null
@@ -0,0 +1,11 @@
+package org.argeo.util.transaction;
+
+import javax.transaction.xa.XAResource;
+
+/**
+ * A minimalistic interface similar to OSGi transaction context in order to
+ * register XA resources.
+ */
+public interface WorkContext {
+       void registerXAResource(XAResource resource, String recoveryId);
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkControl.java b/org.argeo.util/src/org/argeo/util/transaction/WorkControl.java
new file mode 100644 (file)
index 0000000..db0e475
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.util.transaction;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A minimalistic interface inspired by OSGi transaction control in order to
+ * commit units of work externally.
+ */
+public interface WorkControl {
+       <T> T required(Callable<T> work);
+
+       void setRollbackOnly();
+
+       WorkContext getWorkContext();
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java b/org.argeo.util/src/org/argeo/util/transaction/WorkTransaction.java
new file mode 100644 (file)
index 0000000..245ca41
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.util.transaction;
+
+/**
+ * A minimalistic interface inspired by JTA user transaction in order to commit
+ * units of work externally.
+ */
+public interface WorkTransaction {
+       void begin();
+
+       void commit();
+
+       void rollback();
+
+       boolean isNoTransactionStatus();
+}
diff --git a/org.argeo.util/src/org/argeo/util/transaction/package-info.java b/org.argeo.util/src/org/argeo/util/transaction/package-info.java
new file mode 100644 (file)
index 0000000..f481161
--- /dev/null
@@ -0,0 +1,2 @@
+/** Minimalistic and partial XA transaction manager implementation. */
+package org.argeo.util.transaction;
\ No newline at end of file