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.Iterator;
022 import java.util.Map;
023
024 import javax.resource.ResourceException;
025 import javax.resource.spi.ConnectionRequestInfo;
026 import javax.security.auth.Subject;
027
028 import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
029
030 /**
031 * MultiPoolConnectionInterceptor maps the provided subject and connection request info to a
032 * "SinglePool". This can be used to make sure all matches will succeed, avoiding synchronization
033 * slowdowns.
034 *
035 * Created: Fri Oct 10 12:53:11 2003
036 *
037 * @version $Rev: 550546 $ $Date: 2007-06-25 12:52:11 -0400 (Mon, 25 Jun 2007) $
038 */
039 public class MultiPoolConnectionInterceptor implements ConnectionInterceptor, PoolingAttributes{
040
041 private final ConnectionInterceptor next;
042 private final PoolingSupport singlePoolFactory;
043
044 private final boolean useSubject;
045
046 private final boolean useCRI;
047
048 private final Map pools = new HashMap();
049
050 // volatile is not necessary, here, because of synchronization. but maintained for consistency with other Interceptors...
051 private volatile boolean destroyed = false;
052
053 public MultiPoolConnectionInterceptor(
054 final ConnectionInterceptor next,
055 PoolingSupport singlePoolFactory,
056 final boolean useSubject,
057 final boolean useCRI) {
058 this.next = next;
059 this.singlePoolFactory = singlePoolFactory;
060 this.useSubject = useSubject;
061 this.useCRI = useCRI;
062 }
063
064 public void getConnection(ConnectionInfo connectionInfo) throws ResourceException {
065 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
066 SubjectCRIKey key =
067 new SubjectCRIKey(
068 useSubject ? mci.getSubject() : null,
069 useCRI ? mci.getConnectionRequestInfo() : null);
070 ConnectionInterceptor poolInterceptor = null;
071 synchronized (pools) {
072 if (destroyed) {
073 throw new ResourceException("ConnectionManaged has been destroyed");
074 }
075 poolInterceptor = (ConnectionInterceptor) pools.get(key);
076 if (poolInterceptor == null) {
077 poolInterceptor = singlePoolFactory.addPoolingInterceptors(next);
078 pools.put(key, poolInterceptor);
079 }
080 }
081 mci.setPoolInterceptor(poolInterceptor);
082 poolInterceptor.getConnection(connectionInfo);
083 }
084
085 // let underlying pools handle destroyed processing...
086 public void returnConnection(
087 ConnectionInfo connectionInfo,
088 ConnectionReturnAction connectionReturnAction) {
089 ManagedConnectionInfo mci = connectionInfo.getManagedConnectionInfo();
090 ConnectionInterceptor poolInterceptor = mci.getPoolInterceptor();
091 poolInterceptor.returnConnection(connectionInfo, connectionReturnAction);
092 }
093
094 public void destroy() {
095 synchronized (pools) {
096 destroyed = true;
097 for (Iterator it = pools.entrySet().iterator(); it.hasNext(); ) {
098 ((ConnectionInterceptor)((Map.Entry)it.next()).getValue()).destroy();
099 it.remove();
100 }
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 (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
116 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
117 poolingAttributes.setPartitionMaxSize(maxSize);
118 }
119 }
120
121 public int getPartitionMinSize() {
122 return singlePoolFactory.getPartitionMinSize();
123 }
124
125 public void setPartitionMinSize(int minSize) {
126 singlePoolFactory.setPartitionMinSize(minSize);
127 for (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
128 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
129 poolingAttributes.setPartitionMinSize(minSize);
130 }
131 }
132
133 public int getIdleConnectionCount() {
134 int count = 0;
135 for (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
136 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
137 count += poolingAttributes.getIdleConnectionCount();
138 }
139 return count;
140 }
141
142 public int getConnectionCount() {
143 int count = 0;
144 for (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
145 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
146 count += poolingAttributes.getConnectionCount();
147 }
148 return count;
149 }
150
151 public int getBlockingTimeoutMilliseconds() {
152 return singlePoolFactory.getBlockingTimeoutMilliseconds();
153 }
154
155 public void setBlockingTimeoutMilliseconds(int timeoutMilliseconds) {
156 singlePoolFactory.setBlockingTimeoutMilliseconds(timeoutMilliseconds);
157 for (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
158 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
159 poolingAttributes.setBlockingTimeoutMilliseconds(timeoutMilliseconds);
160 }
161 }
162
163 public int getIdleTimeoutMinutes() {
164 return singlePoolFactory.getIdleTimeoutMinutes();
165 }
166
167 public void setIdleTimeoutMinutes(int idleTimeoutMinutes) {
168 singlePoolFactory.setIdleTimeoutMinutes(idleTimeoutMinutes);
169 for (Iterator iterator = pools.entrySet().iterator(); iterator.hasNext();) {
170 PoolingAttributes poolingAttributes = (PoolingAttributes) ((Map.Entry) iterator.next()).getValue();
171 poolingAttributes.setIdleTimeoutMinutes(idleTimeoutMinutes);
172 }
173 }
174
175 static class SubjectCRIKey {
176 private final Subject subject;
177 private final ConnectionRequestInfo cri;
178 private final int hashcode;
179
180 public SubjectCRIKey(
181 final Subject subject,
182 final ConnectionRequestInfo cri) {
183 this.subject = subject;
184 this.cri = cri;
185 this.hashcode =
186 (subject == null ? 17 : subject.hashCode() * 17)
187 ^ (cri == null ? 1 : cri.hashCode());
188 }
189
190 public int hashCode() {
191 return hashcode;
192 }
193
194 public boolean equals(Object other) {
195 if (!(other instanceof SubjectCRIKey)) {
196 return false;
197 } // end of if ()
198 SubjectCRIKey o = (SubjectCRIKey) other;
199 if (hashcode != o.hashcode) {
200 return false;
201 } // end of if ()
202 return subject == null
203 ? o.subject == null
204 : subject.equals(o.subject)
205 && cri == null ? o.cri == null : cri.equals(o.cri);
206 }
207 }
208 } // MultiPoolConnectionInterceptor