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.lang.Nullable; 026import org.springframework.util.Assert; 027 028/** 029 * An adapter for a target CCI {@link javax.resource.cci.ConnectionFactory}, 030 * applying the given ConnectionSpec to every standard {@code getConnection()} 031 * call, that is, implicitly invoking {@code getConnection(ConnectionSpec)} 032 * on the target. All other methods simply delegate to the corresponding methods 033 * of the target ConnectionFactory. 034 * 035 * <p>Can be used to proxy a target JNDI ConnectionFactory that does not have a 036 * ConnectionSpec configured. Client code can work with the ConnectionFactory 037 * without passing in a ConnectionSpec on every {@code getConnection()} call. 038 * 039 * <p>In the following example, client code can simply transparently work with 040 * the preconfigured "myConnectionFactory", implicitly accessing 041 * "myTargetConnectionFactory" with the specified user credentials. 042 * 043 * <pre class="code"> 044 * <bean id="myTargetConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> 045 * <property name="jndiName" value="java:comp/env/cci/mycf"/> 046 * </bean> 047 * 048 * <bean id="myConnectionFactory" class="org.springframework.jca.cci.connection.ConnectionSpecConnectionFactoryAdapter"> 049 * <property name="targetConnectionFactory" ref="myTargetConnectionFactory"/> 050 * <property name="connectionSpec"> 051 * <bean class="your.resource.adapter.ConnectionSpecImpl"> 052 * <property name="username" value="myusername"/> 053 * <property name="password" value="mypassword"/> 054 * </bean> 055 * </property> 056 * </bean></pre> 057 * 058 * <p>If the "connectionSpec" is empty, this proxy will simply delegate to the 059 * standard {@code getConnection()} method of the target ConnectionFactory. 060 * This can be used to keep a UserCredentialsConnectionFactoryAdapter bean definition 061 * just for the <i>option</i> of implicitly passing in a ConnectionSpec if the 062 * particular target ConnectionFactory requires it. 063 * 064 * @author Juergen Hoeller 065 * @since 1.2 066 * @see #getConnection 067 */ 068@SuppressWarnings("serial") 069public class ConnectionSpecConnectionFactoryAdapter extends DelegatingConnectionFactory { 070 071 @Nullable 072 private ConnectionSpec connectionSpec; 073 074 private final ThreadLocal<ConnectionSpec> threadBoundSpec = 075 new NamedThreadLocal<>("Current CCI ConnectionSpec"); 076 077 078 /** 079 * Set the ConnectionSpec that this adapter should use for retrieving Connections. 080 * Default is none. 081 */ 082 public void setConnectionSpec(ConnectionSpec connectionSpec) { 083 this.connectionSpec = connectionSpec; 084 } 085 086 /** 087 * Set a ConnectionSpec for this proxy and the current thread. 088 * The given ConnectionSpec will be applied to all subsequent 089 * {@code getConnection()} calls on this ConnectionFactory proxy. 090 * <p>This will override any statically specified "connectionSpec" property. 091 * @param spec the ConnectionSpec to apply 092 * @see #removeConnectionSpecFromCurrentThread 093 */ 094 public void setConnectionSpecForCurrentThread(ConnectionSpec spec) { 095 this.threadBoundSpec.set(spec); 096 } 097 098 /** 099 * Remove any ConnectionSpec for this proxy from the current thread. 100 * A statically specified ConnectionSpec applies again afterwards. 101 * @see #setConnectionSpecForCurrentThread 102 */ 103 public void removeConnectionSpecFromCurrentThread() { 104 this.threadBoundSpec.remove(); 105 } 106 107 108 /** 109 * Determine whether there is currently a thread-bound ConnectionSpec, 110 * using it if available, falling back to the statically specified 111 * "connectionSpec" property else. 112 * @see #doGetConnection 113 */ 114 @Override 115 public final Connection getConnection() throws ResourceException { 116 ConnectionSpec threadSpec = this.threadBoundSpec.get(); 117 if (threadSpec != null) { 118 return doGetConnection(threadSpec); 119 } 120 else { 121 return doGetConnection(this.connectionSpec); 122 } 123 } 124 125 /** 126 * This implementation delegates to the {@code getConnection(ConnectionSpec)} 127 * method of the target ConnectionFactory, passing in the specified user credentials. 128 * If the specified username is empty, it will simply delegate to the standard 129 * {@code getConnection()} method of the target ConnectionFactory. 130 * @param spec the ConnectionSpec to apply 131 * @return the Connection 132 * @see javax.resource.cci.ConnectionFactory#getConnection(javax.resource.cci.ConnectionSpec) 133 * @see javax.resource.cci.ConnectionFactory#getConnection() 134 */ 135 protected Connection doGetConnection(@Nullable ConnectionSpec spec) throws ResourceException { 136 ConnectionFactory connectionFactory = getTargetConnectionFactory(); 137 Assert.state(connectionFactory != null, "No 'targetConnectionFactory' set"); 138 return (spec != null ? connectionFactory.getConnection(spec) : connectionFactory.getConnection()); 139 } 140 141}