KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > accesslayer > ConnectionFactoryPooledImpl


1 package org.apache.ojb.broker.accesslayer;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import org.apache.commons.pool.BasePoolableObjectFactory;
19 import org.apache.commons.pool.ObjectPool;
20 import org.apache.commons.pool.PoolableObjectFactory;
21 import org.apache.commons.pool.impl.GenericObjectPool;
22 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
23 import org.apache.ojb.broker.util.logging.Logger;
24 import org.apache.ojb.broker.util.logging.LoggerFactory;
25 import org.apache.ojb.broker.OJBRuntimeException;
26
27 import java.sql.Connection JavaDoc;
28 import java.sql.ResultSet JavaDoc;
29 import java.sql.SQLException JavaDoc;
30 import java.sql.PreparedStatement JavaDoc;
31 import java.util.Collection JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.NoSuchElementException JavaDoc;
36
37 /**
38  * Connection factory which pools the requested
39  * connections for different JdbcConnectionDescriptors
40  * using Commons Pool API.
41  *
42  * @version $Id: ConnectionFactoryPooledImpl.java,v 1.15.2.9 2005/10/27 14:54:50 arminw Exp $
43  * @see <a HREF="http://jakarta.apache.org/commons/pool/">Commons Pool Website</a>
44  */

45 public class ConnectionFactoryPooledImpl extends ConnectionFactoryAbstractImpl
46 {
47
48     private Logger log = LoggerFactory.getLogger(ConnectionFactoryPooledImpl.class);
49     /** Key=PBKey, value=ObjectPool. */
50     private Map JavaDoc poolMap = new HashMap JavaDoc();
51     /** Synchronize object for operations not synchronized on Map only. */
52     private final Object JavaDoc poolSynch = new Object JavaDoc();
53
54     public void releaseJdbcConnection(JdbcConnectionDescriptor jcd, Connection JavaDoc con)
55             throws LookupException
56     {
57         final ObjectPool op = (ObjectPool) poolMap.get(jcd.getPBKey());
58         try
59         {
60             /* mkalen: NB - according to the Commons Pool API we should _not_ perform
61              * any additional checks here since we will then break testOnX semantics
62              *
63              * To enable Connection validation on releaseJdbcConnection,
64              * set a validation query and specify testOnRelease=true
65              *
66              * Destruction of pooled objects is performed by the actual Commons Pool
67              * ObjectPool implementation when the object factory's validateObject method
68              * returns false. See ConPoolFactory#validateObject.
69              */

70             op.returnObject(con);
71         }
72         catch (Exception JavaDoc e)
73         {
74             throw new LookupException(e);
75         }
76     }
77
78     public Connection JavaDoc checkOutJdbcConnection(JdbcConnectionDescriptor jcd) throws LookupException
79     {
80         ObjectPool op = (ObjectPool) poolMap.get(jcd.getPBKey());
81         if (op == null)
82         {
83             synchronized (poolSynch)
84             {
85                 log.info("Create new connection pool:" + jcd);
86                 op = createConnectionPool(jcd);
87                 poolMap.put(jcd.getPBKey(), op);
88             }
89         }
90         final Connection JavaDoc conn;
91         try
92         {
93             conn = (Connection JavaDoc) op.borrowObject();
94         }
95         catch (NoSuchElementException JavaDoc e)
96         {
97             int active = 0;
98             int idle = 0;
99             try
100             {
101                 active = op.getNumActive();
102                 idle = op.getNumIdle();
103             }
104             catch(Exception JavaDoc ignore){}
105             throw new LookupException("Could not borrow connection from pool, seems ObjectPool is exhausted." +
106                     " Active/Idle instances in pool=" + active + "/" + idle
107                     + ". "+ JdbcConnectionDescriptor.class.getName() + ": " + jcd, e);
108         }
109         catch (Exception JavaDoc e)
110         {
111             int active = 0;
112             int idle = 0;
113             try
114             {
115                 active = op.getNumActive();
116                 idle = op.getNumIdle();
117             }
118             catch(Exception JavaDoc ignore){}
119             throw new LookupException("Could not borrow connection from pool." +
120                     " Active/Idle instances in pool=" + active + "/" + idle
121                     + ". "+ JdbcConnectionDescriptor.class.getName() + ": " + jcd, e);
122         }
123         return conn;
124     }
125
126     /**
127      * Create the pool for pooling the connections of the given connection descriptor.
128      * Override this method to implement your on {@link org.apache.commons.pool.ObjectPool}.
129      */

130     public ObjectPool createConnectionPool(JdbcConnectionDescriptor jcd)
131     {
132         if (log.isDebugEnabled()) log.debug("createPool was called");
133         PoolableObjectFactory pof = new ConPoolFactory(this, jcd);
134         GenericObjectPool.Config conf = jcd.getConnectionPoolDescriptor().getObjectPoolConfig();
135         return (ObjectPool)new GenericObjectPool(pof, conf);
136     }
137
138     /**
139      * Closes all managed pools.
140      */

141     public void releaseAllResources()
142     {
143         synchronized (poolSynch)
144         {
145             Collection JavaDoc pools = poolMap.values();
146             poolMap = new HashMap JavaDoc(poolMap.size());
147             ObjectPool op = null;
148             for (Iterator JavaDoc iterator = pools.iterator(); iterator.hasNext();)
149             {
150                 try
151                 {
152                     op = ((ObjectPool) iterator.next());
153                     op.close();
154                 }
155                 catch (Exception JavaDoc e)
156                 {
157                     log.error("Exception occured while closing pool " + op, e);
158                 }
159             }
160         }
161         super.releaseAllResources();
162     }
163
164     //**************************************************************************************
165
// Inner classes
166
//************************************************************************************
167

168     /**
169      * Inner class - {@link org.apache.commons.pool.PoolableObjectFactory}
170      * used as factory for connection pooling.
171      */

172     class ConPoolFactory extends BasePoolableObjectFactory
173     {
174         final private JdbcConnectionDescriptor jcd;
175         final private ConnectionFactoryPooledImpl cf;
176         private int failedValidationQuery;
177
178         public ConPoolFactory(ConnectionFactoryPooledImpl cf, JdbcConnectionDescriptor jcd)
179         {
180             this.cf = cf;
181             this.jcd = jcd;
182         }
183
184         public boolean validateObject(Object JavaDoc obj)
185         {
186             boolean isValid = false;
187             if (obj != null)
188             {
189                 final Connection JavaDoc con = (Connection JavaDoc) obj;
190                 try
191                 {
192                     isValid = !con.isClosed();
193                 }
194                 catch (SQLException JavaDoc e)
195                 {
196                     log.warn("Connection validation failed: " + e.getMessage());
197                     if (log.isDebugEnabled()) log.debug(e);
198                     isValid = false;
199                 }
200                 if (isValid)
201                 {
202                     final String JavaDoc validationQuery;
203                     validationQuery = jcd.getConnectionPoolDescriptor().getValidationQuery();
204                     if (validationQuery != null)
205                     {
206                         isValid = validateConnection(con, validationQuery);
207                     }
208                 }
209             }
210             return isValid;
211         }
212
213         private boolean validateConnection(Connection JavaDoc conn, String JavaDoc query)
214         {
215             PreparedStatement JavaDoc stmt = null;
216             ResultSet JavaDoc rset = null;
217             boolean isValid = false;
218             if (failedValidationQuery > 100)
219             {
220                 --failedValidationQuery;
221                 throw new OJBRuntimeException("Validation of connection "+conn+" using validation query '"+
222                         query + "' failed more than 100 times.");
223             }
224             try
225             {
226                 stmt = conn.prepareStatement(query);
227                 stmt.setMaxRows(1);
228                 stmt.setFetchSize(1);
229                 rset = stmt.executeQuery();
230                 if (rset.next())
231                 {
232                     failedValidationQuery = 0;
233                     isValid = true;
234                 }
235                 else
236                 {
237                     ++failedValidationQuery;
238                     log.warn("Validation query '" + query +
239                             "' result set does not match, discard connection");
240                     isValid = false;
241                 }
242             }
243             catch (SQLException JavaDoc e)
244             {
245                 ++failedValidationQuery;
246                 log.warn("Validation query for connection failed, discard connection. Query was '" +
247                         query + "', Message was " + e.getMessage());
248                 if (log.isDebugEnabled()) log.debug(e);
249             }
250             finally
251             {
252                 try
253                 {
254                     if(rset != null) rset.close();
255                 }
256                 catch (SQLException JavaDoc t)
257                 {
258                     if (log.isDebugEnabled()) log.debug("ResultSet already closed.", t);
259                 }
260                 try
261                 {
262                     if(stmt != null) stmt.close();
263                 }
264                 catch (SQLException JavaDoc t)
265                 {
266                     if (log.isDebugEnabled()) log.debug("Statement already closed.", t);
267                 }
268             }
269             return isValid;
270         }
271
272         public Object JavaDoc makeObject() throws Exception JavaDoc
273         {
274             if (log.isDebugEnabled()) log.debug("makeObject called");
275             return cf.newConnectionFromDriverManager(jcd);
276         }
277
278         public void destroyObject(Object JavaDoc obj)
279                 throws Exception JavaDoc
280         {
281             log.info("Destroy object was called, try to close connection: " + obj);
282             try
283             {
284                 ((Connection JavaDoc) obj).close();
285             }
286             catch (SQLException JavaDoc ignore)
287             {
288                 //ignore it
289
}
290         }
291     }
292
293 }
294
Popular Tags