Author: fhanik
Date: Thu Jan 6 18:22:34 2011
New Revision: 1055989
URL: http://svn.apache.org/viewvc?rev=1055989&view=rev
Log:
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
Added:
tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java
(with props)
Modified:
tomcat/trunk/webapps/docs/changelog.xml
tomcat/trunk/webapps/docs/config/context.xml
Added: tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java?rev=1055989&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java
(added)
+++ tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java Thu
Jan 6 18:22:34 2011
@@ -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;
+
+
+
+/**
+ * <p>Object factory for resource links for shared data sources.</p>
+ *
+ * @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());
+ }
+ }
+
+ }
+
+
+
+
+}
Propchange:
tomcat/trunk/java/org/apache/naming/factory/DataSourceLinkFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1055989&r1=1055988&r2=1055989&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jan 6 18:22:34 2011
@@ -44,6 +44,9 @@
<section name="Tomcat 7.0.6 (markt)">
<subsection name="Catalina">
<changelog>
+ <fix><bug>49543</bug> Allow Tomcat to use shared data sources with
+ per application credentials. (fhanik)
+ </fix>
<fix>
<bug>8705</bug>: <code>org.apache.catalina.SessionListener</code> now
extends <code>java.util.EventListener</code>. (markt)
Modified: tomcat/trunk/webapps/docs/config/context.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/context.xml?rev=1055989&r1=1055988&r2=1055989&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/context.xml (original)
+++ tomcat/trunk/webapps/docs/config/context.xml Thu Jan 6 18:22:34 2011
@@ -979,8 +979,68 @@
application when it performs a lookup for this resource link.</p>
</attribute>
+ <attribute name="factory" required="false">
+ <p>The fully qualified Java class name for the class creating these
objects.
+ This class should implement the
<code>javax.naming.spi.ObjectFactory</code> interface.</p>
+ </attribute>
</attributes>
+
+ <p>When the attribute
<code>factory="org.apache.naming.factory.DataSourceLinkFactory"</code>
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
<code>javax.sql.DataSource</code>
+ type, different contexts can share a global data source with different
credentials.
+ Under the hood, what happens is that a call to <a
href="http://download.oracle.com/javase/6/docs/api/javax/sql/DataSource.html#getConnection()"><code>getConnection()</code></a>
+ is simply translated to a call <a
href="http://download.oracle.com/javase/6/docs/api/javax/sql/DataSource.html#getConnection(java.lang.String,%20java.lang.String)">
+ <code>getConnection(username, password)</code></a> 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.
+ </p>
+ <attributes>
+
+ <attribute name="username" required="false">
+ <p></p>
+ </attribute>
+ <attribute name="password" required="false">
+ <p></p>
+ </attribute>
+
+ </attributes>
+ <p>Shared Data Source Example</p>
+<source>
+<GlobalNamingResources ...>
+ ...
+ <Resource name="sharedDataSource"
+ global="sharedDataSource"
+ type="javax.sql.DataSource"
+ username="bar"
+ password="barpass"
+
+ ...
+ ...
+</GlobalNamingResources>
+
+<Context path="/foo"...>
+ ...
+ <ResourceLink
+ name="appDataSource"
+ global="sharedDataSource"
+ type="javax.sql.DataSource"
+ factory="org.apache.naming.factory.DataSourceLinkFactory"
+ username="foo"
+ password="foopass"
+ ...
+</Context>
+<Context path="/bar"...>
+ ...
+ <ResourceLink
+ name="appDataSource"
+ global="sharedDataSource"
+ type="javax.sql.DataSource"
+ ...
+</Context>
+</source>
+ <p>When a request for <code>getConnection()</code> is made in the
<code>/foo</code> context, the request is translated into
+ <code>getConnection("foo","foopass")</code>, while
a request in the <code>/bar</code> gets passed straight through.</p>
</subsection>
<subsection name="Transaction">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]