1 package org.apache.ojb.broker.accesslayer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
28 import java.sql.ResultSet;
29 import java.sql.SQLException;
30 import java.sql.PreparedStatement;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.Map;
35 import java.util.NoSuchElementException;
36
37
38
39
40
41
42
43
44
45 public class ConnectionFactoryPooledImpl extends ConnectionFactoryAbstractImpl
46 {
47
48 private Logger log = LoggerFactory.getLogger(ConnectionFactoryPooledImpl.class);
49
50 private Map poolMap = new HashMap();
51
52 private final Object poolSynch = new Object();
53
54 public void releaseJdbcConnection(JdbcConnectionDescriptor jcd, Connection con)
55 throws LookupException
56 {
57 final ObjectPool op = (ObjectPool) poolMap.get(jcd.getPBKey());
58 try
59 {
60
61
62
63
64
65
66
67
68
69
70 op.returnObject(con);
71 }
72 catch (Exception e)
73 {
74 throw new LookupException(e);
75 }
76 }
77
78 public Connection 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 conn;
91 try
92 {
93 conn = (Connection) op.borrowObject();
94 }
95 catch (NoSuchElementException 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 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 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 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
128
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
140
141 public void releaseAllResources()
142 {
143 synchronized (poolSynch)
144 {
145 Collection pools = poolMap.values();
146 poolMap = new HashMap(poolMap.size());
147 ObjectPool op = null;
148 for (Iterator iterator = pools.iterator(); iterator.hasNext();)
149 {
150 try
151 {
152 op = ((ObjectPool) iterator.next());
153 op.close();
154 }
155 catch (Exception e)
156 {
157 log.error("Exception occured while closing pool " + op, e);
158 }
159 }
160 }
161 super.releaseAllResources();
162 }
163
164 /
165
166
167
168
169
170
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 obj)
185 {
186 boolean isValid = false;
187 if (obj != null)
188 {
189 final Connection con = (Connection) obj;
190 try
191 {
192 isValid = !con.isClosed();
193 }
194 catch (SQLException 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 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 conn, String query)
214 {
215 PreparedStatement stmt = null;
216 ResultSet 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 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 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 t)
265 {
266 if (log.isDebugEnabled()) log.debug("Statement already closed.", t);
267 }
268 }
269 return isValid;
270 }
271
272 public Object makeObject() throws Exception
273 {
274 if (log.isDebugEnabled()) log.debug("makeObject called");
275 return cf.newConnectionFromDriverManager(jcd);
276 }
277
278 public void destroyObject(Object obj)
279 throws Exception
280 {
281 log.info("Destroy object was called, try to close connection: " + obj);
282 try
283 {
284 ((Connection) obj).close();
285 }
286 catch (SQLException ignore)
287 {
288
289 }
290 }
291 }
292
293 }