Massive package refactoring
[lgpl/argeo-commons.git] / org.argeo.api.cms / src / org / argeo / api / cms / transaction / WorkingCopyXaResource.java
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyXaResource.java b/org.argeo.api.cms/src/org/argeo/api/cms/transaction/WorkingCopyXaResource.java
new file mode 100644 (file)
index 0000000..16b08c2
--- /dev/null
@@ -0,0 +1,138 @@
+package org.argeo.api.cms.transaction;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+/** {@link XAResource} for a user directory being edited. */
+public class WorkingCopyXaResource<WC extends WorkingCopy<?, ?, ?>> implements XAResource {
+       private final WorkingCopyProcessor<WC> processor;
+
+       private Map<Xid, WC> workingCopies = new HashMap<Xid, WC>();
+       private Xid editingXid = null;
+       private int transactionTimeout = 0;
+
+       public WorkingCopyXaResource(WorkingCopyProcessor<WC> processor) {
+               this.processor = processor;
+       }
+
+       @Override
+       public synchronized void start(Xid xid, int flags) throws XAException {
+               if (editingXid != null)
+                       throw new IllegalStateException("Already editing " + editingXid);
+               WC wc = workingCopies.put(xid, processor.newWorkingCopy());
+               if (wc != null)
+                       throw new IllegalStateException("There is already a working copy for " + xid);
+               this.editingXid = xid;
+       }
+
+       @Override
+       public void end(Xid xid, int flags) throws XAException {
+               checkXid(xid);
+       }
+
+       private WC wc(Xid xid) {
+               return workingCopies.get(xid);
+       }
+
+       public synchronized WC wc() {
+               if (editingXid == null)
+                       return null;
+               WC wc = workingCopies.get(editingXid);
+               if (wc == null)
+                       throw new IllegalStateException("No working copy found for " + editingXid);
+               return wc;
+       }
+
+       private synchronized void cleanUp(Xid xid) {
+               WC wc = workingCopies.get(xid);
+               if (wc != null) {
+                       wc.cleanUp();
+                       workingCopies.remove(xid);
+               }
+               editingXid = null;
+       }
+
+       @Override
+       public int prepare(Xid xid) throws XAException {
+               checkXid(xid);
+               WC wc = wc(xid);
+               if (wc.noModifications())
+                       return XA_RDONLY;
+               try {
+                       processor.prepare(wc);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               }
+               return XA_OK;
+       }
+
+       @Override
+       public void commit(Xid xid, boolean onePhase) throws XAException {
+               try {
+                       checkXid(xid);
+                       WC wc = wc(xid);
+                       if (wc.noModifications())
+                               return;
+                       if (onePhase)
+                               processor.prepare(wc);
+                       processor.commit(wc);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               } finally {
+                       cleanUp(xid);
+               }
+       }
+
+       @Override
+       public void rollback(Xid xid) throws XAException {
+               try {
+                       checkXid(xid);
+                       processor.rollback(wc(xid));
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new XAException(XAException.XAER_RMERR);
+               } finally {
+                       cleanUp(xid);
+               }
+       }
+
+       @Override
+       public void forget(Xid xid) throws XAException {
+               throw new UnsupportedOperationException();
+       }
+
+       @Override
+       public boolean isSameRM(XAResource xares) throws XAException {
+               return xares == this;
+       }
+
+       @Override
+       public Xid[] recover(int flag) throws XAException {
+               return new Xid[0];
+       }
+
+       @Override
+       public int getTransactionTimeout() throws XAException {
+               return transactionTimeout;
+       }
+
+       @Override
+       public boolean setTransactionTimeout(int seconds) throws XAException {
+               transactionTimeout = seconds;
+               return true;
+       }
+
+       private void checkXid(Xid xid) throws XAException {
+               if (xid == null)
+                       throw new XAException(XAException.XAER_OUTSIDE);
+               if (!xid.equals(xid))
+                       throw new XAException(XAException.XAER_NOTA);
+       }
+
+}