[tx-control] Improvements for the Local and XA JDBC ResourceProviders:
 * Add Metatypes
 * Avoid publishing "." properties
 * Ensure that tracked services are DataSourceFactories

git-svn-id: https://svn.apache.org/repos/asf/aries/trunk/tx-control@1751615 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/tx-control-provider-jdbc-local/pom.xml b/tx-control-provider-jdbc-local/pom.xml
index 4e84990..07b0b31 100644
--- a/tx-control-provider-jdbc-local/pom.xml
+++ b/tx-control-provider-jdbc-local/pom.xml
@@ -79,6 +79,10 @@
 			<groupId>org.osgi</groupId>
 			<artifactId>org.osgi.service.jdbc</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.osgi</groupId>
+			<artifactId>org.osgi.service.metatype.annotations</artifactId>
+		</dependency>
 
 		<!-- Hikari CP dependency -->
 		<dependency>
diff --git a/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Config.java b/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Config.java
new file mode 100644
index 0000000..c3e5c32
--- /dev/null
+++ b/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/Config.java
@@ -0,0 +1,90 @@
+package org.apache.aries.tx.control.jdbc.local.impl;
+
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATABASE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATASOURCE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DESCRIPTION;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_NETWORK_PROTOCOL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PASSWORD;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PORT_NUMBER;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_ROLE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_SERVER_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_URL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_USER;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.AttributeType;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@ObjectClassDefinition(factoryPid="org.apache.aries.tx.control.jdbc.local", description="Aries Transaction Control Factory for Local JDBCResourceProvider Services")
+public @interface Config {
+
+	// Most commonly used properties declared first so that they go into the metatype first
+	
+	@AttributeDefinition(required=false, 
+			description="The name of the driver class for the DataSourceFactory service. This property need not be defined if aries.dsf.target.filter is defined.")
+	String osgi_jdbc_driver_class();
+
+	@AttributeDefinition(required=false, description="The JDBC URL to pass to the DataSourceFactory")
+	String url();
+	
+	@AttributeDefinition(required=false, description="The userid to pass to the DataSourceFactory")
+	String user();
+	
+	@AttributeDefinition(type=AttributeType.PASSWORD, required=false, 
+			description="The password to pass to the DataSourceFactory (not visible as a service property)")
+	String password();
+	
+	// Pool configuration properties
+	
+	@AttributeDefinition(required=false, description="Is connection pooling enabled for this JDBCResourceProvider")
+	boolean osgi_connection_pooling_enabled() default true;
+	
+	@AttributeDefinition(required=false, description="The maximum number of connections in the pool")
+	int osgi_connection_max() default 10;
+
+	@AttributeDefinition(required=false, description="The minimum number of connections in the pool")
+	int osgi_connection_min() default 10;
+	
+	@AttributeDefinition(required=false, description="The maximum time (in ms) that the pool will wait for a connection before failing")
+	long osgi_connection_timeout() default 30000;
+	
+	@AttributeDefinition(required=false, description="The minimum time (in ms) a connection will be idle before being reclaimed by the pool")
+	long osgi_idle_timeout() default 180000;
+	
+	@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;
+	
+	// Detailed Configuration
+	
+	@AttributeDefinition(required=false, description="The filter to use when finding the DataSourceFactory service. This property need not be defined if osgi.jdbc.driver.class is defined.")
+	String aries_dsf_target_filter();
+	
+	@AttributeDefinition(required=false, description="The names of the properties from this configuration that should be passed to the DataSourceFactory")
+	String[] aries_jdbc_property_names() default {JDBC_DATABASE_NAME, JDBC_DATASOURCE_NAME,
+			JDBC_DESCRIPTION, JDBC_NETWORK_PROTOCOL, JDBC_PASSWORD, JDBC_PORT_NUMBER, JDBC_ROLE_NAME, JDBC_SERVER_NAME,
+			JDBC_URL, JDBC_USER};
+	
+
+	//Raw JDBC configuration
+	
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String databaseName();
+	
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String dataSourceName();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String description();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String networkProtocol();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	int portNumber();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String roleName();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String serverName();
+}
diff --git a/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java b/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
index 007a2d7..db09ac2 100644
--- a/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
+++ b/tx-control-provider-jdbc-local/src/main/java/org/apache/aries/tx/control/jdbc/local/impl/ManagedServiceFactoryImpl.java
@@ -166,7 +166,7 @@
 					throw new ConfigurationException(OSGI_JDBC_DRIVER_CLASS,
 							"The configuration must specify either a target filter or a JDBC driver class");
 				}
-				targetFilter = "(" + OSGI_JDBC_DRIVER_CLASS + "=" + driver + ")";
+				targetFilter = "(&(" + OBJECTCLASS + "=" + DataSourceFactory.class.getName() + ")(" + OSGI_JDBC_DRIVER_CLASS + "=" + driver + "))";
 			}
 
 			targetFilter = "(&(" + OBJECTCLASS + "=" + DataSourceFactory.class.getName() + ")" + targetFilter + ")";
@@ -214,7 +214,9 @@
 
 		private Dictionary<String, ?> getServiceProperties() {
 			Hashtable<String, Object> props = new Hashtable<>();
-			providerProperties.keySet().stream().filter(s -> !JDBC_PASSWORD.equals(s))
+			providerProperties.keySet().stream()
+					.filter(s -> !s.startsWith("."))
+					.filter(s -> !JDBC_PASSWORD.equals(s))
 					.forEach(s -> props.put(s, providerProperties.get(s)));
 			return props;
 		}
diff --git a/tx-control-provider-jdbc-xa/pom.xml b/tx-control-provider-jdbc-xa/pom.xml
index 8cd493c..2d42086 100644
--- a/tx-control-provider-jdbc-xa/pom.xml
+++ b/tx-control-provider-jdbc-xa/pom.xml
@@ -78,6 +78,10 @@
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.service.jdbc</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.metatype.annotations</artifactId>
+        </dependency>
 
         <!-- Hikari CP dependency -->
         <dependency>
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
new file mode 100644
index 0000000..cb71589
--- /dev/null
+++ b/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/Config.java
@@ -0,0 +1,98 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATABASE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DATASOURCE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_DESCRIPTION;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_NETWORK_PROTOCOL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PASSWORD;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_PORT_NUMBER;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_ROLE_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_SERVER_NAME;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_URL;
+import static org.osgi.service.jdbc.DataSourceFactory.JDBC_USER;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.AttributeType;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+@ObjectClassDefinition(factoryPid="org.apache.aries.tx.control.jdbc.xa", description="Aries Transaction Control Factory for XA enabled JDBCResourceProvider Services")
+public @interface Config {
+
+	// Most commonly used properties declared first so that they go into the metatype first
+	
+	@AttributeDefinition(required=false, 
+			description="The name of the driver class for the DataSourceFactory service. This property need not be defined if aries.dsf.target.filter is defined.")
+	String osgi_jdbc_driver_class();
+
+	@AttributeDefinition(required=false, description="The JDBC URL to pass to the DataSourceFactory")
+	String url();
+	
+	@AttributeDefinition(required=false, description="The userid to pass to the DataSourceFactory")
+	String user();
+	
+	@AttributeDefinition(type=AttributeType.PASSWORD, required=false, 
+			description="The password to pass to the DataSourceFactory (not visible as a service property)")
+	String password();
+	
+	// Pool configuration properties
+	
+	@AttributeDefinition(required=false, description="Is connection pooling enabled for this JDBCResourceProvider")
+	boolean osgi_connection_pooling_enabled() default true;
+	
+	@AttributeDefinition(required=false, description="The maximum number of connections in the pool")
+	int osgi_connection_max() default 10;
+
+	@AttributeDefinition(required=false, description="The minimum number of connections in the pool")
+	int osgi_connection_min() default 10;
+	
+	@AttributeDefinition(required=false, description="The maximum time (in ms) that the pool will wait for a connection before failing")
+	long osgi_connection_timeout() default 30000;
+	
+	@AttributeDefinition(required=false, description="The minimum time (in ms) a connection will be idle before being reclaimed by the pool")
+	long osgi_idle_timeout() default 180000;
+	
+	@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;
+	
+	// Transaction integration configuration
+	
+	@AttributeDefinition(required=false, description="Should this Resource participate in transactions using XA")
+	boolean osgi_xa_enabled() default true;
+
+	@AttributeDefinition(required=false, description="Should this Resource participate as a Local Resource if XA is not available")
+	boolean osgi_local_enabled() default true;
+
+	// Detailed Configuration
+	
+	@AttributeDefinition(required=false, description="The filter to use when finding the DataSourceFactory service. This property need not be defined if osgi.jdbc.driver.class is defined.")
+	String aries_dsf_target_filter();
+	
+	@AttributeDefinition(required=false, description="The names of the properties from this configuration that should be passed to the DataSourceFactory")
+	String[] aries_jdbc_property_names() default {JDBC_DATABASE_NAME, JDBC_DATASOURCE_NAME,
+			JDBC_DESCRIPTION, JDBC_NETWORK_PROTOCOL, JDBC_PASSWORD, JDBC_PORT_NUMBER, JDBC_ROLE_NAME, JDBC_SERVER_NAME,
+			JDBC_URL, JDBC_USER};
+	
+
+	//Raw JDBC configuration
+	
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String databaseName();
+	
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String dataSourceName();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String description();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String networkProtocol();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	int portNumber();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String roleName();
+
+	@AttributeDefinition(required=false, description="JDBC configuration property")
+	String serverName();
+}
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 28c9f16..ee18aa1 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
@@ -166,7 +166,7 @@
 					throw new ConfigurationException(OSGI_JDBC_DRIVER_CLASS,
 							"The configuration must specify either a target filter or a JDBC driver class");
 				}
-				targetFilter = "(" + OSGI_JDBC_DRIVER_CLASS + "=" + driver + ")";
+				targetFilter = "(&(" + OBJECTCLASS + "=" + DataSourceFactory.class.getName() + ")(" + OSGI_JDBC_DRIVER_CLASS + "=" + driver + "))";
 			}
 
 			targetFilter = "(&(" + OBJECTCLASS + "=" + DataSourceFactory.class.getName() + ")" + targetFilter + ")";
@@ -214,7 +214,9 @@
 
 		private Dictionary<String, ?> getServiceProperties() {
 			Hashtable<String, Object> props = new Hashtable<>();
-			providerProperties.keySet().stream().filter(s -> !JDBC_PASSWORD.equals(s))
+			providerProperties.keySet().stream()
+					.filter(s -> !s.startsWith("."))
+					.filter(s -> !JDBC_PASSWORD.equals(s))
 					.forEach(s -> props.put(s, providerProperties.get(s)));
 			return props;
 		}