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 19:56:54 +0200 (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    }