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 * <bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> 044 * <property name="jndiName" value="java:comp/env/cci/mycf"/> 045 * </bean> 046 * 047 * <bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"> 048 * <property name="targetConnectionFactory" ref="myTargetConnectionFactory"/> 049 * <property name="connectionSpec"> 050 * <bean class="your.resource.adapter.ConnectionSpecImpl"> 051 * <property name="username" value="myusername"/> 052 * <property name="password" value="mypassword"/> 053 * </bean> 054 * </property> 055 * </bean></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}