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