001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.connector.outbound;
019
020 import java.util.HashMap;
021 import java.util.Map;
022
023 import javax.resource.ResourceException;
024 import javax.resource.spi.ConnectionRequestInfo;
025 import javax.security.auth.Subject;
026
027 import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
028
029 /**
030 * MultiPoolConnectionInterceptor maps the provided subject and connection request info to a
031 * "SinglePool". This can be used to make sure all matches will succeed, avoiding synchronization
032 * slowdowns.
033 *
034 * Created: Fri Oct 10 12:53:11 2003
035 *
036 * @version $Rev: 585608 $ $Date: 2007-10-17 13:56:54 -0400 (Wed, 17 Oct 2007) $
037 */
038 public class MultiPoolConnectionInterceptor implements ConnectionInterceptor, PoolingAttributes{
039
040 private final ConnectionInterceptor next;
041 private final PoolingSupport singlePoolFactory;
042
043 private final boolean useSubject;
044
045 private final boolean useCRI;
046
047 private final Map<SubjectCRIKey,PoolingAttributes> pools = new HashMap<SubjectCRIKey,PoolingAttributes>();
048
049 // volatile is not necessary, here, because of synchronization. but maintained for consistency with other Interceptors...
050 private volatile boolean destroyed = false;
051
052 public MultiPoolConnectionInterceptor(
053 final ConnectionInterceptor next,
054 PoolingSupport singlePoolFactory,
055 final boolean useSubject,
056 final boolean useCRI) {
057 this.next = next;
058 this.singlePoolFactory = singlePoolFactory;
059 this.useSubject = useSubject;
060 this.useCRI = useCRI;
061 }
062
063 public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
064 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
065 SubjectCRIKey key =
066 new SubjectCRIKey(
067 useSubject ? mci.getSubject() : null,
068 useCRI ? mci.getConnectionRequestInfo() : null);
069 ConnectionInterceptor poolInterceptor = null;
070 synchronized (pools) {
071 if (destroyed) {
072 throw new ResourceException("ConnectionManaged has been destroyed");
073 }
074 poolInterceptor = (ConnectionInterceptor) pools.get(key);
075 if (poolInterceptor == null) {
076 poolInterceptor = singlePoolFactory.addPoolingInterceptors(next);
077 pools.put(key, (PoolingAttributes) poolInterceptor);
078 }
079 }
080 mci.setPoolInterceptor(poolInterceptor);
081 poolInterceptor.getConnection(connectionInfo);
082 }
083
084 // let underlying pools handle destroyed processing...
085 public void returnConnection(
086 ConnectionInfo connectionInfo,
087 ConnectionReturnAction connectionReturnAction) {
088 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
089 ConnectionInterceptor poolInterceptor = mci.getPoolInterceptor();
090 poolInterceptor.returnConnection(connectionInfo, connectionReturnAction);
091 }
092
093 public void destroy() {
094 synchronized (pools) {
095 destroyed = true;
096 for (PoolingAttributes poolingAttributes : pools.values()) {
097 ConnectionInterceptor poolInterceptor = (ConnectionInterceptor) poolingAttributes;
098 poolInterceptor.destroy();
099 }
100 pools.clear();
101 }
102 next.destroy();
103 }
104
105 public int getPartitionCount() {
106 return pools.size();
107 }
108
109 public int getPartitionMaxSize() {
110 return singlePoolFactory.getPartitionMaxSize();
111 }
112
113 public void setPartitionMaxSize(int maxSize) throws InterruptedException {
114 singlePoolFactory.setPartitionMaxSize(maxSize);
115 for (PoolingAttributes poolingAttributes : pools.values()) {
116 poolingAttributes.setPartitionMaxSize(maxSize);
117 }
118 }
119
120 public int getPartitionMinSize() {
121 return singlePoolFactory.getPartitionMinSize();
122 }
123
124 public void setPartitionMinSize(int minSize) {
125 singlePoolFactory.setPartitionMinSize(minSize);
126 for (PoolingAttributes poolingAttributes : pools.values()) {
127 poolingAttributes.setPartitionMinSize(minSize);
128 }
129 }
130
131 public int getIdleConnectionCount() {
132 int count = 0;
133 for (PoolingAttributes poolingAttributes : pools.values()) {
134 count += poolingAttributes.getIdleConnectionCount();
135 }
136 return count;
137 }
138
139 public int getConnectionCount() {
140 int count = 0;
141 for (PoolingAttributes poolingAttributes : pools.values()) {
142 count += poolingAttributes.getConnectionCount();
143 }
144 return count;
145 }
146
147 public int getBlockingTimeoutMilliseconds() {
148 return singlePoolFactory.getBlockingTimeoutMilliseconds();
149 }
150
151 public void setBlockingTimeoutMilliseconds(int timeoutMilliseconds) {
152 singlePoolFactory.setBlockingTimeoutMilliseconds(timeoutMilliseconds);
153 for (PoolingAttributes poolingAttributes : pools.values()) {
154 poolingAttributes.setBlockingTimeoutMilliseconds(timeoutMilliseconds);
155 }
156 }
157
158 public int getIdleTimeoutMinutes() {
159 return singlePoolFactory.getIdleTimeoutMinutes();
160 }
161
162 public void setIdleTimeoutMinutes(int idleTimeoutMinutes) {
163 singlePoolFactory.setIdleTimeoutMinutes(idleTimeoutMinutes);
164 for (PoolingAttributes poolingAttributes : pools.values()) {
165 poolingAttributes.setIdleTimeoutMinutes(idleTimeoutMinutes);
166 }
167 }
168
169 static class SubjectCRIKey {
170 private final Subject subject;
171 private final ConnectionRequestInfo cri;
172 private final int hashcode;
173
174 public SubjectCRIKey(
175 final Subject subject,
176 final ConnectionRequestInfo cri) {
177 this.subject = subject;
178 this.cri = cri;
179 this.hashcode =
180 (subject == null ? 17 : subject.hashCode() * 17)
181 ^ (cri == null ? 1 : cri.hashCode());
182 }
183
184 public int hashCode() {
185 return hashcode;
186 }
187
188 public boolean equals(Object other) {
189 if (!(other instanceof SubjectCRIKey)) {
190 return false;
191 }
192 SubjectCRIKey o = (SubjectCRIKey) other;
193 return hashcode == o.hashcode &&
194 (subject == null ? o.subject == null : subject.equals(o.subject) &&
195 cri == null ? o.cri == null : cri.equals(o.cri));
196 }
197 }
198 }