001/*
002 * Copyright 2002-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jca.cci.connection;
018
019import javax.resource.ResourceException;
020import javax.resource.cci.Connection;
021import javax.resource.cci.ConnectionFactory;
022import javax.resource.cci.ConnectionSpec;
023
024import org.springframework.core.NamedThreadLocal;
025import org.springframework.util.Assert;
026
027/**
028 * An adapter for a target CCI {@link javax.resource.cci.ConnectionFactory},
029 * applying the given ConnectionSpec to every standard {@code getConnection()}
030 * call, that is, implicitly invoking {@code getConnection(ConnectionSpec)}
031 * on the target. All other methods simply delegate to the corresponding methods
032 * of the target ConnectionFactory.
033 *
034 * <p>Can be used to proxy a target JNDI ConnectionFactory that does not have a
035 * ConnectionSpec configured. Client code can work with the ConnectionFactory
036 * without passing in a ConnectionSpec on every {@code getConnection()} call.
037 *
038 * <p>In the following example, client code can simply transparently work with
039 * the preconfigured "myConnectionFactory", implicitly accessing
040 * "myTargetConnectionFactory" with the specified user credentials.
041 *
042 * <pre class="code">
043 * &lt;bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&gt;
044 *   &lt;property name="jndiName" value="java:comp/env/cci/mycf"/&gt;
045 * &lt;/bean>
046 *
047 * &lt;bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"&gt;
048 *   &lt;property name="targetConnectionFactory" ref="myTargetConnectionFactory"/&gt;
049 *   &lt;property name="connectionSpec"&gt;
050 *     &lt;bean class="your.resource.adapter.ConnectionSpecImpl"&gt;
051 *       &lt;property name="username" value="myusername"/&gt;
052 *       &lt;property name="password" value="mypassword"/&gt;
053 *     &lt;/bean&gt;
054 *   &lt;/property&gt;
055 * &lt;/bean&gt;</pre>
056 *
057 * <p>If the "connectionSpec" is empty, this proxy will simply delegate to the
058 * standard {@code getConnection()} method of the target ConnectionFactory.
059 * This can be used to keep a UserCredentialsConnectionFactoryAdapter bean definition
060 * just for the <i>option</i> of implicitly passing in a ConnectionSpec if the
061 * particular target ConnectionFactory requires it.
062 *
063 * @author Juergen Hoeller
064 * @since 1.2
065 * @see #getConnection
066 */
067@SuppressWarnings("serial")
068public class ConnectionSpecConnectionFactoryAdapter extends DelegatingConnectionFactory {
069
070        private ConnectionSpec connectionSpec;
071
072        private final ThreadLocal<ConnectionSpec> threadBoundSpec =
073                        new NamedThreadLocal<ConnectionSpec>("Current CCI ConnectionSpec");
074
075
076        /**
077         * Set the ConnectionSpec that this adapter should use for retrieving Connections.
078         * Default is none.
079         */
080        public void setConnectionSpec(ConnectionSpec connectionSpec) {
081                this.connectionSpec = connectionSpec;
082        }
083
084        /**
085         * Set a ConnectionSpec for this proxy and the current thread.
086         * The given ConnectionSpec will be applied to all subsequent
087         * {@code getConnection()} calls on this ConnectionFactory proxy.
088         * <p>This will override any statically specified "connectionSpec" property.
089         * @param spec the ConnectionSpec to apply
090         * @see #removeConnectionSpecFromCurrentThread
091         */
092        public void setConnectionSpecForCurrentThread(ConnectionSpec spec) {
093                this.threadBoundSpec.set(spec);
094        }
095
096        /**
097         * Remove any ConnectionSpec for this proxy from the current thread.
098         * A statically specified ConnectionSpec applies again afterwards.
099         * @see #setConnectionSpecForCurrentThread
100         */
101        public void removeConnectionSpecFromCurrentThread() {
102                this.threadBoundSpec.remove();
103        }
104
105
106        /**
107         * Determine whether there is currently a thread-bound ConnectionSpec,
108         * using it if available, falling back to the statically specified
109         * "connectionSpec" property else.
110         * @see #doGetConnection
111         */
112        @Override
113        public final Connection getConnection() throws ResourceException {
114                ConnectionSpec threadSpec = this.threadBoundSpec.get();
115                if (threadSpec != null) {
116                        return doGetConnection(threadSpec);
117                }
118                else {
119                        return doGetConnection(this.connectionSpec);
120                }
121        }
122
123        /**
124         * This implementation delegates to the {@code getConnection(ConnectionSpec)}
125         * method of the target ConnectionFactory, passing in the specified user credentials.
126         * If the specified username is empty, it will simply delegate to the standard
127         * {@code getConnection()} method of the target ConnectionFactory.
128         * @param spec the ConnectionSpec to apply
129         * @return the Connection
130         * @see javax.resource.cci.ConnectionFactory#getConnection(javax.resource.cci.ConnectionSpec)
131         * @see javax.resource.cci.ConnectionFactory#getConnection()
132         */
133        protected Connection doGetConnection(ConnectionSpec spec) throws ResourceException {
134                ConnectionFactory connectionFactory = getTargetConnectionFactory();
135                Assert.state(connectionFactory != null, "No 'targetConnectionFactory' set");
136                return (spec != null ? connectionFactory.getConnection(spec) : connectionFactory.getConnection());
137        }
138
139}