diff --git a/bnd.bnd b/bnd.bnd
new file mode 100644
index 0000000..c90f4be
--- /dev/null
+++ b/bnd.bnd
@@ -0,0 +1,5 @@
+Bundle-DocURL: https://sling.apache.org/documentation/bundles/datasource-providers.html
+Export-Package: !org.apache.juli.logging
+
+-includeresource:\
+ @tomcat-jdbc-*.jar;inline=true
diff --git a/pom.xml b/pom.xml
index 93a92e2..3e26542 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,82 +19,51 @@
-->
-
4.0.0
-
org.apache.sling
- sling
- 26
+ sling-bundle-parent
+ 48
org.apache.sling.datasource
- bundle
1.0.5-SNAPSHOT
Apache Sling DataSource Provider
- Enables creation of DataSource based on OSGi configuration. Refer to http://sling.apache.org/documentation/bundles/datasource-providers.html
+ Enables creation of DataSource based on OSGi configuration. Refer to https://sling.apache.org/documentation/bundles/datasource-providers.html
for more details
- 3.4.0
+ 4.13.3
1.6.0
-
- ${basedir}/target
-
-
- ${bundle.build.name}/${project.build.finalName}.jar
-
+ 1
scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-datasource.git
scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-datasource.git
https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-datasource.git
- HEAD
-
- org.apache.felix
- maven-bundle-plugin
- true
-
-
-
- !org.apache.juli.logging
-
-
- org.apache.sling.commons.osgi;inline=org/apache/sling/commons/osgi/PropertiesUtil.class,
- tomcat-jdbc;inline=true,
-
-
-
+ biz.aQute.bnd
+ bnd-maven-plugin
- org.apache.felix
- maven-scr-plugin
- 1.25.0
+ org.apache.rat
+ apache-rat-plugin
org.apache.servicemix.tooling
depends-maven-plugin
- 1.2
-
-
- generate-depends-file
-
- generate-depends-file
-
-
-
+ org.apache.maven.plugins
maven-failsafe-plugin
@@ -105,9 +74,9 @@
-
- ${bundle.file.name}
- ${coverage.command}
+ true
+
+ ${basedir}/target/${project.build.finalName}.jar
@@ -122,20 +91,28 @@
org.osgi
- org.osgi.core
- 4.3.1
+ osgi.core
provided
org.osgi
- org.osgi.compendium
- 4.3.1
+ org.osgi.service.metatype.annotations
provided
- org.apache.sling
- org.apache.sling.commons.osgi
- 2.2.0
+ org.osgi
+ org.osgi.service.component.annotations
+ provided
+
+
+ org.osgi
+ org.osgi.service.component
+ provided
+
+
+ org.osgi
+ org.osgi.service.cm
+ provided
org.apache.tomcat
@@ -153,7 +130,13 @@
org.apache.felix
org.apache.felix.framework
- 4.4.0
+ 7.0.3
+ test
+
+
+ org.ops4j.pax.exam
+ pax-exam
+ ${pax.exam.version}
test
@@ -192,28 +175,15 @@
${pax.url.version}
test
-
- org.apache.felix
- org.apache.felix.configadmin
- 1.8.0
- test
-
-
- org.apache.felix
- org.apache.felix.scr
- 1.8.2
- test
-
com.h2database
h2
- 1.4.178
+ 2.1.212
test
org.slf4j
slf4j-simple
- 1.5.2
test
@@ -221,36 +191,29 @@
commons-beanutils-core
1.8.3
+
+ org.apache.sling
+ org.apache.sling.testing.paxexam
+ 3.1.0
+
+
+ org.apache.sling
+ org.apache.sling.testing.osgi-mock.junit4
+ 3.2.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 4.5.1
+ test
+
+
+ com.github.h-thurow
+ simple-jndi
+ 0.23.0
+ test
+
-
-
-
- ide
-
-
-
- maven-antrun-plugin
-
-
- bundle-file-create
- package
-
- run
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java b/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java
index 23f0553..4d64c86 100644
--- a/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java
+++ b/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java
@@ -18,6 +18,25 @@
*/
package org.apache.sling.datasource.internal;
+import org.apache.tomcat.jdbc.pool.ConnectionPool;
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.apache.tomcat.jdbc.pool.PoolConfiguration;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.metatype.annotations.Designate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
import java.sql.SQLException;
import java.util.Arrays;
@@ -28,158 +47,39 @@
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Collectors;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Modified;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyOption;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.tomcat.jdbc.pool.ConnectionPool;
-import org.apache.tomcat.jdbc.pool.DataSource;
-import org.apache.tomcat.jdbc.pool.PoolConfiguration;
-import org.apache.tomcat.jdbc.pool.PoolProperties;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import static org.apache.sling.datasource.internal.JNDIDataSourceFactory.PROP_DATASOURCE_NAME;
@Component(
name = DataSourceFactory.NAME,
- label = "%datasource.component.name",
- description = "%datasource.component.description",
- metatype = true,
- configurationFactory = true,
- policy = ConfigurationPolicy.REQUIRE
-)
+ configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = DataSourceFactoryConfig.class, factory = true)
public class DataSourceFactory {
- public static final String NAME = "org.apache.sling.datasource.DataSourceFactory";
-
- @Property
- static final String PROP_DATASOURCE_NAME = "datasource.name";
- @Property(value = PROP_DATASOURCE_NAME)
- static final String PROP_DS_SVC_PROP_NAME = "datasource.svc.prop.name";
-
- @Property
- static final String PROP_DRIVERCLASSNAME = "driverClassName";
-
- @Property
- static final String PROP_URL = "url";
-
- @Property
- static final String PROP_USERNAME = "username";
-
- @Property(passwordValue = "")
- static final String PROP_PASSWORD = "password";
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ public static final String NAME = "org.apache.sling.datasource.DataSourceFactory";
+ static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
+ static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
+ static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
+ static final String PROP_DATASOURCE_SVC_PROPS = "datasource.svc.properties";
/**
* Value indicating default value should be used. if the value is set to
* this value then that value would be treated as null
*/
static final String DEFAULT_VAL = "default";
- @Property(value = DEFAULT_VAL, options = {
- @PropertyOption(name = "Default", value = DEFAULT_VAL),
- @PropertyOption(name = "true", value = "true"),
- @PropertyOption(name = "false", value = "false")})
- static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
-
- @Property(value = DEFAULT_VAL, options = {
- @PropertyOption(name = "Default", value = DEFAULT_VAL),
- @PropertyOption(name = "true", value = "true"),
- @PropertyOption(name = "false", value = "false")})
- static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
-
- @Property(value = DEFAULT_VAL, options = {
- @PropertyOption(name = "Default", value = DEFAULT_VAL),
- @PropertyOption(name = "NONE", value = "NONE"),
- @PropertyOption(name = "READ_COMMITTED", value = "READ_COMMITTED"),
- @PropertyOption(name = "READ_UNCOMMITTED", value = "READ_UNCOMMITTED"),
- @PropertyOption(name = "REPEATABLE_READ", value = "REPEATABLE_READ"),
- @PropertyOption(name = "SERIALIZABLE", value = "SERIALIZABLE")})
- static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
-
- @Property
- static final String PROP_DEFAULTCATALOG = "defaultCatalog";
-
- @Property(intValue = PoolProperties.DEFAULT_MAX_ACTIVE)
- static final String PROP_MAXACTIVE = "maxActive";
-
- @Property(intValue = PoolProperties.DEFAULT_MAX_ACTIVE)
- static final String PROP_MAXIDLE = "maxIdle"; //defaults to maxActive
-
- @Property(intValue = 10)
- static final String PROP_MINIDLE = "minIdle"; //defaults to initialSize
-
- @Property(intValue = 10)
- static final String PROP_INITIALSIZE = "initialSize";
-
- @Property(intValue = 30000)
- static final String PROP_MAXWAIT = "maxWait";
-
- @Property(intValue = 0)
- static final String PROP_MAXAGE = "maxAge";
-
- @Property(boolValue = false)
- static final String PROP_TESTONBORROW = "testOnBorrow";
-
- @Property(boolValue = false)
- static final String PROP_TESTONRETURN = "testOnReturn";
-
- @Property(boolValue = false)
- static final String PROP_TESTWHILEIDLE = "testWhileIdle";
-
- @Property
- static final String PROP_VALIDATIONQUERY = "validationQuery";
-
- @Property(intValue = -1)
- static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
-
- @Property(intValue = 5000)
- protected static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
-
- @Property(intValue = 60000)
- protected static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
-
- @Property
- protected static final String PROP_CONNECTIONPROPERTIES = "connectionProperties";
-
- @Property
- protected static final String PROP_INITSQL = "initSQL";
-
- @Property(value = "StatementCache;SlowQueryReport(threshold=10000);ConnectionState")
- protected static final String PROP_INTERCEPTORS = "jdbcInterceptors";
-
- @Property(intValue = 30000)
- protected static final String PROP_VALIDATIONINTERVAL = "validationInterval";
-
- @Property(boolValue = true)
- protected static final String PROP_LOGVALIDATIONERRORS = "logValidationErrors";
-
- @Property(value = {}, cardinality = 1024)
- static final String PROP_DATASOURCE_SVC_PROPS = "datasource.svc.properties";
-
/**
* Property names where we need to treat value 'default' as null
*/
private static final Set PROPS_WITH_DFEAULT =
- Collections.unmodifiableSet(new HashSet(Arrays.asList(
+ Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
PROP_DEFAULTAUTOCOMMIT,
PROP_DEFAULTREADONLY,
PROP_DEFAULTTRANSACTIONISOLATION
)));
- private final Logger log = LoggerFactory.getLogger(getClass());
-
@Reference
private DriverRegistry driverRegistry;
@@ -196,12 +96,12 @@ public class DataSourceFactory {
private BundleContext bundleContext;
@Activate
- protected void activate(BundleContext bundleContext, Map config) throws Exception {
+ protected void activate(BundleContext bundleContext, DataSourceFactoryConfig config, Map properties) throws Exception {
this.bundleContext = bundleContext;
name = getDataSourceName(config);
checkArgument(name != null, "DataSource name must be specified via [%s] property", PROP_DATASOURCE_NAME);
- dataSource = new LazyJmxRegisteringDataSource(createPoolConfig(config));
+ dataSource = new LazyJmxRegisteringDataSource(createPoolConfig(config, properties));
svcPropName = getSvcPropName(config);
registerDataSource(svcPropName);
@@ -210,20 +110,20 @@ protected void activate(BundleContext bundleContext, Map config) thro
}
@Modified
- protected void modified(Map config) throws Exception {
+ protected void modified(DataSourceFactoryConfig config, Map properties) throws Exception {
String name = getDataSourceName(config);
String svcPropName = getSvcPropName(config);
if (!this.name.equals(name) || !this.svcPropName.equals(svcPropName)) {
log.info("Change in datasource name/service property name detected. DataSource would be recreated");
deactivate();
- activate(bundleContext, config);
+ activate(bundleContext, config, properties);
return;
}
//Other modifications can be applied at runtime itself
//Tomcat Connection Pool is decoupled from DataSource so can be closed and reset
- dataSource.setPoolProperties(createPoolConfig(config));
+ dataSource.setPoolProperties(createPoolConfig(config, properties));
closeConnectionPool();
dataSource.createPool();
log.info("Updated DataSource [{}] with properties {}", name, dataSource.getPoolProperties().toString());
@@ -245,11 +145,16 @@ private void closeConnectionPool() {
dataSource.close();
}
- private PoolConfiguration createPoolConfig(Map config) {
+ private PoolConfiguration createPoolConfig(DataSourceFactoryConfig config, Map properties) {
Properties props = new Properties();
//Copy the other properties first
- Map otherProps = PropertiesUtil.toMap(config.get(PROP_DATASOURCE_SVC_PROPS), new String[0]);
+ Map otherProps = Arrays.asList(config.datasource_svc_properties())
+ .stream()
+ .map(element -> element.split("="))
+ .filter(element -> element[1] != null && !element[1].isEmpty())
+ .collect(Collectors.toMap(element -> element[0], element -> element[1]));
+
for (Map.Entry e : otherProps.entrySet()) {
set(e.getKey(), e.getValue(), props);
}
@@ -257,8 +162,10 @@ private PoolConfiguration createPoolConfig(Map config) {
props.setProperty(org.apache.tomcat.jdbc.pool.DataSourceFactory.OBJECT_NAME, name);
for (String propName : DummyDataSourceFactory.getPropertyNames()) {
- String value = PropertiesUtil.toString(config.get(propName), null);
- set(propName, value, props);
+ if (properties.get(propName) != null) {
+ String value = properties.get(propName).toString();
+ set(propName, value, props);
+ }
}
//Specify the DataSource such that connection creation logic is handled
@@ -274,7 +181,7 @@ private DriverDataSource createDriverDataSource(PoolConfiguration poolProperties
}
private void registerDataSource(String svcPropName) {
- Dictionary svcProps = new Hashtable();
+ Dictionary svcProps = new Hashtable<>();
svcProps.put(svcPropName, name);
svcProps.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
svcProps.put(Constants.SERVICE_DESCRIPTION, "DataSource service based on Tomcat JDBC");
@@ -287,7 +194,7 @@ private void registerJmx(ConnectionPool pool) throws SQLException {
//jmx not enabled
return;
}
- Hashtable table = new Hashtable();
+ Hashtable table = new Hashtable<>();
table.put("type", "ConnectionPool");
table.put("class", javax.sql.DataSource.class.getName());
table.put("name", ObjectName.quote(name));
@@ -321,12 +228,12 @@ private void unregisterJmx() {
//~----------------------------------------< Config Handling >
- static String getDataSourceName(Map config) {
- return PropertiesUtil.toString(config.get(PROP_DATASOURCE_NAME), null);
+ static String getDataSourceName(DataSourceFactoryConfig config) {
+ return config.datasource_name();
}
- static String getSvcPropName(Map config) {
- return PropertiesUtil.toString(config.get(PROP_DS_SVC_PROP_NAME), PROP_DATASOURCE_NAME);
+ static String getSvcPropName(DataSourceFactoryConfig config) {
+ return config.datasource_svc_prop_name();
}
private static void set(String name, String value, Properties props) {
diff --git a/src/main/java/org/apache/sling/datasource/internal/DataSourceFactoryConfig.java b/src/main/java/org/apache/sling/datasource/internal/DataSourceFactoryConfig.java
new file mode 100644
index 0000000..24017d8
--- /dev/null
+++ b/src/main/java/org/apache/sling/datasource/internal/DataSourceFactoryConfig.java
@@ -0,0 +1,149 @@
+/*
+ * 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 WARRANTIES OR 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.sling.datasource.internal;
+
+import org.apache.tomcat.jdbc.pool.PoolProperties;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.AttributeType;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.osgi.service.metatype.annotations.Option;
+
+@SuppressWarnings("java:S100")
+@ObjectClassDefinition(
+ localization = "OSGI-INF/l10n/metatype",
+ name = "%datasource.component.name",
+ description = "%datasource.component.description")
+public @interface DataSourceFactoryConfig {
+
+ /**
+ * Value indicating default value should be used. if the value is set to
+ * this value then that value would be treated as null
+ */
+ String DEFAULT_VAL = "default";
+
+ @AttributeDefinition
+ String datasource_name() default "";
+
+ @AttributeDefinition
+ String datasource_svc_prop_name() default JNDIDataSourceFactory.PROP_DATASOURCE_NAME;
+
+ @AttributeDefinition
+ String url() default "";
+
+ @AttributeDefinition
+ String username() default "";
+
+ @AttributeDefinition(type = AttributeType.PASSWORD)
+ String password() default "";
+
+ @AttributeDefinition(
+ options = {
+ @Option(label = "Default", value = DEFAULT_VAL),
+ @Option(label = "true", value = "true"),
+ @Option(label = "false", value = "false"),
+ @Option(label = "error", value = "error")
+ },
+ defaultValue = DEFAULT_VAL)
+ String defaultAutoCommit();
+
+ @AttributeDefinition(
+ options = {
+ @Option(label = "Default", value = DEFAULT_VAL),
+ @Option(label = "true", value = "true"),
+ @Option(label = "false", value = "false"),
+ @Option(label = "error", value = "error")
+ },
+ defaultValue = DEFAULT_VAL)
+ String defaultReadOnly();
+
+ @AttributeDefinition(
+ options = {
+ @Option(label = "Default", value = DEFAULT_VAL),
+ @Option(label = "NONE", value = "NONE"),
+ @Option(label = "READ_COMMITTED", value = "READ_COMMITTED"),
+ @Option(label = "READ_UNCOMMITTED", value = "READ_UNCOMMITTED"),
+ @Option(label = "REPEATABLE_READ", value = "REPEATABLE_READ"),
+ @Option(label = "SERIALIZABLE", value = "SERIALIZABLE")
+ },
+ defaultValue = DEFAULT_VAL)
+ String defaultTransactionIsolation();
+
+ @AttributeDefinition
+ String driverClassName() default "";
+
+ @AttributeDefinition
+ String defaultCatalog() default "";
+
+ @AttributeDefinition
+ int maxActive() default PoolProperties.DEFAULT_MAX_ACTIVE;
+
+ @AttributeDefinition
+ int maxIdle() default PoolProperties.DEFAULT_MAX_ACTIVE;
+
+ @AttributeDefinition
+ int minIdle() default 10; //defaults to initialSize
+
+ @AttributeDefinition
+ int initialSize() default 10;
+
+ @AttributeDefinition
+ int maxWait() default 30000;
+
+ @AttributeDefinition
+ int maxAge() default 0;
+
+ @AttributeDefinition
+ boolean testOnBorrow() default false;
+
+ @AttributeDefinition
+ boolean testOnReturn() default false;
+
+ @AttributeDefinition
+ boolean testWhileIdle() default false;
+
+ @AttributeDefinition
+ String validationQuery() default "";
+
+ @AttributeDefinition
+ int validationQueryTimeout() default -1;
+
+ @AttributeDefinition
+ int timeBetweenEvictionRunsMillis() default 5000;
+
+ @AttributeDefinition
+ int minEvictableIdleTimeMillis() default 60000;
+
+ @AttributeDefinition
+ String connectionProperties() default "";
+
+ @AttributeDefinition
+ String initSQL() default "";
+
+ @AttributeDefinition
+ String jdbcInterceptors() default "StatementCache;SlowQueryReport(threshold=10000);ConnectionState";
+
+ @AttributeDefinition
+ int validationInterval() default 30000;
+
+ @AttributeDefinition
+ boolean logValidationErrors() default true;
+
+ @AttributeDefinition(cardinality = 1024)
+ String[] datasource_svc_properties() default {};
+}
diff --git a/src/main/java/org/apache/sling/datasource/internal/DriverRegistry.java b/src/main/java/org/apache/sling/datasource/internal/DriverRegistry.java
index ceebf72..92dbda8 100644
--- a/src/main/java/org/apache/sling/datasource/internal/DriverRegistry.java
+++ b/src/main/java/org/apache/sling/datasource/internal/DriverRegistry.java
@@ -30,29 +30,26 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-@Component
-@Service(value = DriverRegistry.class)
+@Component(service = {DriverRegistry.class})
public class DriverRegistry {
- private static final String DRIVER_SERVICE = "META-INF/services/"
- + Driver.class.getName();
+ private static final String DRIVER_SERVICE = "META-INF/services/" + Driver.class.getName();
private final Logger log = LoggerFactory.getLogger(getClass());
private BundleTracker> bundleTracker;
- private ConcurrentMap driverInfos = new ConcurrentHashMap();
+ private ConcurrentMap driverInfos = new ConcurrentHashMap<>();
public Collection getDrivers() {
return driverInfos.values();
@@ -60,8 +57,7 @@ public Collection getDrivers() {
@Activate
protected void activate(BundleContext bundleContext) {
- bundleTracker = new BundleTracker>(bundleContext,
- Bundle.ACTIVE, new DriverBundleTracker());
+ bundleTracker = new BundleTracker<>(bundleContext, Bundle.ACTIVE, new DriverBundleTracker());
bundleTracker.open();
}
diff --git a/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java b/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java
index 925b548..47c125b 100644
--- a/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java
+++ b/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java
@@ -19,10 +19,10 @@
package org.apache.sling.datasource.internal;
+import java.util.Arrays;
import java.util.Dictionary;
import java.util.Hashtable;
-import java.util.Map;
-import java.util.Properties;
+import java.util.stream.Collectors;
import javax.naming.Context;
import javax.naming.InitialContext;
@@ -30,70 +30,70 @@
import javax.naming.NamingException;
import javax.sql.DataSource;
-import org.apache.felix.scr.annotations.Activate;
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.ConfigurationPolicy;
-import org.apache.felix.scr.annotations.Deactivate;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.sling.commons.osgi.PropertiesUtil;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.Designate;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.sling.datasource.internal.DataSourceFactory.checkArgument;
@Component(
+ immediate = true,
name = JNDIDataSourceFactory.NAME,
- label = "Apache Sling JNDI DataSource",
- description = "Registers a DataSource instance with OSGi ServiceRegistry which is looked up " +
- "from the JNDI",
- metatype = true,
- configurationFactory = true,
- policy = ConfigurationPolicy.REQUIRE
-)
+ configurationPolicy = ConfigurationPolicy.REQUIRE)
+@Designate(ocd = JNDIDataSourceFactory.Config.class, factory = true)
public class JNDIDataSourceFactory {
- public static final String NAME = "org.apache.sling.datasource.JNDIDataSourceFactory";
- @Property
- static final String PROP_DATASOURCE_NAME = "datasource.name";
+ private final Logger log = LoggerFactory.getLogger(getClass());
- @Property(value = PROP_DATASOURCE_NAME)
+ public static final String NAME = "org.apache.sling.datasource.JNDIDataSourceFactory";
+ static final String PROP_DATASOURCE_NAME = "datasource.name";
static final String PROP_DS_SVC_PROP_NAME = "datasource.svc.prop.name";
-
- @Property(
- label = "JNDI Name (*)",
- description = "JNDI location name used to perform DataSource instance lookup"
- )
static final String PROP_DS_JNDI_NAME = "datasource.jndi.name";
-
- @Property(
- label = "JNDI Properties",
- description = "Set the environment for the JNDI InitialContext i.e. properties passed on to InitialContext " +
- "for performing the JNDI instance lookup. Each row form a map entry where each row format be propertyName=property " +
- "e.g. java.naming.factory.initial=exampleFactory",
- value = {},
- cardinality = 1024)
static final String PROP_JNDI_PROPS = "jndi.properties";
- private final Logger log = LoggerFactory.getLogger(getClass());
+ @SuppressWarnings("java:S100")
+ @ObjectClassDefinition(name = "Apache Sling JNDI DataSource",
+ description = "Registers a DataSource instance with OSGi ServiceRegistry which is looked up from the JNDI")
+ public @interface Config {
- private ServiceRegistration dsRegistration;
+ @AttributeDefinition
+ String datasource_name() default "";
+ @AttributeDefinition
+ String datasource_svc_prop_name() default PROP_DATASOURCE_NAME;
+
+ @AttributeDefinition(name = "JNDI Name (*)", description = "JNDI location name used to perform DataSource instance lookup")
+ String datasource_jndi_name() default PROP_DATASOURCE_NAME;
+
+ @AttributeDefinition(name = "JNDI Properties", description = "Set the environment for the JNDI InitialContext i.e. properties passed on to " +
+ "InitialContext for performing the JNDI instance lookup. Each row form a map entry where each row format be propertyName=property" +
+ " e.g. java.naming.factory.initial=exampleFactory", cardinality = 1024)
+ String[] jndi_properties() default {};
+ }
+
+ private ServiceRegistration dsRegistration;
@Activate
- protected void activate(BundleContext bundleContext, Map config) throws Exception {
- String name = DataSourceFactory.getDataSourceName(config);
- String jndiName = PropertiesUtil.toString(config.get(PROP_DS_JNDI_NAME), null);
+ protected void activate(BundleContext bundleContext, Config config) throws Exception {
+ String name = config.datasource_name();
+ String jndiName = config.datasource_jndi_name();
checkArgument(name != null, "DataSource name must be specified via [%s] property", PROP_DATASOURCE_NAME);
checkArgument(jndiName != null, "DataSource JNDI name must be specified via [%s] property", PROP_DS_JNDI_NAME);
DataSource dataSource = lookupDataSource(jndiName, config);
- String svcPropName = DataSourceFactory.getSvcPropName(config);
+ String svcPropName = config.datasource_svc_prop_name();
- Dictionary svcProps = new Hashtable();
+ Dictionary svcProps = new Hashtable<>();
svcProps.put(svcPropName, name);
svcProps.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
svcProps.put(Constants.SERVICE_DESCRIPTION, "DataSource service looked up from " + jndiName);
@@ -110,19 +110,18 @@ protected void deactivate() {
}
}
- private DataSource lookupDataSource(String jndiName, Map config) throws NamingException {
- Properties jndiProps = createJndiEnv(config);
+ private DataSource lookupDataSource(String jndiName, Config config) throws NamingException {
+ Hashtable jndiProps = createJndiEnv(config);
Context context = null;
try {
- log.debug("Looking up DataSource [{}] with InitialContext env [{}]", jndiName, jndiProps);
-
+ log.info("Looking up DataSource [{}] with InitialContext env [{}]", jndiName, jndiProps);
context = new InitialContext(jndiProps);
Object lookup = context.lookup(jndiName);
if (lookup == null) {
throw new NameNotFoundException("JNDI object with [" + jndiName + "] not found");
}
- if (!DataSource.class.isInstance(lookup)) {
+ if (!(lookup instanceof DataSource)) {
throw new IllegalStateException("JNDI object of type " + lookup.getClass() +
"is not an instance of javax.sql.DataSource");
}
@@ -135,27 +134,13 @@ private DataSource lookupDataSource(String jndiName, Map config) thro
}
}
- private Properties createJndiEnv(Map config) {
- Properties props = new Properties();
+ private Hashtable createJndiEnv(Config config) {
+ Hashtable jndiEnvProps = Arrays.asList(config.jndi_properties())
+ .stream()
+ .map(element -> element.split("="))
+ .filter(element -> element[1] != null && !element[1].isEmpty())
+ .collect(Collectors.toMap(element -> element[0], element -> element[1], (a, b) -> a, Hashtable::new));
- //Copy the other properties first
- Map otherProps = PropertiesUtil.toMap(config.get(PROP_JNDI_PROPS), new String[0]);
- for (Map.Entry e : otherProps.entrySet()) {
- set(e.getKey(), e.getValue(), props);
- }
-
- return props;
- }
-
- //~----------------------------------------< Config Handling >
-
- private static void set(String name, String value, Properties props) {
- if (value != null) {
- value = value.trim();
- }
-
- if (value != null && !value.isEmpty()) {
- props.setProperty(name, value);
- }
+ return jndiEnvProps;
}
}
diff --git a/src/test/java/org/apache/sling/datasource/DataSourceTestBase.java b/src/test/java/org/apache/sling/datasource/DataSourceTestBase.java
deleted file mode 100644
index 6564dff..0000000
--- a/src/test/java/org/apache/sling/datasource/DataSourceTestBase.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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 WARRANTIES OR 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.sling.datasource;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-import javax.inject.Inject;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-import org.ops4j.pax.exam.Configuration;
-import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Option;
-import org.osgi.framework.BundleContext;
-
-import static org.ops4j.pax.exam.CoreOptions.cleanCaches;
-import static org.ops4j.pax.exam.CoreOptions.composite;
-import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.keepCaches;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
-import static org.ops4j.pax.exam.CoreOptions.options;
-import static org.ops4j.pax.exam.CoreOptions.systemPackage;
-import static org.ops4j.pax.exam.CoreOptions.systemProperty;
-import static org.ops4j.pax.exam.CoreOptions.systemTimeout;
-import static org.ops4j.pax.exam.CoreOptions.workingDirectory;
-import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
-import static org.ops4j.pax.exam.util.PathUtils.getBaseDir;
-
-public abstract class DataSourceTestBase {
- @Inject
- protected BundleContext context;
-
- // the name of the system property providing the bundle file to be installed
- // and tested
- protected static final String BUNDLE_JAR_SYS_PROP = "project.bundle.file";
-
- // the default bundle jar file name
- protected static final String BUNDLE_JAR_DEFAULT = "target/bundle.jar";
-
- // the name of the system property which captures the jococo coverage agent command
- //if specified then agent would be specified otherwise ignored
- protected static final String COVERAGE_COMMAND = "coverage.command";
-
- // the JVM option to set to enable remote debugging
- @SuppressWarnings("UnusedDeclaration")
- protected static final String DEBUG_VM_OPTION = "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=31313";
-
- // the actual JVM option set, extensions may implement a static
- // initializer overwriting this value to have the configuration()
- // method include it when starting the OSGi framework JVM
- protected static String paxRunnerVmOption = null;
-
- @Configuration
- public Option[] config() throws IOException {
- final String bundleFileName = System.getProperty(BUNDLE_JAR_SYS_PROP, BUNDLE_JAR_DEFAULT);
- final File bundleFile = new File(bundleFileName);
- if (!bundleFile.canRead()) {
- throw new IllegalArgumentException("Cannot read from bundle file " + bundleFileName + " specified in the "
- + BUNDLE_JAR_SYS_PROP + " system property. Try building the project first " +
- "with 'mvn clean install -Pide -DskipTests'");
- }
- return options(
- // the current project (the bundle under test)
- CoreOptions.bundle(bundleFile.toURI().toString()),
- mavenBundle("com.h2database", "h2").versionAsInProject(),
- wrappedBundle(mavenBundle("commons-beanutils", "commons-beanutils-core").versionAsInProject()),
- mavenBundle("org.slf4j", "slf4j-simple").versionAsInProject().noStart(),
- mavenBundle("org.apache.felix", "org.apache.felix.scr").versionAsInProject(),
- mavenBundle("org.apache.felix", "org.apache.felix.configadmin").versionAsInProject(),
- junitBundles(),
- systemProperty("pax.exam.osgi.unresolved.fail").value("fail"),
- systemPackage("com.sun.tools.attach"),
- cleanCaches(),
- addCodeCoverageOption(),
- addDebugOptions()
- );
- }
-
- private static Option addCodeCoverageOption() {
- String coverageCommand = System.getProperty(COVERAGE_COMMAND);
- if (coverageCommand != null && !coverageCommand.isEmpty()) {
- return CoreOptions.vmOption(coverageCommand);
- }
- return null;
- }
-
- private static Option addDebugOptions() throws IOException {
- if (paxRunnerVmOption != null) {
- String workDir = FilenameUtils.concat(getBaseDir(), "target/pax");
- File workDirFile = new File(workDir);
- if (workDirFile.exists()) {
- FileUtils.deleteDirectory(workDirFile);
- }
- return composite(CoreOptions.vmOption(paxRunnerVmOption), keepCaches(),
- systemTimeout(TimeUnit.MINUTES.toMillis(10)), workingDirectory(workDir));
- }
- return null;
- }
-}
diff --git a/src/test/java/org/apache/sling/datasource/DataSourceIT.java b/src/test/java/org/apache/sling/datasource/DataSourceTestIT.java
similarity index 64%
rename from src/test/java/org/apache/sling/datasource/DataSourceIT.java
rename to src/test/java/org/apache/sling/datasource/DataSourceTestIT.java
index 9a771f5..19681f5 100644
--- a/src/test/java/org/apache/sling/datasource/DataSourceIT.java
+++ b/src/test/java/org/apache/sling/datasource/DataSourceTestIT.java
@@ -18,59 +18,61 @@
*/
package org.apache.sling.datasource;
+import java.io.IOException;
import java.sql.Connection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.concurrent.TimeUnit;
-import javax.inject.Inject;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
import org.osgi.framework.Filter;
import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.util.tracker.ServiceTracker;
import static org.apache.commons.beanutils.BeanUtils.getProperty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.ops4j.pax.exam.CoreOptions.options;
@RunWith(PaxExam.class)
-public class DataSourceIT extends DataSourceTestBase{
-
- static {
- //paxRunnerVmOption = DEBUG_VM_OPTION;
- }
-
+@ExamReactorStrategy(PerClass.class)
+public class DataSourceTestIT extends DataSourceTestSupport {
String PID = "org.apache.sling.datasource.DataSourceFactory";
- @Inject
- ConfigurationAdmin ca;
+ @org.ops4j.pax.exam.Configuration
+ public Option[] configuration() throws IOException {
+ return options(
+ baseConfiguration()
+ );
+ }
@SuppressWarnings("unchecked")
@Test
public void testDataSourceAsService() throws Exception{
- Configuration config = ca.createFactoryConfiguration(PID, null);
- Dictionary p = new Hashtable();
- p.put("url","jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
- p.put("datasource.name","test");
- p.put("initialSize","5");
- p.put("defaultAutoCommit","default");
- p.put("defaultReadOnly","false");
- p.put("datasource.svc.properties",new String[]{
+ Configuration config = configurationAdmin.createFactoryConfiguration(PID, null);
+ Dictionary properties = new Hashtable<>();
+ properties.put("url","jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
+ properties.put("datasource.name","test");
+ properties.put("initialSize","5");
+ properties.put("defaultAutoCommit","default");
+ properties.put("defaultReadOnly","false");
+ properties.put("datasource.svc.properties",new String[]{
"initSQL=SELECT 1",
});
- p.put("maxActive",70);
- config.update(p);
+ properties.put("maxActive",70);
+ config.update(properties);
- Filter filter = context.createFilter("(&(objectclass=javax.sql.DataSource)(datasource.name=test))");
- ServiceTracker st =
- new ServiceTracker(context, filter, null);
+ Filter filter = bundleContext.createFilter("(&(objectclass=javax.sql.DataSource)(datasource.name=test))");
+ ServiceTracker st = new ServiceTracker<>(bundleContext, filter, null);
st.open();
DataSource ds = st.waitForService(10000);
@@ -86,7 +88,7 @@ public void testDataSourceAsService() throws Exception{
assertEquals("false", getProperty(ds, "poolProperties.defaultReadOnly"));
assertNull(getProperty(ds, "poolProperties.defaultAutoCommit"));
- config = ca.listConfigurations("(datasource.name=test)")[0];
+ config = configurationAdmin.listConfigurations("(datasource.name=test)")[0];
Dictionary dic = config.getProperties();
dic.put("defaultReadOnly", Boolean.TRUE);
config.update(dic);
diff --git a/src/test/java/org/apache/sling/datasource/DataSourceTestSupport.java b/src/test/java/org/apache/sling/datasource/DataSourceTestSupport.java
new file mode 100644
index 0000000..8e97be4
--- /dev/null
+++ b/src/test/java/org/apache/sling/datasource/DataSourceTestSupport.java
@@ -0,0 +1,64 @@
+/*
+ * 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 WARRANTIES OR 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.sling.datasource;
+
+import org.apache.sling.testing.paxexam.TestSupport;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.ModifiableCompositeOption;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+import javax.inject.Inject;
+
+import static org.apache.sling.testing.paxexam.SlingOptions.logback;
+import static org.apache.sling.testing.paxexam.SlingOptions.sling;
+import static org.apache.sling.testing.paxexam.SlingOptions.slingQuickstartOakTar;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
+
+public abstract class DataSourceTestSupport extends TestSupport {
+
+ @Inject
+ protected BundleContext bundleContext;
+
+ @Inject
+ protected ConfigurationAdmin configurationAdmin;
+
+ protected ModifiableCompositeOption baseConfiguration() {
+ return composite(
+ super.baseConfiguration(),
+ slingQuickstart(),
+ logback(),
+ testBundle("bundle.filename"),
+ mavenBundle("com.h2database", "h2").versionAsInProject(),
+ wrappedBundle(mavenBundle("commons-beanutils", "commons-beanutils-core").versionAsInProject()),
+ junitBundles()
+ );
+ }
+
+ protected Option slingQuickstart() {
+ final String workingDirectory = workingDirectory();
+ return composite(
+ slingQuickstartOakTar(workingDirectory, findFreePort()),
+ sling()
+ );
+ }
+}
diff --git a/src/test/java/org/apache/sling/datasource/internal/DataSourceFactoryTest.java b/src/test/java/org/apache/sling/datasource/internal/DataSourceFactoryTest.java
new file mode 100644
index 0000000..c726d11
--- /dev/null
+++ b/src/test/java/org/apache/sling/datasource/internal/DataSourceFactoryTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 WARRANTIES OR 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.sling.datasource.internal;
+
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DataSourceFactoryTest {
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+
+ private DataSourceFactory dataSourceFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ Dictionary properties = new Hashtable<>();
+ properties.put("datasource.name", "test");
+
+ DriverRegistry driverRegistry = Mockito.mock(DriverRegistry.class);
+ context.registerService(DriverRegistry.class, driverRegistry);
+
+ dataSourceFactory = context.registerInjectActivateService(new DataSourceFactory(), properties);
+ }
+
+ @Test
+ public void testIfServiceActive() {
+ assertNotNull(dataSourceFactory);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/datasource/internal/DriverRegistryTest.java b/src/test/java/org/apache/sling/datasource/internal/DriverRegistryTest.java
new file mode 100644
index 0000000..ced168a
--- /dev/null
+++ b/src/test/java/org/apache/sling/datasource/internal/DriverRegistryTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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 WARRANTIES OR 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.sling.datasource.internal;
+
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DriverRegistryTest {
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+
+ private DriverRegistry driverRegistry;
+
+ @Before
+ public void setUp() throws Exception {
+ Dictionary properties = new Hashtable<>();
+ properties.put("datasource.name", "test");
+
+ driverRegistry = context.registerInjectActivateService(new DriverRegistry(), properties);
+ }
+
+ @Test
+ public void testIfServiceActive() {
+ assertNotNull(driverRegistry);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/datasource/internal/JNDIDataSourceFactoryTest.java b/src/test/java/org/apache/sling/datasource/internal/JNDIDataSourceFactoryTest.java
new file mode 100644
index 0000000..9fcbba3
--- /dev/null
+++ b/src/test/java/org/apache/sling/datasource/internal/JNDIDataSourceFactoryTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 WARRANTIES OR 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.sling.datasource.internal;
+
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+
+import javax.naming.Context;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static org.junit.Assert.assertNotNull;
+
+public class JNDIDataSourceFactoryTest {
+
+ @Rule
+ public final OsgiContext osgiContext = new OsgiContext();
+
+ @After
+ public void tearDown() {
+ System.clearProperty(Context.INITIAL_CONTEXT_FACTORY);
+ }
+
+ @Test
+ public void testIfServiceActive() {
+ Dictionary properties = new Hashtable<>();
+ properties.put("datasource.name", "ds");
+ properties.put("datasource.jndi.name", "java:/comp/env/ds");
+
+ defaultJNDIProperties(properties);
+ JNDIDataSourceFactory jndiDataSourceFactory = osgiContext.registerInjectActivateService(new JNDIDataSourceFactory(), properties);
+
+ assertNotNull(jndiDataSourceFactory);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testIllegalStateException() {
+ Dictionary properties = new Hashtable<>();
+ properties.put("datasource.name", "ds");
+ properties.put("datasource.jndi.name", "java:/comp/env");
+
+ defaultJNDIProperties(properties);
+ osgiContext.registerInjectActivateService(new JNDIDataSourceFactory(), properties);
+ }
+
+ private void defaultJNDIProperties(Dictionary properties) {
+ properties.put("jndi.properties", new String[]{
+ "java.naming.factory.initial=org.osjava.sj.SimpleContextFactory",
+ "org.osjava.sj.delimiter=.",
+ "jndi.syntax.separator=/",
+ "org.osjava.sj.space=java:/comp/env",
+ "org.osjava.sj.jndi.shared=true",
+ "org.osjava.sj.root=src/test/resources/datasource.properties"
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/resources/datasource.properties b/src/test/resources/datasource.properties
new file mode 100644
index 0000000..deb61d6
--- /dev/null
+++ b/src/test/resources/datasource.properties
@@ -0,0 +1,23 @@
+#
+# 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 WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+ds.type=javax.sql.DataSource
+ds.driver=org.h2.Driver
+ds.url=jdbc:jdbc:h2:mem:testdb
+ds.user=sa
+ds.password=password
\ No newline at end of file