From de790c35d06399f5ed56d6fe356965339add1ed2 Mon Sep 17 00:00:00 2001
From: fhanik
Date: Thu, 6 Jan 2011 18:22:34 +0000
Subject: [PATCH] https://issues.apache.org/bugzilla/show_bug.cgi?id=49543 Add
the ability to specify a data source link, to use a shared datasource with
per application credentials
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1055989 13f79535-47bb-0310-9956-ffa450edef68
---
.../naming/factory/DataSourceLinkFactory.java | 140 +++++++++++++++++++++
webapps/docs/changelog.xml | 3 +
webapps/docs/config/context.xml | 60 +++++++++
3 files changed, 203 insertions(+)
create mode 100644 java/org/apache/naming/factory/DataSourceLinkFactory.java
diff --git a/java/org/apache/naming/factory/DataSourceLinkFactory.java b/java/org/apache/naming/factory/DataSourceLinkFactory.java
new file mode 100644
index 000000000..bab654d6f
--- /dev/null
+++ b/java/org/apache/naming/factory/DataSourceLinkFactory.java
@@ -0,0 +1,140 @@
+/*
+ * 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.naming.factory;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.sql.SQLException;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.spi.ObjectFactory;
+import javax.sql.DataSource;
+
+import org.apache.naming.ResourceLinkRef;
+
+
+
+/**
+ *
Object factory for resource links for shared data sources.
+ *
+ * @author Filip Hanik
+ * @version $Id: ResourceLinkFactory.java 939311 2010-04-29 14:01:02Z kkolinko $
+ */
+
+public class DataSourceLinkFactory extends ResourceLinkFactory
+ implements ObjectFactory {
+
+
+ // -------------------------------------------------- ObjectFactory Methods
+
+
+ /**
+ * Create a new DataSource instance.
+ *
+ * @param obj The reference object describing the DataSource
+ */
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+ Hashtable,?> environment)
+ throws NamingException {
+ Object result = super.getObjectInstance(obj, name, nameCtx, environment);
+ // Can we process this request?
+ if (result!=null) {
+ Reference ref = (Reference) obj;
+
+ RefAddr userAttr = ref.get("username");
+ RefAddr passAttr = ref.get("password");
+ if (userAttr.getContent()!=null && passAttr.getContent()!=null) {
+ result = wrapDataSource(result,userAttr.getContent().toString(), passAttr.getContent().toString());
+ }
+ }
+ return result;
+ }
+
+ protected Object wrapDataSource(Object datasource, String username, String password) throws NamingException {
+ try {
+ Class> proxyClass = Proxy.getProxyClass(datasource.getClass().getClassLoader(), datasource.getClass().getInterfaces());
+ Constructor> proxyConstructor = proxyClass.getConstructor(new Class[] { InvocationHandler.class });
+ DataSourceHandler handler = new DataSourceHandler((DataSource)datasource, username, password);
+ return proxyConstructor.newInstance(handler);
+ }catch (Exception x) {
+ if (x instanceof NamingException) throw (NamingException)x;
+ else {
+ NamingException nx = new NamingException(x.getMessage());
+ nx.initCause(x);
+ throw nx;
+ }
+ }
+ }
+
+ /**
+ * Simple wrapper class that will allow a user to configure a ResourceLink for a data source
+ * so that when {@link javax.sql.DataSource#getConnection()} is called, it will invoke
+ * {@link javax.sql.DataSource#getConnection(String, String)} with the preconfigured username and password.
+ */
+ public static class DataSourceHandler implements InvocationHandler {
+ DataSource ds;
+ String username;
+ String password;
+ public DataSourceHandler(DataSource ds, String username, String password) {
+ this.ds = ds;
+ this.username = username;
+ this.password = password;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+
+ if ("getConnection".equals(method.getName()) && args.length==0) {
+ args = new String[] {username,password};
+ } else if ("unwrap".equals(method.getName())) {
+ return unwrap((Class>)args[0]);
+ }
+ try {
+ return method.invoke(ds,args);
+ }catch (Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ InvocationTargetException it = (InvocationTargetException)t;
+ throw it.getCause()!=null?it.getCause():it;
+ } else {
+ throw t;
+ }
+ }
+ }
+
+ public Object unwrap(Class> iface) throws SQLException {
+ if (iface == DataSource.class) {
+ return ds;
+ } else {
+ throw new SQLException("Not a wrapper of "+iface.getName());
+ }
+ }
+
+ }
+
+
+
+
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 862b2eccc..aad0e7ab7 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -44,6 +44,9 @@
+ 49543 Allow Tomcat to use shared data sources with
+ per application credentials. (fhanik)
+ 8705: org.apache.catalina.SessionListener now
extends java.util.EventListener. (markt)
diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml
index 90136f45b..e9dd89521 100644
--- a/webapps/docs/config/context.xml
+++ b/webapps/docs/config/context.xml
@@ -979,8 +979,68 @@
application when it performs a lookup for this resource link.
+
+
The fully qualified Java class name for the class creating these objects.
+ This class should implement the javax.naming.spi.ObjectFactory interface.
+
+
+
When the attribute factory="org.apache.naming.factory.DataSourceLinkFactory" the resource link can be used with
+ two additional attributes to allow a shared data source to be used with different credentials.
+ When these two additional attributes are used in combination with the javax.sql.DataSource
+ type, different contexts can share a global data source with different credentials.
+ Under the hood, what happens is that a call to getConnection()
+ is simply translated to a call
+ getConnection(username, password) on the global data source. This is an easy way to get code to be transparent to what schemas are being used,
+ yet be able to control connections (or pools) in the global configuration.
+
When a request for getConnection() is made in the /foo context, the request is translated into
+ getConnection("foo","foopass"), while a request in the /bar gets passed straight through.