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