import org.osgi.service.useradmin.User;
import org.osgi.service.useradmin.UserAdmin;
+import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer;
+
/**
* Aggregates multiple {@link UserDirectory} and integrates them with this node
* system roles.
private Repository repository;
private Session adminSession;
+ private final String cacheName = UserDirectory.class.getName();
+
public NodeUserAdmin(TransactionManager transactionManager,
Repository repository) {
this.repository = repository;
if (userAdmins.get(name) instanceof UserDirectory) {
UserDirectory userDirectory = (UserDirectory) userAdmins
.get(name);
+ try {
+ // FIXME Make it less bitronix dependant
+ EhCacheXAResourceProducer.unregisterXAResource(cacheName,
+ userDirectory.getXaResource());
+ } catch (Exception e) {
+ log.error("Cannot unregister resource from Bitronix", e);
+ }
userDirectory.destroy();
+
}
}
}
//
// USER ADMIN AGGREGATOR
//
- public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
+ public void addUserAdmin(String baseDn, UserAdmin userAdmin) {
if (userAdmins.containsKey(baseDn))
throw new UserDirectoryException(
"There is already a user admin for " + baseDn);
throw new UserDirectoryException("Badly formatted base DN "
+ baseDn, e);
}
+ if (userAdmin instanceof UserDirectory) {
+ try {
+ // FIXME Make it less bitronix dependant
+ EhCacheXAResourceProducer.registerXAResource(cacheName,
+ ((UserDirectory) userAdmin).getXaResource());
+ } catch (Exception e) {
+ log.error("Cannot register resource to Bitronix", e);
+ }
+ }
}
private UserAdmin findUserAdmin(String name) {
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
-import javax.transaction.xa.Xid;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
.asList(new String[] { LdifName.userpassword.name() });
private TransactionManager transactionManager;
- private ThreadLocal<UserDirectoryWorkingCopy> workingCopy = new ThreadLocal<UserDirectoryWorkingCopy>();
- private Xid editingTransactionXid = null;
+ // private TransactionSynchronizationRegistry transactionRegistry;
+ // private Xid editingTransactionXid = null;
+ private WcXaResource xaResource = new WcXaResource(this);
AbstractUserDirectory(Dictionary<String, ?> props) {
properties = new Hashtable<String, Object>();
}
boolean isEditing() {
- if (editingTransactionXid == null)
- return false;
- return workingCopy.get() != null;
+ // if (editingTransactionXid == null)
+ // return false;
+ // return workingCopy.get() != null;
+ return xaResource.wc() != null;
}
protected UserDirectoryWorkingCopy getWorkingCopy() {
- UserDirectoryWorkingCopy wc = workingCopy.get();
+ // UserDirectoryWorkingCopy wc = workingCopy.get();
+ UserDirectoryWorkingCopy wc = xaResource.wc();
if (wc == null)
return null;
- if (wc.getXid() == null) {
- workingCopy.set(null);
- return null;
- }
+ // if (wc.getXid() == null) {
+ // workingCopy.set(null);
+ // return null;
+ // }
return wc;
}
if (transaction == null)
throw new UserDirectoryException(
"A transaction needs to be active in order to edit");
- if (editingTransactionXid == null) {
- UserDirectoryWorkingCopy wc = new UserDirectoryWorkingCopy(this);
+ if (xaResource.wc() == null) {
+ // UserDirectoryWorkingCopy wc = new UserDirectoryWorkingCopy(this);
try {
- transaction.enlistResource(wc);
- editingTransactionXid = wc.getXid();
- workingCopy.set(wc);
+ transaction.enlistResource(xaResource);
+ // editingTransactionXid = wc.getXid();
+ // workingCopy.set(wc);
} catch (Exception e) {
- throw new UserDirectoryException("Cannot enlist " + wc, e);
+ throw new UserDirectoryException("Cannot enlist " + xaResource,
+ e);
}
} else {
- if (workingCopy.get() == null)
- throw new UserDirectoryException("Transaction "
- + editingTransactionXid + " already editing");
- else if (!editingTransactionXid.equals(workingCopy.get().getXid()))
- throw new UserDirectoryException("Working copy Xid "
- + workingCopy.get().getXid() + " inconsistent with"
- + editingTransactionXid);
+ // UserDirectoryWorkingCopy wc = xaResource.wc();
+ // if (wc == null)
+ // throw new UserDirectoryException("Transaction "
+ // + editingTransactionXid + " already editing");
+ // else if
+ // (!editingTransactionXid.equals(workingCopy.get().getXid()))
+ // throw new UserDirectoryException("Working copy Xid "
+ // + workingCopy.get().getXid() + " inconsistent with"
+ // + editingTransactionXid);
}
}
}
- void clearEditingTransactionXid() {
- editingTransactionXid = null;
- }
+ // void clearEditingTransactionXid() {
+ // editingTransactionXid = null;
+ // }
// UTILITIES
protected LdapName toDn(String name) {
this.transactionManager = transactionManager;
}
+ public WcXaResource getXaResource() {
+ return xaResource;
+ }
+
}
import java.util.Dictionary;
import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
import org.osgi.service.useradmin.UserAdmin;
public void init();
public void destroy();
+
+ public XAResource getXaResource();
}
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;
+class UserDirectoryWorkingCopy {
+ // private final static Log log = LogFactory
+ // .getLog(UserDirectoryWorkingCopy.class);
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() {
+ void cleanUp() {
// clean collections
newUsers.clear();
newUsers = null;
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() {
public Map<LdapName, Attributes> getModifiedUsers() {
return modifiedUsers;
}
-
}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+
+/** {@link XAResource} for a user directory being edited. */
+class WcXaResource implements XAResource {
+ private final static Log log = LogFactory.getLog(WcXaResource.class);
+
+ private final AbstractUserDirectory userDirectory;
+
+ private Map<Xid, UserDirectoryWorkingCopy> workingCopies = new HashMap<Xid, UserDirectoryWorkingCopy>();
+ private Xid editingXid = null;
+ private int transactionTimeout = 0;
+
+ public WcXaResource(AbstractUserDirectory userDirectory) {
+ this.userDirectory = userDirectory;
+ }
+
+ @Override
+ public void start(Xid xid, int flags) throws XAException {
+ if (editingXid != null)
+ throw new UserDirectoryException("Already editing " + editingXid);
+ UserDirectoryWorkingCopy wc = workingCopies.put(xid,
+ new UserDirectoryWorkingCopy());
+ if (wc != null)
+ throw new UserDirectoryException(
+ "There is already a working copy for " + xid);
+ this.editingXid = xid;
+ }
+
+ @Override
+ public void end(Xid xid, int flags) throws XAException {
+ checkXid(xid);
+
+ }
+
+ private UserDirectoryWorkingCopy wc(Xid xid) {
+ return workingCopies.get(xid);
+ }
+
+ UserDirectoryWorkingCopy wc() {
+ if (editingXid == null)
+ return null;
+ UserDirectoryWorkingCopy wc = workingCopies.get(editingXid);
+ if (wc == null)
+ throw new UserDirectoryException("No working copy found for "
+ + editingXid);
+ return wc;
+ }
+
+ private void cleanUp(Xid xid) {
+ // clean collections
+ wc(xid).cleanUp();
+ workingCopies.remove(xid);
+
+ // clean IDs
+ // userDirectory.clearEditingTransactionXid();
+ }
+
+ @Override
+ public int prepare(Xid xid) throws XAException {
+ checkXid(xid);
+ UserDirectoryWorkingCopy wc = wc(xid);
+ if (wc.noModifications())
+ return XA_RDONLY;
+ try {
+ userDirectory.prepare(wc);
+ } 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);
+ UserDirectoryWorkingCopy wc = wc(xid);
+ if (wc.noModifications())
+ return;
+ if (onePhase)
+ userDirectory.prepare(wc);
+ userDirectory.commit(wc);
+ } catch (Exception e) {
+ log.error("Cannot commit " + xid, e);
+ throw new XAException(XAException.XA_RBOTHER);
+ } finally {
+ cleanUp(xid);
+ }
+ }
+
+ @Override
+ public void rollback(Xid xid) throws XAException {
+ try {
+ checkXid(xid);
+ userDirectory.rollback(wc(xid));
+ } catch (Exception e) {
+ log.error("Cannot rollback " + xid, e);
+ throw new XAException(XAException.XA_HEURMIX);
+ } 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);
+ }
+
+}