]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java
Use Bitronix as transaction manager.
[lgpl/argeo-commons.git] / org.argeo.security.core / src / org / argeo / osgi / useradmin / UserDirectoryWorkingCopy.java
diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserDirectoryWorkingCopy.java
new file mode 100644 (file)
index 0000000..d2bd9ff
--- /dev/null
@@ -0,0 +1,185 @@
+package org.argeo.osgi.useradmin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer;
+
+/** {@link XAResource} for a user directory being edited. */
+class UserDirectoryWorkingCopy implements XAResource {
+       private final static Log log = LogFactory
+                       .getLog(UserDirectoryWorkingCopy.class);
+       private final String cacheName = getClass().getName();
+
+       private final AbstractUserDirectory userDirectory;
+
+       private Xid xid;
+       private int transactionTimeout = 0;
+
+       private Map<LdapName, DirectoryUser> newUsers = new HashMap<LdapName, DirectoryUser>();
+       private Map<LdapName, Attributes> modifiedUsers = new HashMap<LdapName, Attributes>();
+       private Map<LdapName, DirectoryUser> deletedUsers = new HashMap<LdapName, DirectoryUser>();
+
+       public UserDirectoryWorkingCopy(AbstractUserDirectory userDirectory) {
+               this.userDirectory = userDirectory;
+               try {
+                       // FIXME Make it less bitronix dependant
+                       EhCacheXAResourceProducer.registerXAResource(cacheName, this);
+               } catch (Exception e) {
+                       log.error("Cannot register resource to Bitronix", e);
+               }
+       }
+
+       @Override
+       public void start(Xid xid, int flags) throws XAException {
+               this.xid = xid;
+       }
+
+       @Override
+       public void end(Xid xid, int flags) throws XAException {
+               checkXid(xid);
+
+       }
+
+       private void cleanUp() {
+               // clean collections
+               newUsers.clear();
+               newUsers = null;
+               modifiedUsers.clear();
+               modifiedUsers = null;
+               deletedUsers.clear();
+               deletedUsers = null;
+
+               // clean IDs
+               this.xid = null;
+               userDirectory.clearEditingTransactionXid();
+
+               try {
+                       // FIXME Make it less bitronix dependant
+                       EhCacheXAResourceProducer.unregisterXAResource(cacheName, this);
+               } catch (Exception e) {
+                       log.error("Cannot unregister resource from Bitronix", e);
+               }
+       }
+
+       @Override
+       public int prepare(Xid xid) throws XAException {
+               checkXid(xid);
+               if (noModifications())
+                       return XA_RDONLY;
+               try {
+                       userDirectory.prepare(this);
+               } catch (Exception e) {
+                       log.error("Cannot prepare " + xid, e);
+                       throw new XAException(XAException.XA_RBOTHER);
+               }
+               return XA_OK;
+       }
+
+       @Override
+       public void commit(Xid xid, boolean onePhase) throws XAException {
+               try {
+                       checkXid(xid);
+                       if (noModifications())
+                               return;
+                       if (onePhase)
+                               userDirectory.prepare(this);
+                       userDirectory.commit(this);
+               } catch (Exception e) {
+                       log.error("Cannot commit " + xid, e);
+                       throw new XAException(XAException.XA_RBOTHER);
+               } finally {
+                       cleanUp();
+               }
+       }
+
+       @Override
+       public void rollback(Xid xid) throws XAException {
+               try {
+                       checkXid(xid);
+                       userDirectory.rollback(this);
+               } catch (Exception e) {
+                       log.error("Cannot rollback " + xid, e);
+                       throw new XAException(XAException.XA_HEURMIX);
+               } finally {
+                       cleanUp();
+               }
+       }
+
+       @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;
+       }
+
+       Xid getXid() {
+               return xid;
+       }
+
+       private void checkXid(Xid xid) throws XAException {
+               if (this.xid == null)
+                       throw new XAException(XAException.XAER_OUTSIDE);
+               if (!this.xid.equals(xid))
+                       throw new XAException(XAException.XAER_NOTA);
+       }
+
+       public boolean noModifications() {
+               return newUsers.size() == 0 && modifiedUsers.size() == 0
+                               && deletedUsers.size() == 0;
+       }
+
+       public Attributes getAttributes(LdapName dn) {
+               if (modifiedUsers.containsKey(dn))
+                       return modifiedUsers.get(dn);
+               return null;
+       }
+
+       public void startEditing(DirectoryUser user) {
+               LdapName dn = user.getDn();
+               if (modifiedUsers.containsKey(dn))
+                       throw new UserDirectoryException("Already editing " + dn);
+               modifiedUsers.put(dn, (Attributes) user.getAttributes().clone());
+       }
+
+       public Map<LdapName, DirectoryUser> getNewUsers() {
+               return newUsers;
+       }
+
+       public Map<LdapName, DirectoryUser> getDeletedUsers() {
+               return deletedUsers;
+       }
+
+       public Map<LdapName, Attributes> getModifiedUsers() {
+               return modifiedUsers;
+       }
+
+}