From 5986e55820cba0821f0c16627c4ab144863c82ab Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 7 Dec 2021 09:47:02 +0100 Subject: [PATCH] Remove dependency to JTA --- dep/org.argeo.dep.cms.client/pom.xml | 2 + .../OSGI-INF/userAdminWrapper.xml | 2 +- .../argeo/cms/e4/handlers/ChangePassword.java | 4 +- .../org/argeo/cms/e4/users/GroupEditor.java | 4 +- .../org/argeo/cms/e4/users/UiAdminUtils.java | 4 +- .../argeo/cms/e4/users/UserAdminWrapper.java | 16 +- .../cms/e4/users/UserBatchUpdateWizard.java | 42 +--- .../org/argeo/cms/tabular/JcrTabularTest.java | 4 +- .../AbstractMaintenanceService.java | 8 +- .../maintenance/SimpleRoleRegistration.java | 6 +- org.argeo.cms/OSGI-INF/cmsUserManager.xml | 4 +- .../src/org/argeo/cms/CmsUserManager.java | 12 +- .../cms/internal/auth/CmsUserManagerImpl.java | 21 +- .../cms/internal/kernel/CmsDeployment.java | 12 +- .../argeo/cms/internal/kernel/CmsState.java | 13 +- .../cms/internal/kernel/NodeUserAdmin.java | 10 +- .../osgi/useradmin/LdifUserAdminTest.java | 10 +- .../osgi/transaction/JtaStatusAdapter.java | 61 +++++ .../transaction/SimpleRollbackException.java | 15 ++ .../transaction}/SimpleTransaction.java | 91 ++++---- .../transaction/SimpleTransactionManager.java | 214 ++++++++++++++++++ .../transaction/TransactionStatusAdapter.java | 22 ++ .../simple => osgi/transaction}/UuidXid.java | 2 +- .../argeo/osgi/transaction/WorkContext.java | 11 + .../argeo/osgi/transaction/WorkControl.java | 15 ++ .../osgi/transaction/WorkTransaction.java | 15 ++ .../transaction}/package-info.java | 2 +- .../osgi/useradmin/AbstractUserDirectory.java | 36 +-- .../simple/SimpleTransactionManager.java | 170 -------------- pom.xml | 13 +- 30 files changed, 504 insertions(+), 337 deletions(-) create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/JtaStatusAdapter.java create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleRollbackException.java rename org.argeo.enterprise/src/org/argeo/{transaction/simple => osgi/transaction}/SimpleTransaction.java (55%) create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransactionManager.java create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java rename org.argeo.enterprise/src/org/argeo/{transaction/simple => osgi/transaction}/UuidXid.java (98%) create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkContext.java create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkControl.java create mode 100644 org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkTransaction.java rename org.argeo.enterprise/src/org/argeo/{transaction/simple => osgi/transaction}/package-info.java (65%) delete mode 100644 org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransactionManager.java diff --git a/dep/org.argeo.dep.cms.client/pom.xml b/dep/org.argeo.dep.cms.client/pom.xml index 2381d27b3..3c99ba16c 100644 --- a/dep/org.argeo.dep.cms.client/pom.xml +++ b/dep/org.argeo.dep.cms.client/pom.xml @@ -45,6 +45,8 @@ org.argeo.tp.javax javax.enterprise.cdi-api + + org.argeo.tp.javax javax.transaction-api diff --git a/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml b/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml index 6fa13d402..a267aa519 100644 --- a/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml +++ b/org.argeo.cms.e4/OSGI-INF/userAdminWrapper.xml @@ -1,7 +1,7 @@ - + diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java index 52756376b..fe05253c1 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/handlers/ChangePassword.java @@ -11,13 +11,13 @@ import java.util.Arrays; import javax.inject.Inject; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; -import javax.transaction.UserTransaction; import org.argeo.api.security.CryptoKeyring; import org.argeo.cms.CmsException; import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.ui.dialogs.CmsMessageDialog; import org.argeo.eclipse.ui.dialogs.ErrorFeedback; +import org.argeo.osgi.transaction.WorkTransaction; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.jface.dialogs.Dialog; @@ -38,7 +38,7 @@ public class ChangePassword { @Inject private UserAdmin userAdmin; @Inject - private UserTransaction userTransaction; + private WorkTransaction userTransaction; @Inject @Optional private CryptoKeyring keyring = null; diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java index 2c7504971..9ba7af72f 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/GroupEditor.java @@ -17,7 +17,6 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; -import javax.transaction.UserTransaction; import org.argeo.api.NodeConstants; import org.argeo.api.NodeInstance; @@ -36,6 +35,7 @@ import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.parts.LdifUsersTable; import org.argeo.jcr.JcrUtils; import org.argeo.naming.LdapAttrs; +import org.argeo.osgi.transaction.WorkTransaction; import org.eclipse.e4.ui.workbench.modeling.EPartService; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ToolBarManager; @@ -514,7 +514,7 @@ public class GroupEditor extends AbstractRoleEditor { userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup)); } else if (role.getType() == Role.USER) { // TODO check if the group is already member of this group - UserTransaction transaction = userAdminWrapper.beginTransactionIfNeeded(); + WorkTransaction transaction = userAdminWrapper.beginTransactionIfNeeded(); User user = (User) role; myGroup.addMember(user); if (UserAdminWrapper.COMMIT_ON_SAVE) diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UiAdminUtils.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UiAdminUtils.java index a5fb6100e..f85649260 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UiAdminUtils.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UiAdminUtils.java @@ -1,6 +1,6 @@ package org.argeo.cms.e4.users; -import javax.transaction.UserTransaction; +import org.argeo.osgi.transaction.WorkTransaction; /** First effort to centralize back end methods used by the user admin UI */ public class UiAdminUtils { @@ -10,7 +10,7 @@ public class UiAdminUtils { */ /** Easily notify the ActiveWindow that the transaction had a state change */ public final static void notifyTransactionStateChange( - UserTransaction userTransaction) { + WorkTransaction userTransaction) { // try { // IWorkbenchWindow aww = PlatformUI.getWorkbench() // .getActiveWorkbenchWindow(); diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java index 60d232aba..d1bdd775a 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserAdminWrapper.java @@ -8,11 +8,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import javax.transaction.Status; -import javax.transaction.UserTransaction; - import org.argeo.api.NodeConstants; 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.osgi.service.useradmin.UserAdmin; @@ -27,7 +25,7 @@ public class UserAdminWrapper { // private Set uris; private Map> userDirectories = Collections .synchronizedMap(new LinkedHashMap<>()); - private UserTransaction userTransaction; + private WorkTransaction userTransaction; // First effort to simplify UX while managing users and groups public final static boolean COMMIT_ON_SAVE = true; @@ -40,10 +38,10 @@ public class UserAdminWrapper { * {@link UserAdminWrapper#commitOrNotifyTransactionStateChange()} once the * security model changes have been performed. */ - public UserTransaction beginTransactionIfNeeded() { + public WorkTransaction beginTransactionIfNeeded() { try { // UserTransaction userTransaction = getUserTransaction(); - if (userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION) { + if (userTransaction.isNoTransactionStatus()) { userTransaction.begin(); // UiAdminUtils.notifyTransactionStateChange(userTransaction); } @@ -61,7 +59,7 @@ public class UserAdminWrapper { public void commitOrNotifyTransactionStateChange() { try { // UserTransaction userTransaction = getUserTransaction(); - if (userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION) + if (userTransaction.isNoTransactionStatus()) return; if (UserAdminWrapper.COMMIT_ON_SAVE) @@ -126,7 +124,7 @@ public class UserAdminWrapper { return userAdmin; } - public UserTransaction getUserTransaction() { + public WorkTransaction getUserTransaction() { return userTransaction; } @@ -136,7 +134,7 @@ public class UserAdminWrapper { // this.uris = Collections.unmodifiableSortedSet(new TreeSet<>(properties.keySet())); } - public void setUserTransaction(UserTransaction userTransaction) { + public void setUserTransaction(WorkTransaction userTransaction) { this.userTransaction = userTransaction; } diff --git a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserBatchUpdateWizard.java b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserBatchUpdateWizard.java index 7513102fe..4073a209b 100644 --- a/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserBatchUpdateWizard.java +++ b/org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserBatchUpdateWizard.java @@ -5,9 +5,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.transaction.SystemException; -import javax.transaction.UserTransaction; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; @@ -23,6 +20,7 @@ import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.parts.LdifUsersTable; import org.argeo.naming.LdapAttrs; import org.argeo.naming.LdapObjs; +import org.argeo.osgi.transaction.WorkTransaction; import org.eclipse.jface.dialogs.IPageChangeProvider; import org.eclipse.jface.dialogs.IPageChangedListener; import org.eclipse.jface.dialogs.MessageDialog; @@ -90,15 +88,10 @@ public class UserBatchUpdateWizard extends Wizard { public boolean performFinish() { if (!canFinish()) return false; - UserTransaction ut = userAdminWrapper.getUserTransaction(); - try { - if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION - && !MessageDialog.openConfirm(getShell(), "Existing Transaction", - "A user transaction is already existing, " + "are you sure you want to proceed ?")) - return false; - } catch (SystemException e) { - throw new CmsException("Cannot get user transaction state " + "before user batch update", e); - } + WorkTransaction ut = userAdminWrapper.getUserTransaction(); + if (!ut.isNoTransactionStatus() && !MessageDialog.openConfirm(getShell(), "Existing Transaction", + "A user transaction is already existing, " + "are you sure you want to proceed ?")) + return false; // We cannot use jobs, user modifications are still meant to be done in // the UIThread @@ -151,14 +144,9 @@ public class UserBatchUpdateWizard extends Wizard { } catch (Exception e) { throw new CmsException("Cannot perform batch update on users", e); } finally { - UserTransaction ut = userAdminWrapper.getUserTransaction(); - try { - if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION) - ut.rollback(); - } catch (IllegalStateException | SecurityException | SystemException e) { - log.error("Unable to rollback session in 'finally', " + "the system might be in a dirty state"); - e.printStackTrace(); - } + WorkTransaction ut = userAdminWrapper.getUserTransaction(); + if (!ut.isNoTransactionStatus()) + ut.rollback(); } } } @@ -190,14 +178,9 @@ public class UserBatchUpdateWizard extends Wizard { } catch (Exception e) { throw new CmsException("Cannot perform batch update on users", e); } finally { - UserTransaction ut = userAdminWrapper.getUserTransaction(); - try { - if (ut.getStatus() != javax.transaction.Status.STATUS_NO_TRANSACTION) - ut.rollback(); - } catch (IllegalStateException | SecurityException | SystemException e) { - log.error("Unable to rollback session in finally block, the system might be in a dirty state"); - e.printStackTrace(); - } + WorkTransaction ut = userAdminWrapper.getUserTransaction(); + if (!ut.isNoTransactionStatus()) + ut.rollback(); } } } @@ -457,8 +440,7 @@ public class UserBatchUpdateWizard extends Wizard { } /** - * Displays a list of users with a check box to be able to choose some of - * them + * Displays a list of users with a check box to be able to choose some of them */ private class ChooseUsersWizardPage extends WizardPage implements IPageChangedListener { private static final long serialVersionUID = 7651807402211214274L; diff --git a/org.argeo.cms.jcr/ext/test/org/argeo/cms/tabular/JcrTabularTest.java b/org.argeo.cms.jcr/ext/test/org/argeo/cms/tabular/JcrTabularTest.java index 8da614800..18150c791 100644 --- a/org.argeo.cms.jcr/ext/test/org/argeo/cms/tabular/JcrTabularTest.java +++ b/org.argeo.cms.jcr/ext/test/org/argeo/cms/tabular/JcrTabularTest.java @@ -22,10 +22,10 @@ public class JcrTabularTest extends AbstractJackrabbitTestCase { public void testWriteReadCsv() throws Exception { // session().setNamespacePrefix("argeo", ArgeoNames.ARGEO_NAMESPACE); - InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/api/ldap.cnd")); + InputStreamReader reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/cms/jcr/ldap.cnd")); CndImporter.registerNodeTypes(reader, session()); reader.close(); - reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/cms/argeo.cnd")); + reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/cms/jcr/argeo.cnd")); CndImporter.registerNodeTypes(reader, session()); reader.close(); // reader = new InputStreamReader(getClass().getResourceAsStream("/org/argeo/cms/cms.cnd")); diff --git a/org.argeo.cms.jcr/src/org/argeo/maintenance/AbstractMaintenanceService.java b/org.argeo.cms.jcr/src/org/argeo/maintenance/AbstractMaintenanceService.java index 6003d638d..ae09cd4bf 100644 --- a/org.argeo.cms.jcr/src/org/argeo/maintenance/AbstractMaintenanceService.java +++ b/org.argeo.cms.jcr/src/org/argeo/maintenance/AbstractMaintenanceService.java @@ -9,7 +9,6 @@ import javax.jcr.NoSuchWorkspaceException; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; -import javax.transaction.UserTransaction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -17,6 +16,7 @@ import org.argeo.api.NodeUtils; import org.argeo.jcr.Jcr; import org.argeo.jcr.JcrUtils; import org.argeo.naming.Distinguished; +import org.argeo.osgi.transaction.WorkTransaction; import org.osgi.service.useradmin.Group; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.UserAdmin; @@ -28,7 +28,7 @@ public abstract class AbstractMaintenanceService { private Repository repository; // private UserAdminService userAdminService; private UserAdmin userAdmin; - private UserTransaction userTransaction; + private WorkTransaction userTransaction; public void init() { makeSureRolesExists(getRequiredRoles()); @@ -202,7 +202,7 @@ public abstract class AbstractMaintenanceService { // this.userAdminService = userAdminService; // } - protected UserTransaction getUserTransaction() { + protected WorkTransaction getUserTransaction() { return userTransaction; } @@ -214,7 +214,7 @@ public abstract class AbstractMaintenanceService { this.userAdmin = userAdmin; } - public void setUserTransaction(UserTransaction userTransaction) { + public void setUserTransaction(WorkTransaction userTransaction) { this.userTransaction = userTransaction; } diff --git a/org.argeo.cms.jcr/src/org/argeo/maintenance/SimpleRoleRegistration.java b/org.argeo.cms.jcr/src/org/argeo/maintenance/SimpleRoleRegistration.java index a30fe9796..07dc39985 100644 --- a/org.argeo.cms.jcr/src/org/argeo/maintenance/SimpleRoleRegistration.java +++ b/org.argeo.cms.jcr/src/org/argeo/maintenance/SimpleRoleRegistration.java @@ -6,10 +6,10 @@ import java.util.Map; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; -import javax.transaction.UserTransaction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.argeo.osgi.transaction.WorkTransaction; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.UserAdmin; @@ -23,7 +23,7 @@ public class SimpleRoleRegistration implements Runnable { private String role; private List roles = new ArrayList(); private UserAdmin userAdmin; - private UserTransaction userTransaction; + private WorkTransaction userTransaction; @Override public void run() { @@ -80,7 +80,7 @@ public class SimpleRoleRegistration implements Runnable { this.userAdmin = userAdminService; } - public void setUserTransaction(UserTransaction userTransaction) { + public void setUserTransaction(WorkTransaction userTransaction) { this.userTransaction = userTransaction; } diff --git a/org.argeo.cms/OSGI-INF/cmsUserManager.xml b/org.argeo.cms/OSGI-INF/cmsUserManager.xml index 045c9609a..524c054ec 100644 --- a/org.argeo.cms/OSGI-INF/cmsUserManager.xml +++ b/org.argeo.cms/OSGI-INF/cmsUserManager.xml @@ -5,6 +5,6 @@ - + - \ No newline at end of file + diff --git a/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java b/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java index d970855ff..cd76d65ef 100644 --- a/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java +++ b/org.argeo.cms/src/org/argeo/cms/CmsUserManager.java @@ -5,12 +5,10 @@ import java.util.List; import java.util.Set; import javax.security.auth.Subject; -import javax.transaction.UserTransaction; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; -import org.osgi.service.useradmin.UserAdmin; /** * Provide method interfaces to manage user concepts without accessing directly @@ -81,9 +79,9 @@ public interface CmsUserManager { // User createUserFromPerson(Node person); - @Deprecated - public UserAdmin getUserAdmin(); - - @Deprecated - public UserTransaction getUserTransaction(); +// @Deprecated +// public UserAdmin getUserAdmin(); +// +// @Deprecated +// public UserTransaction getUserTransaction(); } \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java index d21e8616c..5753decf9 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/auth/CmsUserManagerImpl.java @@ -22,8 +22,6 @@ import java.util.UUID; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; import javax.security.auth.Subject; -import javax.transaction.Status; -import javax.transaction.UserTransaction; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -34,6 +32,7 @@ import org.argeo.cms.auth.UserAdminUtils; import org.argeo.naming.LdapAttrs; import org.argeo.naming.NamingUtils; import org.argeo.naming.SharedSecret; +import org.argeo.osgi.transaction.WorkTransaction; import org.argeo.osgi.useradmin.TokenUtils; import org.argeo.osgi.useradmin.UserAdminConf; import org.argeo.osgi.useradmin.UserDirectory; @@ -61,7 +60,7 @@ public class CmsUserManagerImpl implements CmsUserManager { private UserAdmin userAdmin; // private Map serviceProperties; - private UserTransaction userTransaction; + private WorkTransaction userTransaction; private Map> userDirectories = Collections .synchronizedMap(new LinkedHashMap<>()); @@ -351,7 +350,7 @@ public class CmsUserManagerImpl implements CmsUserManager { return tokenStr; } catch (Exception e1) { try { - if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) + if (!userTransaction.isNoTransactionStatus()) userTransaction.rollback(); } catch (Exception e2) { if (log.isTraceEnabled()) @@ -374,7 +373,7 @@ public class CmsUserManagerImpl implements CmsUserManager { log.debug("Token " + token + " expired."); } catch (Exception e1) { try { - if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) + if (!userTransaction.isNoTransactionStatus()) userTransaction.rollback(); } catch (Exception e2) { if (log.isTraceEnabled()) @@ -423,7 +422,7 @@ public class CmsUserManagerImpl implements CmsUserManager { userTransaction.commit(); } catch (Exception e1) { try { - if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) + if (!userTransaction.isNoTransactionStatus()) userTransaction.rollback(); } catch (Exception e2) { if (log.isTraceEnabled()) @@ -468,9 +467,9 @@ public class CmsUserManagerImpl implements CmsUserManager { return userAdmin; } - public UserTransaction getUserTransaction() { - return userTransaction; - } +// public UserTransaction getUserTransaction() { +// return userTransaction; +// } /* DEPENDENCY INJECTION */ public void setUserAdmin(UserAdmin userAdmin) { @@ -478,10 +477,10 @@ public class CmsUserManagerImpl implements CmsUserManager { // this.serviceProperties = serviceProperties; } - public void setUserTransaction(UserTransaction userTransaction) { + public void setUserTransaction(WorkTransaction userTransaction) { this.userTransaction = userTransaction; } - + public void addUserDirectory(UserDirectory userDirectory, Map properties) { userDirectories.put(userDirectory, new Hashtable<>(properties)); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java index cb4d55273..b24fb0a12 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java @@ -5,13 +5,12 @@ import java.lang.management.ManagementFactory; import java.net.URL; import java.util.Dictionary; -import javax.transaction.UserTransaction; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; import org.argeo.api.NodeDeployment; import org.argeo.api.NodeState; +import org.argeo.osgi.transaction.WorkTransaction; import org.argeo.osgi.useradmin.UserAdminConf; import org.eclipse.equinox.http.jetty.JettyConfigurator; import org.osgi.framework.BundleContext; @@ -34,7 +33,6 @@ public class CmsDeployment implements NodeDeployment { private Long availableSince; - // Readiness private boolean nodeAvailable = false; private boolean userAdminAvailable = false; @@ -69,7 +67,6 @@ public class CmsDeployment implements NodeDeployment { // httpSt.open(); KernelUtils.asyncOpen(httpSt); - ServiceTracker userAdminSt = new ServiceTracker(bc, UserAdmin.class, null) { @Override public UserAdmin addingService(ServiceReference reference) { @@ -96,7 +93,7 @@ public class CmsDeployment implements NodeDeployment { } catch (Exception e) { throw new IllegalStateException("Cannot analyse clean state", e); } - deployConfig = new DeployConfig(configurationAdmin, isClean); + deployConfig = new DeployConfig(configurationAdmin, isClean); Activator.registerService(NodeDeployment.class, CmsDeployment.this, null); // JcrInitUtils.addToDeployment(CmsDeployment.this); httpExpected = deployConfig.getProps(KernelConstants.JETTY_FACTORY_PID, "default") != null; @@ -145,7 +142,7 @@ public class CmsDeployment implements NodeDeployment { private void addStandardSystemRoles(UserAdmin userAdmin) { // we assume UserTransaction is already available (TODO make it more robust) - UserTransaction userTransaction = bc.getService(bc.getServiceReference(UserTransaction.class)); + WorkTransaction userTransaction = bc.getService(bc.getServiceReference(WorkTransaction.class)); try { userTransaction.begin(); Role adminRole = userAdmin.getRole(NodeConstants.ROLE_ADMIN); @@ -180,7 +177,6 @@ public class CmsDeployment implements NodeDeployment { // if (nodeHttp != null) // nodeHttp.destroy(); - try { JettyConfigurator.stopServer(KernelConstants.DEFAULT_JETTY_SERVER); } catch (Exception e) { @@ -236,7 +232,6 @@ public class CmsDeployment implements NodeDeployment { } } - @Override public synchronized Long getAvailableSince() { return availableSince; @@ -246,5 +241,4 @@ public class CmsDeployment implements NodeDeployment { return availableSince != null; } - } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java index fc9ea7dd7..219f2d53c 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java @@ -8,15 +8,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -import javax.transaction.TransactionManager; -import javax.transaction.UserTransaction; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.api.NodeConstants; import org.argeo.api.NodeState; import org.argeo.cms.LocaleUtils; -import org.argeo.transaction.simple.SimpleTransactionManager; +import org.argeo.osgi.transaction.SimpleTransactionManager; +import org.argeo.osgi.transaction.WorkControl; +import org.argeo.osgi.transaction.WorkTransaction; import org.argeo.util.LangUtils; import org.osgi.framework.Constants; import org.osgi.service.cm.ManagedServiceFactory; @@ -117,8 +116,10 @@ public class CmsState implements NodeState { private void initSimpleTransactionManager() { SimpleTransactionManager transactionManager = new SimpleTransactionManager(); - Activator.registerService(TransactionManager.class, transactionManager, null); - Activator.registerService(UserTransaction.class, transactionManager, null); + Activator.registerService(WorkControl.class, transactionManager, null); + Activator.registerService(WorkTransaction.class, transactionManager, null); +// Activator.registerService(TransactionManager.class, transactionManager, null); +// Activator.registerService(UserTransaction.class, transactionManager, null); // TODO TransactionSynchronizationRegistry } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java index 1a9817450..86c6c9c31 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java @@ -25,7 +25,6 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.kerberos.KerberosPrincipal; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; -import javax.transaction.TransactionManager; import org.apache.commons.httpclient.auth.AuthPolicy; import org.apache.commons.httpclient.auth.CredentialsProvider; @@ -38,6 +37,7 @@ import org.argeo.api.NodeConstants; import org.argeo.cms.internal.http.client.HttpCredentialProvider; import org.argeo.cms.internal.http.client.SpnegoAuthScheme; import org.argeo.naming.DnsBrowser; +import org.argeo.osgi.transaction.WorkControl; import org.argeo.osgi.useradmin.AbstractUserDirectory; import org.argeo.osgi.useradmin.AggregatingUserAdmin; import org.argeo.osgi.useradmin.LdapUserAdmin; @@ -72,7 +72,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor // private ServiceRegistration userAdminReg; // JTA - private final ServiceTracker tmTracker; + private final ServiceTracker tmTracker; // private final String cacheName = UserDirectory.class.getName(); // GSS API @@ -86,7 +86,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor super(systemRolesBaseDn, tokensBaseDn); BundleContext bc = Activator.getBundleContext(); if (bc != null) { - tmTracker = new ServiceTracker<>(bc, TransactionManager.class, null); + tmTracker = new ServiceTracker<>(bc, WorkControl.class, null); tmTracker.open(); } else { tmTracker = null; @@ -194,10 +194,10 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor protected void postAdd(AbstractUserDirectory userDirectory) { // JTA - TransactionManager tm = tmTracker != null ? tmTracker.getService() : null; + WorkControl tm = tmTracker != null ? tmTracker.getService() : null; if (tm == null) throw new IllegalStateException("A JTA transaction manager must be available."); - userDirectory.setTransactionManager(tm); + userDirectory.setTransactionControl(tm); // if (tmTracker.getService() instanceof BitronixTransactionManager) // EhCacheXAResourceProducer.registerXAResource(cacheName, userDirectory.getXaResource()); diff --git a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java index 126125b85..8432ce999 100644 --- a/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java +++ b/org.argeo.enterprise/ext/test/org/argeo/osgi/useradmin/LdifUserAdminTest.java @@ -16,10 +16,8 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; -import javax.transaction.TransactionManager; - import org.argeo.naming.LdapAttrs; -import org.argeo.transaction.simple.SimpleTransactionManager; +import org.argeo.osgi.transaction.SimpleTransactionManager; import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Group; import org.osgi.service.useradmin.Role; @@ -36,7 +34,7 @@ public class LdifUserAdminTest extends TestCase implements BasicTestConstants { final static int TM_BITRONIX = 1; private int tmType = TM_SIMPLE; - private TransactionManager tm; + private SimpleTransactionManager tm; private URI uri; private AbstractUserDirectory userAdmin; private Path tempDir; @@ -171,7 +169,7 @@ public class LdifUserAdminTest extends TestCase implements BasicTestConstants { } } - private AbstractUserDirectory initUserAdmin(URI uri, TransactionManager tm) { + private AbstractUserDirectory initUserAdmin(URI uri, SimpleTransactionManager tm) { Dictionary props = new Hashtable<>(); props.put(UserAdminConf.uri.name(), uri.toString()); props.put(UserAdminConf.baseDn.name(), BASE_DN); @@ -186,7 +184,7 @@ public class LdifUserAdminTest extends TestCase implements BasicTestConstants { // JTA // if (TM_BITRONIX == tmType) // EhCacheXAResourceProducer.registerXAResource(UserDirectory.class.getName(), userAdmin.getXaResource()); - userAdmin.setTransactionManager(tm); + userAdmin.setTransactionControl(tm); return userAdmin; } diff --git a/org.argeo.enterprise/src/org/argeo/osgi/transaction/JtaStatusAdapter.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/JtaStatusAdapter.java new file mode 100644 index 000000000..2dd94c654 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/JtaStatusAdapter.java @@ -0,0 +1,61 @@ +package org.argeo.osgi.transaction; + +/** JTA transaction status. */ +public class JtaStatusAdapter implements TransactionStatusAdapter { + 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.enterprise/src/org/argeo/osgi/transaction/SimpleRollbackException.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleRollbackException.java new file mode 100644 index 000000000..cf8a80b83 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleRollbackException.java @@ -0,0 +1,15 @@ +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.enterprise/src/org/argeo/transaction/simple/SimpleTransaction.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransaction.java similarity index 55% rename from org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransaction.java rename to org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransaction.java index 43d4cd91c..e668b317e 100644 --- a/org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransaction.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransaction.java @@ -1,77 +1,77 @@ -package org.argeo.transaction.simple; +package org.argeo.osgi.transaction; import java.util.ArrayList; import java.util.List; -import javax.transaction.HeuristicMixedException; -import javax.transaction.HeuristicRollbackException; -import javax.transaction.RollbackException; -import javax.transaction.Status; -import javax.transaction.Synchronization; -import javax.transaction.SystemException; -import javax.transaction.Transaction; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; -/** Simple implementation of an XA {@link Transaction}. */ -class SimpleTransaction implements Transaction, Status { +/** Simple implementation of an XA transaction. */ +class SimpleTransaction +//implements Transaction, Status +{ private final Xid xid; - private int status = Status.STATUS_ACTIVE; + private T status; private final List xaResources = new ArrayList(); private final SimpleTransactionManager transactionManager; + private TransactionStatusAdapter tsa; - public SimpleTransaction(SimpleTransactionManager transactionManager) { + public SimpleTransaction(SimpleTransactionManager transactionManager, TransactionStatusAdapter tsa) { + this.tsa = tsa; + this.status = tsa.getActiveStatus(); this.xid = new UuidXid(); this.transactionManager = transactionManager; } - @Override - public synchronized void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, - SecurityException, IllegalStateException, SystemException { - status = STATUS_PREPARING; + public synchronized void commit() +// throws RollbackException, HeuristicMixedException, HeuristicRollbackException, +// SecurityException, IllegalStateException, SystemException + { + status = tsa.getPreparingStatus(); for (XAResource xaRes : xaResources) { - if (status == STATUS_MARKED_ROLLBACK) + if (status.equals(tsa.getMarkedRollbackStatus())) break; try { xaRes.prepare(xid); } catch (XAException e) { - status = STATUS_MARKED_ROLLBACK; + status = tsa.getMarkedRollbackStatus(); error("Cannot prepare " + xaRes + " for " + xid, e); } } - if (status == STATUS_MARKED_ROLLBACK) { + if (status.equals(tsa.getMarkedRollbackStatus())) { rollback(); - throw new RollbackException(); + throw new SimpleRollbackException(); } - status = STATUS_PREPARED; + status = tsa.getPreparedStatus(); - status = STATUS_COMMITTING; + status = tsa.getCommittingStatus(); for (XAResource xaRes : xaResources) { - if (status == STATUS_MARKED_ROLLBACK) + if (status.equals(tsa.getMarkedRollbackStatus())) break; try { xaRes.commit(xid, false); } catch (XAException e) { - status = STATUS_MARKED_ROLLBACK; + status = tsa.getMarkedRollbackStatus(); error("Cannot prepare " + xaRes + " for " + xid, e); } } - if (status == STATUS_MARKED_ROLLBACK) { + if (status.equals(tsa.getMarkedRollbackStatus())) { rollback(); - throw new RollbackException(); + throw new SimpleRollbackException(); } // complete - status = STATUS_COMMITTED; + status = tsa.getCommittedStatus(); clearResources(XAResource.TMSUCCESS); transactionManager.unregister(xid); } - @Override - public synchronized void rollback() throws IllegalStateException, SystemException { - status = STATUS_ROLLING_BACK; + public synchronized void rollback() +// throws IllegalStateException, SystemException + { + status = tsa.getRollingBackStatus(); for (XAResource xaRes : xaResources) { try { xaRes.rollback(xid); @@ -81,14 +81,14 @@ class SimpleTransaction implements Transaction, Status { } // complete - status = STATUS_ROLLEDBACK; + status = tsa.getRolledBackStatus(); clearResources(XAResource.TMFAIL); transactionManager.unregister(xid); } - @Override public synchronized boolean enlistResource(XAResource xaRes) - throws RollbackException, IllegalStateException, SystemException { +// throws RollbackException, IllegalStateException, SystemException + { if (xaResources.add(xaRes)) { try { xaRes.start(getXid(), XAResource.TMNOFLAGS); @@ -101,9 +101,9 @@ class SimpleTransaction implements Transaction, Status { return false; } - @Override public synchronized boolean delistResource(XAResource xaRes, int flag) - throws IllegalStateException, SystemException { +// throws IllegalStateException, SystemException + { if (xaResources.remove(xaRes)) { try { xaRes.end(getXid(), flag); @@ -131,20 +131,21 @@ class SimpleTransaction implements Transaction, Status { e.printStackTrace(); } - @Override - public synchronized int getStatus() throws SystemException { + public synchronized T getStatus() +// throws SystemException + { return status; } - @Override - public void registerSynchronization(Synchronization sync) - throws RollbackException, IllegalStateException, SystemException { - throw new UnsupportedOperationException(); - } +// public void registerSynchronization(Synchronization sync) +// throws RollbackException, IllegalStateException, SystemException { +// throw new UnsupportedOperationException(); +// } - @Override - public void setRollbackOnly() throws IllegalStateException, SystemException { - status = STATUS_MARKED_ROLLBACK; + public void setRollbackOnly() +// throws IllegalStateException, SystemException + { + status = tsa.getMarkedRollbackStatus(); } @Override diff --git a/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransactionManager.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransactionManager.java new file mode 100644 index 000000000..3d4edfd17 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/SimpleTransactionManager.java @@ -0,0 +1,214 @@ +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> current = new ThreadLocal>(); + + private Map> knownTransactions = Collections + .synchronizedMap(new HashMap>()); + private TransactionStatusAdapter tsa = new JtaStatusAdapter(); +// private SyncRegistry syncRegistry = new SyncRegistry(); + + /* + * WORK IMPLEMENTATION + */ + @Override + public T required(Callable 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 transaction = new SimpleTransaction(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 getTransaction() +// throws SystemException + { + return getCurrent(); + } + + protected SimpleTransaction getCurrent() +// throws SystemException + { + SimpleTransaction 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 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 suspend() +// throws SystemException + { + SimpleTransaction 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.enterprise/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java new file mode 100644 index 000000000..87abceba4 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/TransactionStatusAdapter.java @@ -0,0 +1,22 @@ +package org.argeo.osgi.transaction; + +/** Abstract the various approaches to represent transaction status. */ +public interface TransactionStatusAdapter { + T getActiveStatus(); + + T getPreparingStatus(); + + T getMarkedRollbackStatus(); + + T getPreparedStatus(); + + T getCommittingStatus(); + + T getCommittedStatus(); + + T getRollingBackStatus(); + + T getRolledBackStatus(); + + T getNoTransactionStatus(); +} diff --git a/org.argeo.enterprise/src/org/argeo/transaction/simple/UuidXid.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/UuidXid.java similarity index 98% rename from org.argeo.enterprise/src/org/argeo/transaction/simple/UuidXid.java rename to org.argeo.enterprise/src/org/argeo/osgi/transaction/UuidXid.java index 1009c8200..729aef8e5 100644 --- a/org.argeo.enterprise/src/org/argeo/transaction/simple/UuidXid.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/UuidXid.java @@ -1,4 +1,4 @@ -package org.argeo.transaction.simple; +package org.argeo.osgi.transaction; import java.io.Serializable; import java.nio.ByteBuffer; diff --git a/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkContext.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkContext.java new file mode 100644 index 000000000..f50f20870 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkContext.java @@ -0,0 +1,11 @@ +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.enterprise/src/org/argeo/osgi/transaction/WorkControl.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkControl.java new file mode 100644 index 000000000..766809555 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkControl.java @@ -0,0 +1,15 @@ +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 required(Callable work); + + void setRollbackOnly(); + + WorkContext getWorkContext(); +} diff --git a/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkTransaction.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkTransaction.java new file mode 100644 index 000000000..653390912 --- /dev/null +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/WorkTransaction.java @@ -0,0 +1,15 @@ +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.enterprise/src/org/argeo/transaction/simple/package-info.java b/org.argeo.enterprise/src/org/argeo/osgi/transaction/package-info.java similarity index 65% rename from org.argeo.enterprise/src/org/argeo/transaction/simple/package-info.java rename to org.argeo.enterprise/src/org/argeo/osgi/transaction/package-info.java index 19adecc49..3d3756243 100644 --- a/org.argeo.enterprise/src/org/argeo/transaction/simple/package-info.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/transaction/package-info.java @@ -1,2 +1,2 @@ /** Minimalistic and partial XA transaction manager implementation. */ -package org.argeo.transaction.simple; \ No newline at end of file +package org.argeo.osgi.transaction; \ No newline at end of file diff --git a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java index f2d7c88fc..7279877e0 100644 --- a/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.enterprise/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -27,11 +27,9 @@ import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; -import javax.transaction.SystemException; -import javax.transaction.Transaction; -import javax.transaction.TransactionManager; import org.argeo.naming.LdapAttrs; +import org.argeo.osgi.transaction.WorkControl; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; @@ -64,8 +62,9 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory private List credentialAttributeIds = Arrays .asList(new String[] { LdapAttrs.userPassword.name(), LdapAttrs.authPassword.name() }); - // JTA - private TransactionManager transactionManager; + // Transaction +// private TransactionManager transactionManager; + private WorkControl transactionControl; private WcXaResource xaResource = new WcXaResource(this); AbstractUserDirectory(URI uriArg, Dictionary props, boolean scoped) { @@ -142,17 +141,18 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory } protected void checkEdit() { - Transaction transaction; - try { - transaction = transactionManager.getTransaction(); - } catch (SystemException e) { - throw new UserDirectoryException("Cannot get transaction", e); - } - if (transaction == null) - throw new UserDirectoryException("A transaction needs to be active in order to edit"); +// Transaction transaction; +// try { +// transaction = transactionManager.getTransaction(); +// } catch (SystemException e) { +// throw new UserDirectoryException("Cannot get transaction", e); +// } +// if (transaction == null) +// throw new UserDirectoryException("A transaction needs to be active in order to edit"); if (xaResource.wc() == null) { try { - transaction.enlistResource(xaResource); +// transaction.enlistResource(xaResource); + transactionControl.getWorkContext().registerXAResource(xaResource, null); } catch (Exception e) { throw new UserDirectoryException("Cannot enlist " + xaResource, e); } @@ -490,8 +490,12 @@ public abstract class AbstractUserDirectory implements UserAdmin, UserDirectory this.externalRoles = externalRoles; } - public void setTransactionManager(TransactionManager transactionManager) { - this.transactionManager = transactionManager; +// public void setTransactionManager(TransactionManager transactionManager) { +// this.transactionManager = transactionManager; +// } + + public void setTransactionControl(WorkControl transactionControl) { + this.transactionControl = transactionControl; } public WcXaResource getXaResource() { diff --git a/org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransactionManager.java b/org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransactionManager.java deleted file mode 100644 index 7dcf7d99a..000000000 --- a/org.argeo.enterprise/src/org/argeo/transaction/simple/SimpleTransactionManager.java +++ /dev/null @@ -1,170 +0,0 @@ -package org.argeo.transaction.simple; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import javax.transaction.HeuristicMixedException; -import javax.transaction.HeuristicRollbackException; -import javax.transaction.InvalidTransactionException; -import javax.transaction.NotSupportedException; -import javax.transaction.RollbackException; -import javax.transaction.Status; -import javax.transaction.Synchronization; -import javax.transaction.SystemException; -import javax.transaction.Transaction; -import javax.transaction.TransactionManager; -import javax.transaction.TransactionSynchronizationRegistry; -import javax.transaction.UserTransaction; -import javax.transaction.xa.Xid; - -/** - * Simple implementation of an XA {@link TransactionManager} and - * {@link UserTransaction}. - */ -public class SimpleTransactionManager implements TransactionManager, UserTransaction { - private ThreadLocal current = new ThreadLocal(); - - private Map knownTransactions = Collections - .synchronizedMap(new HashMap()); - private SyncRegistry syncRegistry = new SyncRegistry(); - - @Override - public void begin() throws NotSupportedException, SystemException { - if (getCurrent() != null) - throw new NotSupportedException("Nested transactions are not supported"); - SimpleTransaction transaction = new SimpleTransaction(this); - knownTransactions.put(transaction.getXid(), transaction); - current.set(transaction); - } - - @Override - 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(); - } - - @Override - public int getStatus() throws SystemException { - if (getCurrent() == null) - return Status.STATUS_NO_TRANSACTION; - return getTransaction().getStatus(); - } - - @Override - public Transaction getTransaction() throws SystemException { - return getCurrent(); - } - - protected SimpleTransaction getCurrent() throws SystemException { - SimpleTransaction transaction = current.get(); - if (transaction == null) - return null; - int status = transaction.getStatus(); - if (Status.STATUS_COMMITTED == status || Status.STATUS_ROLLEDBACK == status) { - current.remove(); - return null; - } - return transaction; - } - - void unregister(Xid xid) { - knownTransactions.remove(xid); - } - - @Override - public void resume(Transaction tobj) throws InvalidTransactionException, IllegalStateException, SystemException { - if (getCurrent() != null) - throw new IllegalStateException("Transaction " + current.get() + " already registered"); - current.set((SimpleTransaction) tobj); - } - - @Override - public void rollback() throws IllegalStateException, SecurityException, SystemException { - if (getCurrent() == null) - throw new IllegalStateException("No transaction registered with the current thread."); - getCurrent().rollback(); - } - - @Override - public void setRollbackOnly() throws IllegalStateException, SystemException { - if (getCurrent() == null) - throw new IllegalStateException("No transaction registered with the current thread."); - getCurrent().setRollbackOnly(); - } - - @Override - public void setTransactionTimeout(int seconds) throws SystemException { - throw new UnsupportedOperationException(); - } - - @Override - public Transaction suspend() throws SystemException { - Transaction 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/pom.xml b/pom.xml index c4d70f610..88ab72780 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.maven @@ -19,7 +21,7 @@ org.argeo.enterprise - + org.argeo.osgi.boot org.argeo.core @@ -27,7 +29,7 @@ org.argeo.eclipse.ui.rap org.argeo.api - + org.argeo.cms org.argeo.cms.jcr org.argeo.cms.ui.theme @@ -96,6 +98,11 @@ org.argeo.tp.misc slf4j.osgi + + + org.argeo.tp.javax + javax.transaction-api + -- 2.30.2