[tx-control] Add recovery support to the XA JDBC provider
git-svn-id: https://svn.apache.org/repos/asf/aries/trunk/tx-control@1751616 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tx-control-api/src/main/java/org/osgi/service/transaction/control/jdbc/JDBCConnectionProviderFactory.java b/tx-control-api/src/main/java/org/osgi/service/transaction/control/jdbc/JDBCConnectionProviderFactory.java
index 89321d1..fac8ccb 100644
--- a/tx-control-api/src/main/java/org/osgi/service/transaction/control/jdbc/JDBCConnectionProviderFactory.java
+++ b/tx-control-api/src/main/java/org/osgi/service/transaction/control/jdbc/JDBCConnectionProviderFactory.java
@@ -86,6 +86,11 @@
* held in the pool
*/
public static final String USE_DRIVER = "osgi.use.driver";
+
+ /**
+ * The property used to set the recovery identifier that should be used
+ */
+ public static String OSGI_RECOVERY_IDENTIFIER = "osgi.recovery.identifier";
/**
* Create a private {@link JDBCConnectionProvider} using a
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Config.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Config.java
index cb71589..635f790 100644
--- a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Config.java
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Config.java
@@ -34,6 +34,10 @@
description="The password to pass to the DataSourceFactory (not visible as a service property)")
String password();
+ // Recovery configuration
+ @AttributeDefinition(required=false, description="The recovery identifier for this resource. If not set then this resource will not be recoverable. This identifier must uniquely identify a single resource, and must not change if the framework is restarted.")
+ String osgi_recovery_identifier();
+
// Pool configuration properties
@AttributeDefinition(required=false, description="Is connection pooling enabled for this JDBCResourceProvider")
@@ -54,6 +58,15 @@
@AttributeDefinition(required=false, description="The maximum time (in ms) that a connection will stay in the pool before being discarded")
long osgi_connection_lifetime() default 10800000;
+ // Recovery credential configuration
+
+ @AttributeDefinition(required=false, description="The user that should be used for recovery. If not specified then recovery will use the same user credentials as normal operation")
+ String recovery_user();
+
+ @AttributeDefinition(type=AttributeType.PASSWORD, required=false,
+ description="The password that should be used for recovery. Only used if recovery.user is specified")
+ String _recovery_password();
+
// Transaction integration configuration
@AttributeDefinition(required=false, description="Should this Resource participate in transactions using XA")
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
index 9118ad2..28204db 100644
--- a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderFactoryImpl.java
@@ -38,14 +38,18 @@
import org.osgi.service.transaction.control.TransactionException;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class JDBCConnectionProviderFactoryImpl implements JDBCConnectionProviderFactory {
+ private static final Logger LOG = LoggerFactory.getLogger(ManagedServiceFactoryImpl.class);
+
@Override
- public JDBCConnectionProvider getProviderFor(DataSourceFactory dsf, Properties jdbcProperties,
+ public JDBCConnectionProviderImpl getProviderFor(DataSourceFactory dsf, Properties jdbcProperties,
Map<String, Object> resourceProviderProperties) {
boolean xaEnabled = toBoolean(resourceProviderProperties, XA_ENLISTMENT_ENABLED, true);
@@ -69,8 +73,21 @@
}
DataSource toUse = poolIfNecessary(resourceProviderProperties, unpooled);
+
+ return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled,
+ getRecoveryId(resourceProviderProperties, xaEnabled));
+ }
- return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled);
+ private String getRecoveryId(Map<String, Object> resourceProviderProps, boolean xaEnabled) {
+ String recoveryIdentifier = ofNullable(resourceProviderProps)
+ .map(m -> m.get(OSGI_RECOVERY_IDENTIFIER))
+ .map(String::valueOf)
+ .orElse(null);
+
+ if(recoveryIdentifier != null && !xaEnabled) {
+ LOG.warn("A recovery identifier {} has been declared, but the JDBCConnectionProvider is configured to disable XA", recoveryIdentifier);
+ }
+ return recoveryIdentifier;
}
@Override
@@ -83,7 +100,8 @@
DataSource toUse = poolIfNecessary(resourceProviderProperties, xaEnabled ?
new XADataSourceMapper(ds.unwrap(XADataSource.class)) : ds);
- return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled);
+ return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled,
+ getRecoveryId(resourceProviderProperties, xaEnabled));
} catch (SQLException sqle) {
throw new TransactionException("Unable to create the JDBC resource provider", sqle);
}
@@ -101,7 +119,8 @@
DataSource toUse = poolIfNecessary(resourceProviderProperties,
new DriverDataSource(driver, jdbcProperties.getProperty(JDBC_URL), jdbcProperties));
- return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled);
+ return new JDBCConnectionProviderImpl(toUse, xaEnabled, localEnabled,
+ getRecoveryId(resourceProviderProperties, xaEnabled));
}
@Override
@@ -115,7 +134,7 @@
DataSource unpooled = new XADataSourceMapper(ds);
return new JDBCConnectionProviderImpl(poolIfNecessary(resourceProviderProperties, unpooled),
- xaEnabled, localEnabled);
+ xaEnabled, localEnabled, getRecoveryId(resourceProviderProperties, xaEnabled));
}
private void checkEnlistment(boolean xaEnabled, boolean localEnabled, boolean isXA) {
@@ -153,7 +172,7 @@
return toUse;
}
- private boolean toBoolean(Map<String, Object> props, String key, boolean defaultValue) {
+ static boolean toBoolean(Map<String, Object> props, String key, boolean defaultValue) {
Object o = ofNullable(props)
.map(m -> m.get(key))
.orElse(defaultValue);
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
index ec95513..9adc9af 100644
--- a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/JDBCConnectionProviderImpl.java
@@ -37,18 +37,25 @@
private final boolean localEnabled;
+ private final String recoveryIdentifier;
+
public JDBCConnectionProviderImpl(DataSource dataSource, boolean xaEnabled,
- boolean localEnabled) {
+ boolean localEnabled, String recoveryIdentifier) {
this.dataSource = dataSource;
this.xaEnabled = xaEnabled;
this.localEnabled = localEnabled;
+ this.recoveryIdentifier = recoveryIdentifier;
}
@Override
public Connection getResource(TransactionControl txControl)
throws TransactionException {
return new XAEnabledTxContextBindingConnection(txControl, dataSource , uuid,
- xaEnabled, localEnabled);
+ xaEnabled, localEnabled, recoveryIdentifier);
+ }
+
+ public DataSource getRawDataSource() {
+ return dataSource;
}
}
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
index ee18aa1..7f0ac5d 100644
--- a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
@@ -20,6 +20,7 @@
import static java.util.Arrays.asList;
import static java.util.Optional.ofNullable;
+import static org.apache.aries.tx.control.jdbc.xa.impl.JDBCConnectionProviderFactoryImpl.toBoolean;
import static org.osgi.framework.Constants.OBJECTCLASS;
import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATABASE_NAME;
import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATASOURCE_NAME;
@@ -32,6 +33,8 @@
import static org.osgi.service.jdbc.DataSourceFactory.JDBC_URL;
import static org.osgi.service.jdbc.DataSourceFactory.JDBC_USER;
import static org.osgi.service.jdbc.DataSourceFactory.OSGI_JDBC_DRIVER_CLASS;
+import static org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.OSGI_RECOVERY_IDENTIFIER;
+import static org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory.XA_ENLISTMENT_ENABLED;
import java.util.Arrays;
import java.util.Collection;
@@ -43,7 +46,6 @@
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicReference;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
@@ -53,6 +55,7 @@
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.jdbc.DataSourceFactory;
import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
+import org.osgi.service.transaction.control.recovery.RecoverableXAResource;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
@@ -148,8 +151,9 @@
private final Map<String, Object> providerProperties;
private final ServiceTracker<DataSourceFactory, DataSourceFactory> dsfTracker;
- private final AtomicReference<DataSourceFactory> activeDsf = new AtomicReference<>();
- private final AtomicReference<ServiceRegistration<JDBCConnectionProvider>> serviceReg = new AtomicReference<>();
+ private DataSourceFactory activeDsf;
+ private ServiceRegistration<JDBCConnectionProvider> serviceReg;
+ private ServiceRegistration<RecoverableXAResource> recoveryReg;
public ManagedJDBCResourceProvider(BundleContext context, String pid, Properties jdbcProperties,
Map<String, Object> providerProperties) throws InvalidSyntaxException, ConfigurationException {
@@ -185,33 +189,81 @@
@Override
public DataSourceFactory addingService(ServiceReference<DataSourceFactory> reference) {
DataSourceFactory service = context.getService(reference);
+ return updateService(service);
+ }
- updateService(service);
+ private DataSourceFactory updateService(DataSourceFactory service) {
+ boolean setDsf;
+ synchronized (this) {
+ setDsf = activeDsf == null;
+ if(setDsf)
+ activeDsf = service;
+ }
+
+ ServiceRegistration<JDBCConnectionProvider> reg = null;
+ ServiceRegistration<RecoverableXAResource> reg2 = null;
+ if (setDsf) {
+ try {
+ JDBCConnectionProviderImpl provider = new JDBCConnectionProviderFactoryImpl().getProviderFor(service,
+ jdbcProperties, providerProperties);
+ reg = context
+ .registerService(JDBCConnectionProvider.class, provider, getServiceProperties());
+
+
+ String recoveryId = (String) providerProperties.get(OSGI_RECOVERY_IDENTIFIER);
+ if(recoveryId !=null) {
+ if(toBoolean(providerProperties, XA_ENLISTMENT_ENABLED, true)) {
+ LOG.warn("A JDBCResourceProvider has been configured with a recovery identifier {} but it has also been configured not to use XA transactions. No recovery will be available.", recoveryId);
+ } else {
+ reg2 = context.registerService(RecoverableXAResource.class,
+ new RecoverableXAResourceImpl(recoveryId, provider,
+ (String) providerProperties.get("recovery.user"),
+ (String) providerProperties.get(".recovery.password)")),
+ getServiceProperties());
+ }
+ }
+
+ ServiceRegistration<JDBCConnectionProvider> oldReg;
+ ServiceRegistration<RecoverableXAResource> oldReg2;
+
+ synchronized (this) {
+ if(activeDsf == service) {
+ oldReg = serviceReg;
+ serviceReg = reg;
+ oldReg2 = recoveryReg;
+ recoveryReg = reg2;
+ } else {
+ oldReg = reg;
+ oldReg2 = reg2;
+ }
+ }
+ safeUnregister(oldReg);
+ safeUnregister(oldReg2);
+ } catch (Exception e) {
+ LOG.error("An error occurred when creating the connection provider for {}.", pid, e);
+
+ synchronized (this) {
+ if(activeDsf == service) {
+ activeDsf = null;
+ }
+ }
+ safeUnregister(reg);
+ safeUnregister(reg2);
+ }
+ }
return service;
}
- private void updateService(DataSourceFactory service) {
- boolean setDsf;
- synchronized (this) {
- setDsf = activeDsf.compareAndSet(null, service);
- }
-
- if (setDsf) {
+ private void safeUnregister(ServiceRegistration<?> reg) {
+ if(reg != null) {
try {
- JDBCConnectionProvider provider = new JDBCConnectionProviderFactoryImpl().getProviderFor(service,
- jdbcProperties, providerProperties);
- ServiceRegistration<JDBCConnectionProvider> reg = context
- .registerService(JDBCConnectionProvider.class, provider, getServiceProperties());
- if (!serviceReg.compareAndSet(null, reg)) {
- throw new IllegalStateException("Unable to set the JDBC connection provider registration");
- }
- } catch (Exception e) {
- LOG.error("An error occurred when creating the connection provider for {}.", pid, e);
- activeDsf.compareAndSet(service, null);
+ reg.unregister();
+ } catch (IllegalStateException ise) {
+ LOG.debug("An exception occurred when unregistering a service for {}", pid);
}
}
}
-
+
private Dictionary<String, ?> getServiceProperties() {
Hashtable<String, Object> props = new Hashtable<>();
providerProperties.keySet().stream()
@@ -229,20 +281,19 @@
public void removedService(ServiceReference<DataSourceFactory> reference, DataSourceFactory service) {
boolean dsfLeft;
ServiceRegistration<JDBCConnectionProvider> oldReg = null;
+ ServiceRegistration<RecoverableXAResource> oldReg2 = null;
synchronized (this) {
- dsfLeft = activeDsf.compareAndSet(service, null);
+ dsfLeft = activeDsf == service;
if (dsfLeft) {
- oldReg = serviceReg.getAndSet(null);
+ activeDsf = null;
+ oldReg = serviceReg;
+ oldReg2 = recoveryReg;
+ serviceReg = null;
+ recoveryReg = null;
}
}
-
- if (oldReg != null) {
- try {
- oldReg.unregister();
- } catch (IllegalStateException ise) {
- LOG.debug("An exception occurred when unregistering a service for {}", pid);
- }
- }
+ safeUnregister(oldReg);
+ safeUnregister(oldReg2);
if (dsfLeft) {
DataSourceFactory newDSF = dsfTracker.getService();
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/RecoverableXAResourceImpl.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/RecoverableXAResourceImpl.java
new file mode 100644
index 0000000..ea7e0df
--- /dev/null
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/RecoverableXAResourceImpl.java
@@ -0,0 +1,119 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.osgi.service.transaction.control.recovery.RecoverableXAResource;
+
+public class RecoverableXAResourceImpl implements RecoverableXAResource {
+
+ private final String id;
+
+ private final JDBCConnectionProviderImpl providerImpl;
+
+ private final String recoveryUser;
+
+ private final String recoveryPw;
+
+ public RecoverableXAResourceImpl(String id, JDBCConnectionProviderImpl providerImpl, String recoveryUser,
+ String recoveryPw) {
+ this.id = id;
+ this.providerImpl = providerImpl;
+ this.recoveryUser = recoveryUser;
+ this.recoveryPw = recoveryPw;
+ }
+
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public XAResource getXAResource() throws Exception {
+ DataSource rawDataSource = providerImpl.getRawDataSource();
+
+ Connection recoveryConn;
+ if(recoveryUser != null) {
+ recoveryConn = rawDataSource.getConnection(recoveryUser, recoveryPw);
+ } else {
+ recoveryConn = rawDataSource.getConnection();
+ }
+
+ return new CloseableXAResource(recoveryConn);
+ }
+
+ @Override
+ public void releaseXAResource(XAResource xaRes) {
+ if(xaRes instanceof CloseableXAResource) {
+ try {
+ ((CloseableXAResource) xaRes).close();
+ } catch (Exception e) {
+ // This is fine, the connection has been returned
+ }
+ } else {
+ throw new IllegalArgumentException("The XAResource being returned was not created by this provider implementation");
+ }
+ }
+
+ private static class CloseableXAResource implements XAResource, AutoCloseable {
+ private final Connection conn;
+
+ private final XAResource resource;
+
+ public CloseableXAResource(Connection conn) throws SQLException {
+ conn.isValid(5);
+ this.conn = conn;
+ this.resource = XAEnabledTxContextBindingConnection.getXAResource(conn);
+ }
+
+ @Override
+ public void close() throws Exception {
+ conn.close();
+ }
+
+ public void commit(Xid arg0, boolean arg1) throws XAException {
+ resource.commit(arg0, arg1);
+ }
+
+ public void end(Xid arg0, int arg1) throws XAException {
+ resource.end(arg0, arg1);
+ }
+
+ public void forget(Xid arg0) throws XAException {
+ resource.forget(arg0);
+ }
+
+ public int getTransactionTimeout() throws XAException {
+ return resource.getTransactionTimeout();
+ }
+
+ public boolean isSameRM(XAResource arg0) throws XAException {
+ return resource.isSameRM(arg0);
+ }
+
+ public int prepare(Xid arg0) throws XAException {
+ return resource.prepare(arg0);
+ }
+
+ public Xid[] recover(int arg0) throws XAException {
+ return resource.recover(arg0);
+ }
+
+ public void rollback(Xid arg0) throws XAException {
+ resource.rollback(arg0);
+ }
+
+ public boolean setTransactionTimeout(int arg0) throws XAException {
+ return resource.setTransactionTimeout(arg0);
+ }
+
+ public void start(Xid arg0, int arg1) throws XAException {
+ resource.start(arg0, arg1);
+ }
+ }
+}
diff --git a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java
index 764bb0c..78b5d0a 100644
--- a/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java
@@ -43,14 +43,17 @@
private final DataSource dataSource;
private final boolean xaEnabled;
private final boolean localEnabled;
+ private final String recoveryIdentifier;
public XAEnabledTxContextBindingConnection(TransactionControl txControl,
- DataSource dataSource, UUID resourceId, boolean xaEnabled, boolean localEnabled) {
+ DataSource dataSource, UUID resourceId, boolean xaEnabled, boolean localEnabled,
+ String recoveryIdentifier) {
this.txControl = txControl;
this.dataSource = dataSource;
this.resourceId = resourceId;
this.xaEnabled = xaEnabled;
this.localEnabled = localEnabled;
+ this.recoveryIdentifier = recoveryIdentifier;
}
@Override
@@ -79,7 +82,7 @@
} else if (txContext.supportsXA() && xaEnabled) {
toClose = dataSource.getConnection();
toReturn = new TxConnectionWrapper(toClose);
- txContext.registerXAResource(getXAResource(toClose), null);
+ txContext.registerXAResource(getXAResource(toClose), recoveryIdentifier);
} else if (txContext.supportsLocal() && localEnabled) {
toClose = dataSource.getConnection();
toReturn = new TxConnectionWrapper(toClose);
@@ -109,7 +112,7 @@
}
- private XAResource getXAResource(Connection conn) throws SQLException {
+ static XAResource getXAResource(Connection conn) throws SQLException {
if(conn instanceof XAConnectionWrapper) {
return ((XAConnectionWrapper)conn).getXaResource();
} else if(conn.isWrapperFor(XAConnectionWrapper.class)){
diff --git a/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java b/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java
index d447d79..870c6f9 100644
--- a/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java
+++ b/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java
@@ -90,9 +90,9 @@
Mockito.when(xaMock.getConnection()).thenReturn(rawConnection);
Mockito.when(xaMock.getXAResource()).thenReturn(xaResource);
- localConn = new XAEnabledTxContextBindingConnection(control, dataSource, id, false, true);
+ localConn = new XAEnabledTxContextBindingConnection(control, dataSource, id, false, true, null);
xaConn = new XAEnabledTxContextBindingConnection(control, new XADataSourceMapper(xaDataSource),
- id, true, false);
+ id, true, false, null);
}
private void setupNoTransaction() {
diff --git a/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java b/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
index 218f977..c4db2ec 100644
--- a/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
+++ b/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java
@@ -20,6 +20,7 @@
import static org.apache.aries.tx.control.service.xa.impl.Activator.ChangeType.RECREATE;
import static org.apache.aries.tx.control.service.xa.impl.Activator.ChangeType.SERVICE_PROPS;
+import static org.apache.aries.tx.control.service.xa.impl.LocalResourceSupport.DISABLED;
import static org.apache.aries.tx.control.service.xa.impl.LocalResourceSupport.ENFORCE_SINGLE;
import java.io.File;
@@ -221,7 +222,7 @@
.forEach(e -> props.put(e.getKey(), e.getValue()));
props.put("osgi.xa.enabled", Boolean.TRUE);
- props.put("osgi.local.enabled", Boolean.TRUE);
+ props.put("osgi.local.enabled", getLocalResourceSupport() != DISABLED);
props.put(Constants.SERVICE_DESCRIPTION, "The Apache Aries Transaction Control Service for XA Transactions");
props.put(Constants.SERVICE_VENDOR, "Apache Aries");
@@ -237,7 +238,7 @@
* @return
*/
public synchronized ChangeType changed(Map<String, Object> updated, boolean isRegistered) {
- Map<String, Object> current = filterFixedProps(updated);
+ Map<String, Object> current = filterFixedProps(config);
Map<String, Object> replacement = filterFixedProps(updated);
// If our configuration is unchanged then just issue a service property update