You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:25:22 UTC

[sling-org-apache-sling-datasource] 12/22: SLING-3735 - support JNDI lookup in JDBC DataSource Provider

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.datasource-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-datasource.git

commit 47452e2a08bccdf052aa92e38ae49108cb07ab62
Author: Chetan Mehrotra <ch...@apache.org>
AuthorDate: Mon Nov 10 07:05:08 2014 +0000

    SLING-3735 - support JNDI lookup in JDBC DataSource Provider
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/datasource@1637799 13f79535-47bb-0310-9956-ffa450edef68
---
 README.md                                          |  70 +++++----
 .../datasource/internal/DataSourceFactory.java     |   6 +-
 .../datasource/internal/JNDIDataSourceFactory.java | 160 +++++++++++++++++++++
 .../OSGI-INF/metatype/metatype.properties          |   2 +-
 4 files changed, 207 insertions(+), 31 deletions(-)

diff --git a/README.md b/README.md
index f987e4d..0da8c3e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,11 @@
-Apache Sling DataSource Provider
-================================
+# Apache Sling DataSource Provider
+
+DataSource provider bundle supports two type of DataSource
+
+1. Pooled Connection DataSource
+2. JNDI DataSource
+
+## Pooled Connection DataSource Provider
 
 This bundle enables creating and configuring JDBC DataSource in OSGi environment based on 
 OSGi configuration. It uses [Tomcat JDBC Pool][1] as the JDBC Connection Pool provider.
@@ -9,8 +15,7 @@ OSGi configuration. It uses [Tomcat JDBC Pool][1] as the JDBC Connection Pool pr
 3. Exposes the DataSource stats as JMX MBean 
 4. Supports updating of DataSource connection pool properties at runtime without restart
 
-Driver Loading
---------------
+### Driver Loading
 
 Loading of JDBC driver is tricky on OSGi env. Mostly one has to attach the Driver bundle as a
 fragment bundle to the code which creates the JDBC Connection. 
@@ -28,8 +33,7 @@ bundle to Driver class supported by it. With this feature there is no need to wr
 bundle as fragment to DataSource provider bundle
 
 
-Configuration
--------------
+### Configuration
 
 1. Install the current bundle
 2. Install the JDBC Driver bundle
@@ -42,26 +46,7 @@ http://localhost:8080/system/console/configMgr/org.apache.sling.datasource.DataS
 
 Using the config ui above one can directly configure most of the properties as explained in [Tomcat Docs][1]
 
-Usage
------
-
-Once the required configuration is done the `DataSource` would be registered as part of the OSGi Service Registry
-The service is registered with service property `datasource.name` whose value is the name of datasource provided in 
-OSGi config. 
-
-Following snippet demonstrates accessing the DataSource named `foo` via DS annotation
-
-    import javax.sql.DataSource;
-    import org.apache.felix.scr.annotations.Reference;
-    
-    public class DSExample {
-        
-        @Reference(target = "(&(objectclass=javax.sql.DataSource)(datasource.name=foo))")
-        private DataSource dataSource;
-    }
-
-Convert Driver jars to Bundle
------------------------------
+### Convert Driver jars to Bundle
 
 Most of the JDBC driver jars have the required OSGi headers and can be directly deployed to OSGi container
 as bundles. However some of the drivers e.g. Postgres are not having such headers and hence need to be 
@@ -85,6 +70,37 @@ In the steps above we
 2. Create a bnd file with required instructions. 
 3. Execute the bnd command
 4. Resulting bundle is present in `org.postgresql-9.3.1101.jar`
- 
+
+## JNDI DataSource
+
+While running in Application Server the DataSource instance might be managed by app server and registered with
+JNDI. To enable lookup of DataSource instance from JNDI you can configure `JNDIDataSourceFactory`
+
+1. Configure the DataSource from OSGi config for PID `org.apache.sling.datasource.JNDIDataSourceFactory`
+2. Provide the JNDI name to lookup from and other details
+
+If Felix WebConsole is used then you can configure it via Configuration UI at
+http://localhost:8080/system/console/configMgr/org.apache.sling.datasource.JNDIDataSourceFactory
+
+Once configured `JNDIDataSourceFactory` would lookup the DataSource instance and register it with OSGi
+ServiceRegistry
+
+## Usage
+
+Once the required configuration is done the `DataSource` would be registered as part of the OSGi Service Registry
+The service is registered with service property `datasource.name` whose value is the name of datasource provided in
+OSGi config.
+
+Following snippet demonstrates accessing the DataSource named `foo` via DS annotation
+
+    import javax.sql.DataSource;
+    import org.apache.felix.scr.annotations.Reference;
+
+    public class DSExample {
+
+        @Reference(target = "(&(objectclass=javax.sql.DataSource)(datasource.name=foo))")
+        private DataSource dataSource;
+    }
+
 [1]: http://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html
 [2]: http://www.aqute.biz/Bnd/Wrapping
\ No newline at end of file
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 436ebf3..23f0553 100644
--- a/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java
+++ b/src/main/java/org/apache/sling/datasource/internal/DataSourceFactory.java
@@ -321,11 +321,11 @@ public class DataSourceFactory {
 
     //~----------------------------------------< Config Handling >
 
-    private static String getDataSourceName(Map<String, ?> config) {
+    static String getDataSourceName(Map<String, ?> config) {
         return PropertiesUtil.toString(config.get(PROP_DATASOURCE_NAME), null);
     }
 
-    private static String getSvcPropName(Map<String, ?> config) {
+    static String getSvcPropName(Map<String, ?> config) {
         return PropertiesUtil.toString(config.get(PROP_DS_SVC_PROP_NAME), PROP_DATASOURCE_NAME);
     }
 
@@ -343,7 +343,7 @@ public class DataSourceFactory {
         }
     }
 
-    private static void checkArgument(boolean expression,
+    static void checkArgument(boolean expression,
                                       String errorMessageTemplate,
                                       Object... errorMessageArgs) {
         if (!expression) {
diff --git a/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java b/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java
new file mode 100644
index 0000000..07108ec
--- /dev/null
+++ b/src/main/java/org/apache/sling/datasource/internal/JNDIDataSourceFactory.java
@@ -0,0 +1,160 @@
+/*
+ * 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 java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.sling.datasource.internal.DataSourceFactory.checkArgument;
+
+@Component(
+        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
+)
+public class JNDIDataSourceFactory {
+    public static final String NAME = "org.apache.sling.datasource.JNDIDataSourceFactory";
+
+    @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(
+            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",
+            value = {},
+            cardinality = 1024)
+    static final String PROP_JNDI_PROPS = "jndi.properties";
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private ServiceRegistration dsRegistration;
+
+
+    @Activate
+    protected void activate(BundleContext bundleContext, Map<String, ?> config) throws Exception {
+        String name = DataSourceFactory.getDataSourceName(config);
+        String jndiName = PropertiesUtil.toString(config.get(PROP_DS_JNDI_NAME), null);
+
+        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);
+
+        Dictionary<String, Object> svcProps = new Hashtable<String, Object>();
+        svcProps.put(svcPropName, name);
+        svcProps.put(Constants.SERVICE_VENDOR, "Apache Software Foundation");
+        svcProps.put(Constants.SERVICE_DESCRIPTION, "DataSource service looked up from " + jndiName);
+        dsRegistration = bundleContext.registerService(javax.sql.DataSource.class, dataSource, svcProps);
+
+        log.info("Registered DataSource [{}] looked up from JNDI at [{}]", name, jndiName);
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        if (dsRegistration != null) {
+            dsRegistration.unregister();
+            dsRegistration = null;
+        }
+    }
+
+    private DataSource lookupDataSource(String jndiName, Map<String, ?> config) throws NamingException {
+        Properties jndiProps = createJndiEnv(config);
+        Context context = null;
+        try {
+            log.debug("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)) {
+                throw new IllegalStateException("JNDI object of type " + lookup.getClass() +
+                        "is not an instance of javax.sql.DataSource");
+            }
+
+            return (DataSource) lookup;
+        } finally {
+            if (context != null) {
+                context.close();
+            }
+        }
+    }
+
+    private Properties createJndiEnv(Map<String, ?> config) {
+        Properties props = new Properties();
+
+        //Copy the other properties first
+        Map<String, String> otherProps = PropertiesUtil.toMap(config.get(PROP_JNDI_PROPS), new String[0]);
+        for (Map.Entry<String, String> 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);
+        }
+    }
+}
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
index 0984696..f2acb93 100644
--- a/src/main/resources/OSGI-INF/metatype/metatype.properties
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -130,7 +130,7 @@ logValidationErrors.name=Log Validation Error
 logValidationErrors.description=Set this to true to log errors during the validation phase to the log file
 
 datasource.svc.prop.name.name=DataSource Service Property Name
-datasource.svc.prop.name.name.description=Name of the service property which would store the DataSource Name while\
+datasource.svc.prop.name.description=Name of the service property which would store the DataSource Name while\
   registering the DataSource instance as OSGi service
 
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.