You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2016/10/10 14:46:19 UTC

svn commit: r1764108 - in /aries/trunk/tx-control: ./ tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ tx-control-provider-common/ tx-control-provider-common/src/ tx-control-provider-common/src/main/ tx-control-provider-common/src/ma...

Author: timothyjward
Date: Mon Oct 10 14:46:18 2016
New Revision: 1764108

URL: http://svn.apache.org/viewvc?rev=1764108&view=rev
Log:
ARIES-1616 Factor out resource provider independent common code

Added:
    aries/trunk/tx-control/tx-control-provider-common/
    aries/trunk/tx-control/tx-control-provider-common/pom.xml
    aries/trunk/tx-control/tx-control-provider-common/src/
    aries/trunk/tx-control/tx-control-provider-common/src/main/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactory.java
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/LifecycleAware.java
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivator.java
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactory.java
    aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactory.java
    aries/trunk/tx-control/tx-control-provider-common/src/test/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactoryTest.java
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivatorTest.java
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactoryTest.java
    aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactoryTest.java
Removed:
    aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/JDBCConnectionProviderFactoryServiceFactory.java
Modified:
    aries/trunk/tx-control/pom.xml
    aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
    aries/trunk/tx-control/tx-control-provider-jdbc-common/pom.xml
    aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
    aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
    aries/trunk/tx-control/tx-control-provider-jdbc-local/bnd.bnd
    aries/trunk/tx-control/tx-control-provider-jdbc-local/pom.xml
    aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
    aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
    aries/trunk/tx-control/tx-control-provider-jdbc-xa/bnd.bnd
    aries/trunk/tx-control/tx-control-provider-jdbc-xa/pom.xml
    aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
    aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
    aries/trunk/tx-control/tx-control-provider-jpa-xa/bnd.bnd

Modified: aries/trunk/tx-control/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/pom.xml?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/pom.xml (original)
+++ aries/trunk/tx-control/pom.xml Mon Oct 10 14:46:18 2016
@@ -182,4 +182,7 @@
 			</plugins>
 		</pluginManagement>
 	</build>
+	<modules>
+		<module>tx-control-provider-common</module>
+	</modules>
 </project>
\ No newline at end of file

Modified: aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java (original)
+++ aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java Mon Oct 10 14:46:18 2016
@@ -61,6 +61,8 @@ import org.osgi.service.transaction.cont
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 import org.osgi.util.tracker.ServiceTracker;
 
+import junit.framework.AssertionFailedError;
+
 @RunWith(PaxExam.class)
 @ExamReactorStrategy(PerClass.class)
 public abstract class AbstractTransactionTest {
@@ -195,6 +197,25 @@ public abstract class AbstractTransactio
 
 		if(isConfigured()) {
 			clearConfiguration();
+			ServiceTracker<JDBCConnectionProvider, JDBCConnectionProvider> tracker = new ServiceTracker<>(context, JDBCConnectionProvider.class, null);
+			tracker.open();
+			for(int i = 0;; i++) {
+				if(i == 10) {
+					throw new AssertionFailedError("The JDBCConnectionProvider was not unregistered");
+				}
+				
+				if(tracker.getService() == null) {
+					break;
+				} else {
+					try {
+						Thread.sleep(250);
+					} catch (InterruptedException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				}
+			}
+			tracker.close();
 		}
 		
 		if(server != null) {

Added: aries/trunk/tx-control/tx-control-provider-common/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/pom.xml?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/pom.xml (added)
+++ aries/trunk/tx-control/tx-control-provider-common/pom.xml Mon Oct 10 14:46:18 2016
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.aries.tx-control</groupId>
+		<artifactId>tx-control</artifactId>
+		<version>0.0.2-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<groupId>org.apache.aries.tx-control</groupId>
+	<artifactId>tx-control-provider-common</artifactId>
+	<packaging>jar</packaging>
+	<name>OSGi Transaction Control Resource Provider - Common Code</name>
+	<version>0.0.2-SNAPSHOT</version>
+	
+	<description>
+        This jar contains a common code for building OSGi Transaction Control ResourceProvider 
+        implementations. It is not complete and should not be deployed at runtime, instead it should 
+        be repackaged inside a complete implementation.
+    </description>
+    
+    <scm>
+        <connection>
+            scm:svn:http://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-provider-common
+        </connection>
+        <developerConnection>
+            scm:svn:https://svn.apache.org/repos/asf/aries/trunk/tx-control/tx-control-provider-common
+        </developerConnection>
+        <url>
+            http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common
+        </url>
+    </scm>
+
+    <dependencies>
+        <!-- Internal Aries project dependencies -->
+        <dependency>
+            <groupId>org.apache.aries.tx-control</groupId>
+            <artifactId>tx-control-api</artifactId>
+            <version>0.0.2-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        
+        <!-- OSGi dependencies -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.util.tracker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.cm</artifactId>
+        </dependency>
+        
+        <!-- Logging dependencies -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

Added: aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactory.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactory.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactory.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.tx.control.resource.common.impl;
+
+import static java.util.Optional.ofNullable;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ConfigurationDefinedResourceFactory implements ManagedServiceFactory {
+
+	private static final Logger LOG = LoggerFactory.getLogger(ConfigurationDefinedResourceFactory.class);
+	
+	private final Map<String, LifecycleAware> managedInstances = new ConcurrentHashMap<>();
+
+	private final BundleContext context;
+
+	public ConfigurationDefinedResourceFactory(BundleContext context) {
+		this.context = context;
+	}
+
+	@Override
+	public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
+
+		Map<String, Object> propsMap = new HashMap<>();
+
+		Enumeration<String> keys = properties.keys();
+		while (keys.hasMoreElements()) {
+			String key = keys.nextElement();
+			propsMap.put(key, properties.get(key));
+		}
+
+		try {
+			LifecycleAware existing = managedInstances.get(pid);
+			
+			LifecycleAware cdr;
+			if(existing != null) {
+				if(existing.update(propsMap)) {
+					LOG.debug("The Configuration driven resource with pid {} updated successfully", pid);
+					return;
+				}
+				closeCDR(pid, existing);
+				
+				cdr = getConfigurationDrivenResource(context, pid, propsMap);
+				if(!managedInstances.replace(pid, existing, cdr)) {
+					// We lost this race
+					return;
+				}
+			} else {
+				cdr = getConfigurationDrivenResource(context, pid, propsMap);
+				if(managedInstances.putIfAbsent(pid, cdr) != null) {
+					// We lost this race
+					return;
+				}
+			}
+			
+			cdr.start();
+		} catch (Exception e) {
+			LOG.error("The configuration driven resource for pid {} encountered a failure", pid, e);
+			
+			if(e instanceof ConfigurationException) {
+				throw (ConfigurationException) e;
+			} else {
+				throw new ConfigurationException(null, "A failure occured configuring the resource for pid " + pid, e);
+			}
+		}
+	}
+
+	protected abstract LifecycleAware getConfigurationDrivenResource(BundleContext context, 
+			String pid, Map<String, Object> properties) throws Exception;
+
+	public void stop() {
+		managedInstances.entrySet().forEach(e -> closeCDR(e.getKey(), e.getValue()));
+	}
+	
+	private void closeCDR(String pid, LifecycleAware cdr) {
+		try {
+			cdr.stop();
+		} catch (Exception ex) {
+			LOG.warn("There was an error stopping Configuration Driven Resource {}", pid, ex);
+		}
+	}
+
+	@Override
+	public void deleted(String pid) {
+		ofNullable(managedInstances.remove(pid))
+			.ifPresent(cdr -> closeCDR(pid, cdr));
+	}
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/LifecycleAware.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/LifecycleAware.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/LifecycleAware.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/LifecycleAware.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.tx.control.resource.common.impl;
+
+import java.util.Map;
+
+/**
+ * This interface is used to control the lifecycle of configuration driven
+ * resources
+ */
+public interface LifecycleAware {
+
+	/**
+	 * Start the configuration-driven resource. This method will
+	 * be called once, and must fail if the resource has already
+	 * started or been stopped.
+	 * @throws Exception
+	 */
+	public void start() throws Exception;
+	
+	/**
+	 * Update the configuration-driven resource. Must fail
+	 * (either with false or an exception) if the resource
+	 * is closed.
+	 * 
+	 * @return false if the configuration driven resource could
+	 *  not be updated and should be destroyed/recreated
+	 * @throws Exception
+	 */
+	public default boolean update(Map<String, Object> properties) throws Exception {
+		return false;
+	};
+	
+	/**
+	 * Close the configuration driven resource, either because the 
+	 * configuration was deleted, the bundle is stopping, or an update 
+	 * could not be dynamically applied.
+	 * 
+	 * Repeated calls to close should have no effect
+	 * 
+	 * @throws Exception
+	 */
+	public void stop() throws Exception;
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivator.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivator.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivator.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivator.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.tx.control.resource.common.impl;
+
+import static org.osgi.framework.Constants.SERVICE_PID;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ResourceActivator<R extends AutoCloseable, F extends TrackingResourceProviderFactory<R>> implements BundleActivator {
+
+	private static final Logger LOG = LoggerFactory.getLogger(ResourceActivator.class);
+	
+	private ResourceProviderFactoryServiceFactory<R, F> service;
+	private ConfigurationDefinedResourceFactory msf;
+	
+	private ServiceRegistration<?> reg;
+	private ServiceRegistration<ManagedServiceFactory> factoryReg;
+	
+	@Override
+	public void start(BundleContext context) throws Exception {
+		
+		service = getServiceFactory(context);
+		
+		if(service != null) {
+			reg = context.registerService(getAdvertisedInterface().getName(), 
+					service, getServiceProperties());
+		}
+		
+		msf = getConfigurationDefinedResourceFactory(context);
+		
+		if(msf != null) {
+			factoryReg = context.registerService(ManagedServiceFactory.class, 
+					msf, getMSFProperties());
+		}
+		
+		if(service == null && msf == null) {
+			LOG.warn("The Resource Activator class {} defined no service factory or configuration defined resources", getClass().getName());
+		}
+	}
+
+	@Override
+	public void stop(BundleContext context) throws Exception {
+		safeUnregister(reg);
+		safeUnregister(factoryReg);
+		if(msf != null) {
+			try {
+				msf.stop();
+			} catch (Exception e) {
+				LOG.error("There was an error closing the Configuration Defined Resource Manager", e);
+			}
+		}
+		if(service != null) {
+			try {
+				service.close();
+			} catch (Exception e) {
+				LOG.error("There was an error closing the ResourceProviderFactory", e);
+			}
+		}
+	}
+
+	private void safeUnregister(ServiceRegistration<?> reg) {
+		if(reg != null) {
+			try {
+				reg.unregister();
+			} catch (IllegalStateException ise) {
+				// Ignore this
+			}
+		}
+	}
+
+	protected Dictionary<String, ?> getMSFProperties() {
+		Dictionary<String, Object> props = new Hashtable<>();
+		props.put(SERVICE_PID, getMSFPid());
+		return props;
+	}
+
+	protected ResourceProviderFactoryServiceFactory<R, F> getServiceFactory(BundleContext context) {
+		return null;
+	}
+
+	protected Class<? super F> getAdvertisedInterface() {
+		throw new UnsupportedOperationException("Resource factories are not supported");
+	}
+	
+	protected Dictionary<String, Object> getServiceProperties() {
+		throw new UnsupportedOperationException("Resource factories are not supported");
+	}
+
+	protected ConfigurationDefinedResourceFactory getConfigurationDefinedResourceFactory(
+			BundleContext context) {
+		return null;
+	}
+	
+	protected String getMSFPid() {
+		throw new UnsupportedOperationException("Configuration defined resources are not supported");
+	}
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactory.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactory.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactory.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,39 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+public abstract class ResourceProviderFactoryServiceFactory<R extends AutoCloseable,
+	T extends TrackingResourceProviderFactory<R>> implements 
+	ServiceFactory<TrackingResourceProviderFactory<R>> {
+
+	Set<TrackingResourceProviderFactory<R>> factories = new CopyOnWriteArraySet<>();
+	
+	@Override
+	public TrackingResourceProviderFactory<R> getService(Bundle bundle,
+			ServiceRegistration<TrackingResourceProviderFactory<R>> registration) {
+		TrackingResourceProviderFactory<R> factory = 
+						getTrackingResourceManagerProviderFactory();
+		factories.add(factory);
+		return factory;
+	}
+
+	@Override
+	public void ungetService(Bundle bundle, ServiceRegistration<TrackingResourceProviderFactory<R>> registration,
+			TrackingResourceProviderFactory<R> service) {
+		factories.remove(service);
+		service.closeAll();
+	}
+	
+	public void close() {
+		factories.stream()
+			.forEach(r -> r.closeAll());
+	}
+	
+	protected abstract TrackingResourceProviderFactory<R> 
+		getTrackingResourceManagerProviderFactory();
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactory.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactory.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/main/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactory.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,64 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.osgi.framework.ServiceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class TrackingResourceProviderFactory<T extends AutoCloseable> {
+
+	private static final Logger LOG = LoggerFactory.getLogger(TrackingResourceProviderFactory.class);
+	
+	private final List<T> toClose = new ArrayList<>();
+	
+	private boolean closed;
+	
+	protected T doGetResult(Callable<T> getter) {
+		synchronized (getter) {
+			if (closed) {
+				throw new IllegalStateException("This ResourceProvider has been reclaimed because the factory service that provided it was released");
+			}
+		}
+		T t;
+		try {
+			t = getter.call();
+		} catch (Exception e) {
+			LOG.warn("A failure occurred obtaining the resource provider", e);
+			throw new ServiceException("A failure occurred obtaining the resource provider", e);
+		}
+		boolean destroy = false;
+		synchronized (toClose) {
+			if (closed) {
+				destroy = true;
+			} else {
+			    toClose.add(t);
+			}
+		}
+		if(destroy) {
+			try {
+				t.close();
+			} catch (Exception e) {
+				LOG.warn("A failure occurred closing the resource provider", e);
+			}
+			throw new IllegalStateException("This ResourceProvider has been reclaimed because the factory service that provided it was released");
+		}
+		return t;
+	}
+
+	public void closeAll() {
+		synchronized (toClose) {
+			closed = true;
+		}
+		// toClose is now up to date and no other thread will write it
+		toClose.stream().forEach(ajcp -> {
+			try {
+				ajcp.close();
+			} catch (Exception e) {}
+		});
+		
+		toClose.clear();
+	}
+}
\ No newline at end of file

Added: aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactoryTest.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactoryTest.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ConfigurationDefinedResourceFactoryTest.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,100 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import static org.mockito.Mockito.anyMapOf;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ConfigurationDefinedResourceFactoryTest {
+
+	private final class ConfigurationDefinedResourceFactoryExtension extends ConfigurationDefinedResourceFactory {
+		private ConfigurationDefinedResourceFactoryExtension(BundleContext context) {
+			super(context);
+		}
+
+		@Override
+		public String getName() {
+			return "Test";
+		}
+
+		@Override
+		protected LifecycleAware getConfigurationDrivenResource(BundleContext context, String pid,
+				Map<String, Object> properties) throws Exception {
+			switch(pid) {
+				case "a": return resourceA;
+				case "b": return resourceB;
+				default: throw new IllegalArgumentException(pid);
+			}
+		}
+	}
+
+	@Mock
+	BundleContext ctx;
+	
+	@Mock
+	LifecycleAware resourceA;
+	
+	@Mock
+	LifecycleAware resourceB;
+	
+	@Test
+	public void testLifecycleStop() throws Exception {
+		ConfigurationDefinedResourceFactory cdrf = new ConfigurationDefinedResourceFactoryExtension(ctx);
+		
+		cdrf.updated("a", new Hashtable<>());
+		Mockito.verify(resourceA).start();
+		
+		cdrf.stop();
+		Mockito.verify(resourceA).stop();
+	}
+	
+	@Test
+	public void testLifecycleDelete() throws Exception {
+		ConfigurationDefinedResourceFactory cdrf = new ConfigurationDefinedResourceFactoryExtension(ctx);
+		
+		cdrf.updated("a", new Hashtable<>());
+		Mockito.verify(resourceA).start();
+		
+		cdrf.deleted("a");
+		
+		Mockito.verify(resourceA).stop();
+		
+		cdrf.stop();
+		Mockito.verify(resourceA).stop();
+	}
+
+	@Test
+	public void testLifecycleUpdate() throws Exception {
+		
+		Mockito.when(resourceB.update(anyMapOf(String.class, Object.class))).thenReturn(true);
+		
+		ConfigurationDefinedResourceFactory cdrf = new ConfigurationDefinedResourceFactoryExtension(ctx);
+		
+		cdrf.updated("a", new Hashtable<>());
+		Mockito.verify(resourceA).start();
+		cdrf.updated("b", new Hashtable<>());
+		Mockito.verify(resourceB).start();
+		
+		cdrf.updated("a", new Hashtable<>());
+		Mockito.verify(resourceA).stop();
+		Mockito.verify(resourceA, times(2)).start();
+		
+		cdrf.updated("b", new Hashtable<>());
+		Mockito.verify(resourceB, never()).stop();
+
+		
+		cdrf.stop();
+		Mockito.verify(resourceA, times(2)).stop();
+		Mockito.verify(resourceB).stop();
+	}
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivatorTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivatorTest.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivatorTest.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceActivatorTest.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,205 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import static org.hamcrest.CoreMatchers.both;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Matchers.eq;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourceActivatorTest {
+
+	@Mock
+	BundleContext ctx;
+	
+	@Mock
+	ResourceProviderFactoryServiceFactory<AutoCloseable, TrackingResourceProviderFactory<AutoCloseable>> serviceFactory;
+
+	@SuppressWarnings("rawtypes")
+	@Mock
+	ServiceRegistration providerReg;
+	
+	@Mock
+	ConfigurationDefinedResourceFactory configDrivenResourceFactory;
+
+	@Mock
+	ServiceRegistration<ManagedServiceFactory> msfReg;
+	
+	@Test
+	public void testLifecycleNoServiceOrMSF() throws Exception {
+		ResourceActivator<?,?> ra = new ResourceActivator<AutoCloseable,
+				TrackingResourceProviderFactory<AutoCloseable>>() {
+		};
+		
+		ra.start(ctx);
+		ra.stop(ctx);
+		
+		Mockito.verifyNoMoreInteractions(ctx);
+	}
+
+	@SuppressWarnings("unchecked")
+	@Test
+	public void testLifecycleNoMSF() throws Exception {
+		
+		Mockito.when(ctx.registerService(eq(TrackingResourceProviderFactory.class.getName()), 
+				any(), argThat(both(hasKeyValue("foo", "bar")).and(hasKeyValue("fizz", 42)))))
+					.thenReturn(providerReg);
+		
+		ResourceActivator<?,?> ra = new ResourceActivator<AutoCloseable,
+				TrackingResourceProviderFactory<AutoCloseable>>() {
+					@Override
+					protected ResourceProviderFactoryServiceFactory<AutoCloseable, TrackingResourceProviderFactory<AutoCloseable>> getServiceFactory(
+							BundleContext context) {
+						return serviceFactory;
+					}
+
+					@Override
+					protected Class<? super TrackingResourceProviderFactory<AutoCloseable>> getAdvertisedInterface() {
+						return TrackingResourceProviderFactory.class;
+					}
+
+					@Override
+					protected Dictionary<String, Object> getServiceProperties() {
+						Hashtable<String, Object> table = new Hashtable<>();
+						table.put("foo", "bar");
+						table.put("fizz", 42);
+						return table;
+					}
+			};
+		
+		ra.start(ctx);
+		
+		ra.stop(ctx);
+		
+		Mockito.verify(providerReg).unregister();
+		Mockito.verify(serviceFactory).close();
+	}
+
+	@Test
+	public void testLifecycleNoService() throws Exception {
+		
+		Mockito.when(ctx.registerService(eq(ManagedServiceFactory.class), 
+				any(), argThat(hasKeyValue(Constants.SERVICE_PID, "foo.bar.baz"))))
+		.thenReturn(msfReg);
+		
+		ResourceActivator<?,?> ra = new ResourceActivator<AutoCloseable,
+				TrackingResourceProviderFactory<AutoCloseable>>() {
+
+					@Override
+					protected ConfigurationDefinedResourceFactory getConfigurationDefinedResourceFactory(
+							BundleContext context) {
+						return configDrivenResourceFactory;
+					}
+
+					@Override
+					protected String getMSFPid() {
+						return "foo.bar.baz";
+					}
+		};
+		
+		ra.start(ctx);
+		
+		ra.stop(ctx);
+		
+		Mockito.verify(msfReg).unregister();
+		Mockito.verify(configDrivenResourceFactory).stop();
+	}
+	
+	@SuppressWarnings("unchecked")
+	@Test
+	public void testLifecycleBothServiceAndMSF() throws Exception {
+		Mockito.when(ctx.registerService(eq(TrackingResourceProviderFactory.class.getName()), 
+				any(), argThat(both(hasKeyValue("foo", "bar")).and(hasKeyValue("fizz", 42)))))
+					.thenReturn(providerReg);
+		
+		Mockito.when(ctx.registerService(eq(ManagedServiceFactory.class), 
+				any(), argThat(hasKeyValue(Constants.SERVICE_PID, "foo.bar.baz"))))
+		.thenReturn(msfReg);
+		
+		ResourceActivator<?,?> ra = new ResourceActivator<AutoCloseable,
+				TrackingResourceProviderFactory<AutoCloseable>>() {
+					@Override
+					protected ResourceProviderFactoryServiceFactory<AutoCloseable, TrackingResourceProviderFactory<AutoCloseable>> getServiceFactory(
+							BundleContext context) {
+						return serviceFactory;
+					}
+
+					@Override
+					protected Class<? super TrackingResourceProviderFactory<AutoCloseable>> getAdvertisedInterface() {
+						return TrackingResourceProviderFactory.class;
+					}
+
+					@Override
+					protected Dictionary<String, Object> getServiceProperties() {
+						Hashtable<String, Object> table = new Hashtable<>();
+						table.put("foo", "bar");
+						table.put("fizz", 42);
+						return table;
+					}
+					
+					@Override
+					protected ConfigurationDefinedResourceFactory getConfigurationDefinedResourceFactory(
+							BundleContext context) {
+						return configDrivenResourceFactory;
+					}
+
+					@Override
+					protected String getMSFPid() {
+						return "foo.bar.baz";
+					}
+			};
+		
+		ra.start(ctx);
+		
+		ra.stop(ctx);
+		
+		Mockito.verify(providerReg).unregister();
+		Mockito.verify(serviceFactory).close();
+		
+		Mockito.verify(msfReg).unregister();
+		Mockito.verify(configDrivenResourceFactory).stop();
+	}
+
+
+	static Matcher<Dictionary<String, Object>> hasKeyValue(String key, Object value) {
+		return new DictionaryMatcher(key, value);
+	}
+	
+	
+	private static class DictionaryMatcher extends TypeSafeDiagnosingMatcher<Dictionary<String, Object>> {
+
+		private final String key;
+		private final Object value;
+		
+		public DictionaryMatcher(String key, Object value) {
+			this.key = key;
+			this.value = value;
+		}
+
+		@Override
+		protected boolean matchesSafely(Dictionary<String, Object> map, Description mismatchDescription) {
+			return value.equals(map.get(key));
+		}
+
+		@Override
+		public void describeTo(Description description) {
+			description.appendText("Map entry: " + key + "=" + value);
+		}
+		
+	}
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactoryTest.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactoryTest.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/ResourceProviderFactoryServiceFactoryTest.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,83 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.Bundle;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ResourceProviderFactoryServiceFactoryTest {
+
+	@Mock
+	Bundle b1;
+
+	@Mock
+	Bundle b2;
+	
+	List<TrackingResourceProviderFactory<AutoCloseable>> factories = new ArrayList<>();
+
+	@Mock
+	TrackingResourceProviderFactory<AutoCloseable> factory2;
+
+	@Test
+	public void testLifecycleClose() throws Exception {
+		ResourceProviderFactoryServiceFactory<?,?> rpfsf = new ResourceProviderFactoryServiceFactory<
+				AutoCloseable, TrackingResourceProviderFactory<AutoCloseable>>() {
+
+					@SuppressWarnings({ "rawtypes", "unchecked" })
+					@Override
+					protected TrackingResourceProviderFactory<AutoCloseable> getTrackingResourceManagerProviderFactory() {
+						TrackingResourceProviderFactory mock = Mockito.mock(TrackingResourceProviderFactory.class);
+						factories.add(mock);
+						return mock;
+					}
+		};
+		
+		rpfsf.getService(b1, null);
+		rpfsf.getService(b2, null);
+		
+		
+		rpfsf.close();
+		
+		for(TrackingResourceProviderFactory<AutoCloseable> t : factories) {
+			Mockito.verify(t).closeAll();
+		}
+	}
+
+	@Test
+	public void testLifecycleCloseWithUnget() throws Exception {
+		ResourceProviderFactoryServiceFactory<AutoCloseable, 
+				TrackingResourceProviderFactory<AutoCloseable>> rpfsf = 
+				new ResourceProviderFactoryServiceFactory<
+				AutoCloseable, TrackingResourceProviderFactory<AutoCloseable>>() {
+			
+			@SuppressWarnings({ "rawtypes", "unchecked" })
+			@Override
+			protected TrackingResourceProviderFactory<AutoCloseable> getTrackingResourceManagerProviderFactory() {
+				TrackingResourceProviderFactory mock = Mockito.mock(TrackingResourceProviderFactory.class);
+				factories.add(mock);
+				return mock;
+			}
+		};
+		
+		rpfsf.getService(b1, null);
+		TrackingResourceProviderFactory<AutoCloseable> tf = rpfsf.getService(b2, null);
+		
+		rpfsf.ungetService(b2, null, tf);
+		
+		Mockito.verify(tf).closeAll();
+		
+		factories.remove(tf);
+		
+		rpfsf.close();
+		
+		for(TrackingResourceProviderFactory<AutoCloseable> t : factories) {
+			Mockito.verify(t).closeAll();
+		}
+	}
+}

Added: aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactoryTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactoryTest.java?rev=1764108&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactoryTest.java (added)
+++ aries/trunk/tx-control/tx-control-provider-common/src/test/java/org/apache/aries/tx/control/resource/common/impl/TrackingResourceProviderFactoryTest.java Mon Oct 10 14:46:18 2016
@@ -0,0 +1,19 @@
+package org.apache.aries.tx.control.resource.common.impl;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class TrackingResourceProviderFactoryTest {
+
+	@Test
+	public void testLifecycleClose() throws Exception {
+		TrackingResourceProviderFactory<AutoCloseable> trpf = new TrackingResourceProviderFactory<AutoCloseable>(){};
+		
+		AutoCloseable result = trpf.doGetResult(() -> Mockito.mock(AutoCloseable.class));
+		
+		
+		trpf.closeAll();
+		
+		Mockito.verify(result).close();
+	}
+}

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-common/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/pom.xml?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-common/pom.xml (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-common/pom.xml Mon Oct 10 14:46:18 2016
@@ -57,6 +57,12 @@
             <version>0.0.2-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.aries.tx-control</groupId>
+            <artifactId>tx-control-provider-common</artifactId>
+            <version>0.0.2-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
         
         <!-- OSGi dependencies -->
         <dependency>

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/AbstractJDBCConnectionProvider.java Mon Oct 10 14:46:18 2016
@@ -28,7 +28,7 @@ import org.osgi.service.transaction.cont
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractJDBCConnectionProvider implements JDBCConnectionProvider {
+public abstract class AbstractJDBCConnectionProvider implements JDBCConnectionProvider, AutoCloseable {
 
 	private static final Logger LOG = LoggerFactory.getLogger(AbstractJDBCConnectionProvider.class);
 	

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-common/src/main/java/org/apache/aries/tx/control/jdbc/common/impl/ResourceTrackingJDBCConnectionProviderFactory.java Mon Oct 10 14:46:18 2016
@@ -1,28 +1,23 @@
 package org.apache.aries.tx.control.jdbc.common.impl;
 
 import java.sql.Driver;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.function.Supplier;
 
 import javax.sql.DataSource;
 import javax.sql.XADataSource;
 
+import org.apache.aries.tx.control.resource.common.impl.TrackingResourceProviderFactory;
 import org.osgi.service.jdbc.DataSourceFactory;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 
-class ResourceTrackingJDBCConnectionProviderFactory implements
-	JDBCConnectionProviderFactory {
+public class ResourceTrackingJDBCConnectionProviderFactory extends 
+	TrackingResourceProviderFactory<AbstractJDBCConnectionProvider>
+	implements JDBCConnectionProviderFactory {
 
-	private final List<AbstractJDBCConnectionProvider> toClose = new ArrayList<>();
-	
 	private final InternalJDBCConnectionProviderFactory factory;
 	
-	private boolean closed;
-	
 	public ResourceTrackingJDBCConnectionProviderFactory(InternalJDBCConnectionProviderFactory factory) {
 		this.factory = factory;
 	}
@@ -52,40 +47,4 @@ class ResourceTrackingJDBCConnectionProv
 		return doGetResult(() -> factory.getProviderFor(ds, 
 				resourceProviderProperties));
 	}
-	
-	private AbstractJDBCConnectionProvider doGetResult(Supplier<AbstractJDBCConnectionProvider> getter) {
-		synchronized (getter) {
-			if (closed) {
-				throw new IllegalStateException("This ResourceProvider has been reclaimed because the factory service that provided it was released");
-			}
-		}
-		AbstractJDBCConnectionProvider ajcp = getter.get();
-		boolean destroy = false;
-		synchronized (toClose) {
-			if (closed) {
-				destroy = true;
-			} else {
-			    toClose.add(ajcp);
-			}
-		}
-		if(destroy) {
-			ajcp.close();
-			throw new IllegalStateException("This ResourceProvider has been reclaimed because the factory service that provided it was released");
-		}
-		return ajcp;
-	}
-
-	public void closeAll() {
-		synchronized (toClose) {
-			closed = true;
-		}
-		// toClose is now up to date and no other thread will write it
-		toClose.stream().forEach(ajcp -> {
-			try {
-				ajcp.close();
-			} catch (Exception e) {}
-		});
-		
-		toClose.clear();
-	}
 }
\ No newline at end of file

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-local/bnd.bnd
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/bnd.bnd?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-local/bnd.bnd (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-local/bnd.bnd Mon Oct 10 14:46:18 2016
@@ -28,6 +28,7 @@ Export-Package: org.osgi.service.transac
 # as a single bundle. We also embed Hikari CP to avoid dependency fanout
 
 Private-Package: org.apache.aries.tx.control.jdbc.*, \
+                 org.apache.aries.tx.control.resource.common.impl, \
                  com.zaxxer.hikari, \
                  com.zaxxer.hikari.metrics, \
                  com.zaxxer.hikari.pool, \

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-local/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/pom.xml?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-local/pom.xml (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-local/pom.xml Mon Oct 10 14:46:18 2016
@@ -57,6 +57,12 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.aries.tx-control</groupId>
+			<artifactId>tx-control-provider-common</artifactId>
+			<version>0.0.2-SNAPSHOT</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.aries.tx-control</groupId>
 			<artifactId>tx-control-provider-jdbc-common</artifactId>
 			<version>0.0.2-SNAPSHOT</version>
 			<scope>provided</scope>

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Activator.java Mon Oct 10 14:46:18 2016
@@ -18,69 +18,52 @@
  */
 package org.apache.aries.tx.control.jdbc.local.impl;
 
-import static org.osgi.framework.Constants.SERVICE_PID;
-
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
-import org.apache.aries.tx.control.jdbc.common.impl.JDBCConnectionProviderFactoryServiceFactory;
-import org.osgi.framework.BundleActivator;
+import org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
+import org.apache.aries.tx.control.jdbc.common.impl.ResourceTrackingJDBCConnectionProviderFactory;
+import org.apache.aries.tx.control.resource.common.impl.ConfigurationDefinedResourceFactory;
+import org.apache.aries.tx.control.resource.common.impl.ResourceActivator;
+import org.apache.aries.tx.control.resource.common.impl.ResourceProviderFactoryServiceFactory;
+import org.apache.aries.tx.control.resource.common.impl.TrackingResourceProviderFactory;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.ManagedServiceFactory;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 
-public class Activator implements BundleActivator {
-
-	private ServiceRegistration<?> reg;
-	private ServiceRegistration<ManagedServiceFactory> factoryReg;
-	private JDBCConnectionProviderFactoryServiceFactory service;
-	private ManagedServiceFactoryImpl msf;
+public class Activator extends ResourceActivator<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory> {
 	
 	@Override
-	public void start(BundleContext context) throws Exception {
-		
-		InternalJDBCConnectionProviderFactory ijcpf = new JDBCConnectionProviderFactoryImpl();
-		
-		service = new JDBCConnectionProviderFactoryServiceFactory() {
+	protected ResourceProviderFactoryServiceFactory<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory> getServiceFactory(
+			BundleContext context) {
+		return new ResourceProviderFactoryServiceFactory<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory>() {
 			@Override
-			protected InternalJDBCConnectionProviderFactory getInternalJDBCConnectionProviderFactory() {
-				return ijcpf;
+			protected TrackingResourceProviderFactory<AbstractJDBCConnectionProvider> getTrackingResourceManagerProviderFactory() {
+				return new ResourceTrackingJDBCConnectionProviderFactory(
+						new JDBCConnectionProviderFactoryImpl());
 			}
 		};
-		reg = context.registerService(JDBCConnectionProviderFactory.class.getName(), 
-				service, getProperties());
-		
-		msf = new ManagedServiceFactoryImpl(context);
-		factoryReg = context.registerService(ManagedServiceFactory.class, 
-				msf, getMSFProperties());
 	}
 
 	@Override
-	public void stop(BundleContext context) throws Exception {
-		safeUnregister(reg);
-		safeUnregister(factoryReg);
-		service.close();
-		msf.stop();
+	protected Class<? super ResourceTrackingJDBCConnectionProviderFactory> getAdvertisedInterface() {
+		return JDBCConnectionProviderFactory.class;
 	}
 
-	private void safeUnregister(ServiceRegistration<?> reg) {
-		try {
-			reg.unregister();
-		} catch (IllegalStateException ise) {}
-	}
-
-	private Dictionary<String, Object> getProperties() {
+	@Override
+	protected Dictionary<String, Object> getServiceProperties() {
 		Dictionary<String, Object> props = new Hashtable<>();
 		props.put("osgi.local.enabled", Boolean.TRUE);
 		return props;
 	}
 
-	private Dictionary<String, ?> getMSFProperties() {
-		Dictionary<String, Object> props = new Hashtable<>();
-		props.put(SERVICE_PID, "org.apache.aries.tx.control.jdbc.local");
-		return props;
+	@Override
+	protected ConfigurationDefinedResourceFactory getConfigurationDefinedResourceFactory(
+			BundleContext context) {
+		return new ManagedServiceFactoryImpl(context);
 	}
 
+	@Override
+	protected String getMSFPid() {
+		return "org.apache.aries.tx.control.jdbc.local";
+	}
 }

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java Mon Oct 10 14:46:18 2016
@@ -19,7 +19,6 @@
 package org.apache.aries.tx.control.jdbc.local.impl;
 
 import static java.util.Arrays.asList;
-import static java.util.Optional.ofNullable;
 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;
@@ -36,22 +35,20 @@ import static org.osgi.service.jdbc.Data
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
+import org.apache.aries.tx.control.resource.common.impl.ConfigurationDefinedResourceFactory;
+import org.apache.aries.tx.control.resource.common.impl.LifecycleAware;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedServiceFactory;
 import org.osgi.service.jdbc.DataSourceFactory;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProvider;
 import org.osgi.util.tracker.ServiceTracker;
@@ -59,7 +56,7 @@ import org.osgi.util.tracker.ServiceTrac
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ManagedServiceFactoryImpl implements ManagedServiceFactory {
+public class ManagedServiceFactoryImpl extends ConfigurationDefinedResourceFactory {
 
 	private static final Logger LOG = LoggerFactory.getLogger(ManagedServiceFactoryImpl.class);
 	
@@ -69,12 +66,8 @@ public class ManagedServiceFactoryImpl i
 			JDBC_DESCRIPTION, JDBC_NETWORK_PROTOCOL, JDBC_PASSWORD, JDBC_PORT_NUMBER, JDBC_ROLE_NAME, JDBC_SERVER_NAME,
 			JDBC_URL, JDBC_USER);
 
-	private final Map<String, ManagedJDBCResourceProvider> managedInstances = new ConcurrentHashMap<>();
-
-	private final BundleContext context;
-
 	public ManagedServiceFactoryImpl(BundleContext context) {
-		this.context = context;
+		super(context);
 	}
 
 	@Override
@@ -83,32 +76,18 @@ public class ManagedServiceFactoryImpl i
 	}
 
 	@Override
-	public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
-
-		Map<String, Object> propsMap = new HashMap<>();
-
-		Enumeration<String> keys = properties.keys();
-		while (keys.hasMoreElements()) {
-			String key = keys.nextElement();
-			propsMap.put(key, properties.get(key));
-		}
-
-		Properties jdbcProps = getJdbcProps(pid, propsMap);
-
+	protected LifecycleAware getConfigurationDrivenResource(BundleContext context, 
+			String pid, Map<String, Object> properties) throws Exception {
+		Properties jdbcProps = getJdbcProps(pid, properties);
+	
 		try {
-			ManagedJDBCResourceProvider mjrp = new ManagedJDBCResourceProvider(context, pid, jdbcProps, propsMap);
-			ofNullable(managedInstances.put(pid, mjrp)).ifPresent(ManagedJDBCResourceProvider::stop);
-			mjrp.start();
+			return new ManagedJDBCResourceProvider(context, pid, jdbcProps, properties);
 		} catch (InvalidSyntaxException e) {
 			LOG.error("The configuration {} contained an invalid target filter {}", pid, e.getFilter());
 			throw new ConfigurationException(DSF_TARGET_FILTER, "The target filter was invalid", e);
 		}
 	}
 
-	public void stop() {
-		managedInstances.values().forEach(ManagedJDBCResourceProvider::stop);
-	}
-
 	@SuppressWarnings("unchecked")
 	private Properties getJdbcProps(String pid, Map<String, Object> properties) throws ConfigurationException {
 
@@ -134,14 +113,8 @@ public class ManagedServiceFactoryImpl i
 		return p;
 	}
 
-	@Override
-	public void deleted(String pid) {
-		ofNullable(managedInstances.remove(pid))
-			.ifPresent(ManagedJDBCResourceProvider::stop);
-	}
-
 	private static class ManagedJDBCResourceProvider
-			implements ServiceTrackerCustomizer<DataSourceFactory, DataSourceFactory> {
+			implements ServiceTrackerCustomizer<DataSourceFactory, DataSourceFactory>, LifecycleAware {
 
 		private final BundleContext context;
 		private final String pid;

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-xa/bnd.bnd
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/bnd.bnd?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/bnd.bnd (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/bnd.bnd Mon Oct 10 14:46:18 2016
@@ -28,6 +28,7 @@ Export-Package: org.osgi.service.transac
 # as a single bundle. We also embed Hikari CP to avoid dependency fanout
 
 Private-Package: org.apache.aries.tx.control.jdbc.*, \
+                 org.apache.aries.tx.control.resource.common.impl, \
                  com.zaxxer.hikari, \
                  com.zaxxer.hikari.metrics, \
                  com.zaxxer.hikari.pool, \

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-xa/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/pom.xml?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/pom.xml (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/pom.xml Mon Oct 10 14:46:18 2016
@@ -56,6 +56,12 @@
         </dependency>
         <dependency>
             <groupId>org.apache.aries.tx-control</groupId>
+            <artifactId>tx-control-provider-common</artifactId>
+            <version>0.0.2-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.tx-control</groupId>
             <artifactId>tx-control-provider-jdbc-common</artifactId>
             <version>0.0.2-SNAPSHOT</version>
             <scope>provided</scope>

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Activator.java Mon Oct 10 14:46:18 2016
@@ -18,70 +18,53 @@
  */
 package org.apache.aries.tx.control.jdbc.xa.impl;
 
-import static org.osgi.framework.Constants.SERVICE_PID;
-
 import java.util.Dictionary;
 import java.util.Hashtable;
 
-import org.apache.aries.tx.control.jdbc.common.impl.InternalJDBCConnectionProviderFactory;
-import org.apache.aries.tx.control.jdbc.common.impl.JDBCConnectionProviderFactoryServiceFactory;
-import org.osgi.framework.BundleActivator;
+import org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
+import org.apache.aries.tx.control.jdbc.common.impl.ResourceTrackingJDBCConnectionProviderFactory;
+import org.apache.aries.tx.control.resource.common.impl.ConfigurationDefinedResourceFactory;
+import org.apache.aries.tx.control.resource.common.impl.ResourceActivator;
+import org.apache.aries.tx.control.resource.common.impl.ResourceProviderFactoryServiceFactory;
+import org.apache.aries.tx.control.resource.common.impl.TrackingResourceProviderFactory;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.ManagedServiceFactory;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
 
-public class Activator implements BundleActivator {
+public class Activator extends ResourceActivator<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory> {
 
-	private ServiceRegistration<JDBCConnectionProviderFactory> reg;
-	private ServiceRegistration<ManagedServiceFactory> factoryReg;
-	private JDBCConnectionProviderFactoryServiceFactory service;
-	private ManagedServiceFactoryImpl msf;
 	
 	@Override
-	public void start(BundleContext context) throws Exception {
-		InternalJDBCConnectionProviderFactory ijcpf = new JDBCConnectionProviderFactoryImpl();
-		
-		service = new JDBCConnectionProviderFactoryServiceFactory() {
+	protected ResourceProviderFactoryServiceFactory<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory> getServiceFactory(
+			BundleContext context) {
+		return new ResourceProviderFactoryServiceFactory<AbstractJDBCConnectionProvider, ResourceTrackingJDBCConnectionProviderFactory>() {
 			@Override
-			protected InternalJDBCConnectionProviderFactory getInternalJDBCConnectionProviderFactory() {
-				return ijcpf;
+			protected TrackingResourceProviderFactory<AbstractJDBCConnectionProvider> getTrackingResourceManagerProviderFactory() {
+				return new ResourceTrackingJDBCConnectionProviderFactory(
+						new JDBCConnectionProviderFactoryImpl());
 			}
 		};
-		
-		reg = context.registerService(JDBCConnectionProviderFactory.class, 
-				new JDBCConnectionProviderFactoryImpl(), getProperties());
-		
-		msf = new ManagedServiceFactoryImpl(context);
-		factoryReg = context.registerService(ManagedServiceFactory.class, 
-				msf, getMSFProperties());
 	}
 
 	@Override
-	public void stop(BundleContext context) throws Exception {
-		safeUnregister(reg);
-		safeUnregister(factoryReg);
-		service.close();
-		msf.stop();
+	protected Class<? super ResourceTrackingJDBCConnectionProviderFactory> getAdvertisedInterface() {
+		return JDBCConnectionProviderFactory.class;
 	}
 
-	private void safeUnregister(ServiceRegistration<?> reg) {
-		try {
-			reg.unregister();
-		} catch (IllegalStateException ise) {}
-	}
-	
-	private Dictionary<String, Object> getProperties() {
+	@Override
+	protected Dictionary<String, Object> getServiceProperties() {
 		Dictionary<String, Object> props = new Hashtable<>();
 		props.put("osgi.local.enabled", Boolean.TRUE);
 		props.put("osgi.xa.enabled", Boolean.TRUE);
 		return props;
 	}
 
-	private Dictionary<String, ?> getMSFProperties() {
-		Dictionary<String, Object> props = new Hashtable<>();
-		props.put(SERVICE_PID, "org.apache.aries.tx.control.jdbc.xa");
-		return props;
+	@Override
+	protected ConfigurationDefinedResourceFactory getConfigurationDefinedResourceFactory(BundleContext context) {
+		return new ManagedServiceFactoryImpl(context);
 	}
 
+	@Override
+	protected String getMSFPid() {
+		return "org.apache.aries.tx.control.jdbc.xa";
+	}
 }

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/ManagedServiceFactoryImpl.java Mon Oct 10 14:46:18 2016
@@ -19,7 +19,6 @@
 package org.apache.aries.tx.control.jdbc.xa.impl;
 
 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;
@@ -39,21 +38,19 @@ import static org.osgi.service.transacti
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.aries.tx.control.jdbc.common.impl.AbstractJDBCConnectionProvider;
+import org.apache.aries.tx.control.resource.common.impl.ConfigurationDefinedResourceFactory;
+import org.apache.aries.tx.control.resource.common.impl.LifecycleAware;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
-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;
@@ -62,7 +59,7 @@ import org.osgi.util.tracker.ServiceTrac
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ManagedServiceFactoryImpl implements ManagedServiceFactory {
+public class ManagedServiceFactoryImpl extends ConfigurationDefinedResourceFactory {
 
 	private static final Logger LOG = LoggerFactory.getLogger(ManagedServiceFactoryImpl.class);
 	
@@ -72,12 +69,8 @@ public class ManagedServiceFactoryImpl i
 			JDBC_DESCRIPTION, JDBC_NETWORK_PROTOCOL, JDBC_PASSWORD, JDBC_PORT_NUMBER, JDBC_ROLE_NAME, JDBC_SERVER_NAME,
 			JDBC_URL, JDBC_USER);
 
-	private final Map<String, ManagedJDBCResourceProvider> managedInstances = new ConcurrentHashMap<>();
-
-	private final BundleContext context;
-
 	public ManagedServiceFactoryImpl(BundleContext context) {
-		this.context = context;
+		super(context);
 	}
 
 	@Override
@@ -86,32 +79,18 @@ public class ManagedServiceFactoryImpl i
 	}
 
 	@Override
-	public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
-
-		Map<String, Object> propsMap = new HashMap<>();
-
-		Enumeration<String> keys = properties.keys();
-		while (keys.hasMoreElements()) {
-			String key = keys.nextElement();
-			propsMap.put(key, properties.get(key));
-		}
-
-		Properties jdbcProps = getJdbcProps(pid, propsMap);
-
+	protected LifecycleAware getConfigurationDrivenResource(BundleContext context, 
+			String pid, Map<String, Object> properties) throws Exception {
+		Properties jdbcProps = getJdbcProps(pid, properties);
+	
 		try {
-			ManagedJDBCResourceProvider mjrp = new ManagedJDBCResourceProvider(context, pid, jdbcProps, propsMap);
-			ofNullable(managedInstances.put(pid, mjrp)).ifPresent(ManagedJDBCResourceProvider::stop);
-			mjrp.start();
+			return new ManagedJDBCResourceProvider(context, pid, jdbcProps, properties);
 		} catch (InvalidSyntaxException e) {
 			LOG.error("The configuration {} contained an invalid target filter {}", pid, e.getFilter());
 			throw new ConfigurationException(DSF_TARGET_FILTER, "The target filter was invalid", e);
 		}
 	}
 
-	public void stop() {
-		managedInstances.values().forEach(ManagedJDBCResourceProvider::stop);
-	}
-
 	@SuppressWarnings("unchecked")
 	private Properties getJdbcProps(String pid, Map<String, Object> properties) throws ConfigurationException {
 
@@ -137,14 +116,8 @@ public class ManagedServiceFactoryImpl i
 		return p;
 	}
 
-	@Override
-	public void deleted(String pid) {
-		ofNullable(managedInstances.remove(pid))
-			.ifPresent(ManagedJDBCResourceProvider::stop);
-	}
-
 	private static class ManagedJDBCResourceProvider
-			implements ServiceTrackerCustomizer<DataSourceFactory, DataSourceFactory> {
+			implements ServiceTrackerCustomizer<DataSourceFactory, DataSourceFactory>, LifecycleAware {
 
 		private final BundleContext context;
 		private final String pid;

Modified: aries/trunk/tx-control/tx-control-provider-jpa-xa/bnd.bnd
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jpa-xa/bnd.bnd?rev=1764108&r1=1764107&r2=1764108&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jpa-xa/bnd.bnd (original)
+++ aries/trunk/tx-control/tx-control-provider-jpa-xa/bnd.bnd Mon Oct 10 14:46:18 2016
@@ -40,6 +40,7 @@ Export-Package: org.osgi.service.transac
 
 Private-Package: org.apache.aries.tx.control.jdbc.common.impl, \
                  org.apache.aries.tx.control.jdbc.xa.connection.impl, \
+                 org.apache.aries.tx.control.resource.common.impl, \
                  org.apache.aries.tx.control.jpa.*, \
                  org.apache.geronimo.osgi.locator, \
                  org.apache.geronimo.specs.jpa, \