1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. 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 package org.apache.commons.dbcp;
19
20 import java.util.ArrayList;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import org.apache.commons.pool.PoolableObjectFactory;
25 import org.apache.commons.pool.impl.GenericObjectPool;
26
27 /**
28 * <p>An implementation of a Jakarta-Commons ObjectPool which
29 * tracks JDBC connections and can recover abandoned db connections.
30 * If logAbandoned=true, a stack trace will be printed for any
31 * abandoned db connections recovered.
32 *
33 * @author Glenn L. Nielsen
34 * @version $Revision: 482015 $ $Date: 2006-12-03 19:22:09 -0700 (Sun, 03 Dec 2006) $
35 * @deprecated This will be removed in a future version of DBCP.
36 */
37 public class AbandonedObjectPool extends GenericObjectPool {
38
39 /**
40 * DBCP AbandonedConfig
41 */
42 private AbandonedConfig config = null;
43
44 /**
45 * A list of connections in use
46 */
47 private List trace = new ArrayList();
48
49 /**
50 * Create an ObjectPool which tracks db connections.
51 *
52 * @param factory PoolableObjectFactory used to create this
53 * @param config configuration for abandoned db connections
54 */
55 public AbandonedObjectPool(PoolableObjectFactory factory,
56 AbandonedConfig config) {
57 super(factory);
58 this.config = config;
59 System.out.println("AbandonedObjectPool is used (" + this + ")");
60 System.out.println(" LogAbandoned: " + config.getLogAbandoned());
61 System.out.println(" RemoveAbandoned: " + config.getRemoveAbandoned());
62 System.out.println(" RemoveAbandonedTimeout: " + config.getRemoveAbandonedTimeout());
63 }
64
65 /**
66 * Get a db connection from the pool.
67 *
68 * If removeAbandoned=true, recovers db connections which
69 * have been idle > removeAbandonedTimeout and
70 * getNumActive() > getMaxActive() - 3 and
71 * getNumIdle() < 2
72 *
73 * @return Object jdbc Connection
74 * @throws Exception if an exception occurs retrieving a
75 * connection from the pool
76 */
77 public Object borrowObject() throws Exception {
78 if (config != null
79 && config.getRemoveAbandoned()
80 && (getNumIdle() < 2)
81 && (getNumActive() > getMaxActive() - 3) ) {
82 removeAbandoned();
83 }
84 Object obj = super.borrowObject();
85 if (obj instanceof AbandonedTrace) {
86 ((AbandonedTrace) obj).setStackTrace();
87 }
88 if (obj != null && config != null && config.getRemoveAbandoned()) {
89 synchronized (trace) {
90 trace.add(obj);
91 }
92 }
93 return obj;
94 }
95
96 /**
97 * Return a db connection to the pool.
98 *
99 * @param obj db Connection to return
100 * @throws Exception if an exception occurs returning the connection
101 * to the pool
102 */
103 public void returnObject(Object obj) throws Exception {
104 if (config != null && config.getRemoveAbandoned()) {
105 synchronized (trace) {
106 boolean foundObject = trace.remove(obj);
107 if (!foundObject) {
108 return; // This connection has already been invalidated. Stop now.
109 }
110 }
111 }
112 super.returnObject(obj);
113 }
114
115 /**
116 * Invalidates an object from the pool.
117 *
118 * @param obj object to be returned
119 * @throws Exception if an exception occurs invalidating the object
120 */
121 public void invalidateObject(Object obj) throws Exception {
122 if (config != null && config.getRemoveAbandoned()) {
123 synchronized (trace) {
124 boolean foundObject = trace.remove(obj);
125 if (!foundObject) {
126 return; // This connection has already been invalidated. Stop now.
127 }
128 }
129 }
130 super.invalidateObject(obj);
131 }
132
133 /**
134 * Recover abandoned db connections which have been idle
135 * greater than the removeAbandonedTimeout.
136 */
137 private void removeAbandoned() {
138 // Generate a list of abandoned connections to remove
139 long now = System.currentTimeMillis();
140 long timeout = now - (config.getRemoveAbandonedTimeout() * 1000);
141 ArrayList remove = new ArrayList();
142 synchronized (trace) {
143 Iterator it = trace.iterator();
144 while (it.hasNext()) {
145 AbandonedTrace pc = (AbandonedTrace) it.next();
146 if (pc.getLastUsed() > timeout) {
147 continue;
148 }
149 if (pc.getLastUsed() > 0) {
150 remove.add(pc);
151 }
152 }
153 }
154
155 // Now remove the abandoned connections
156 Iterator it = remove.iterator();
157 while (it.hasNext()) {
158 AbandonedTrace pc = (AbandonedTrace) it.next();
159 if (config.getLogAbandoned()) {
160 pc.printStackTrace();
161 }
162 try {
163 invalidateObject(pc);
164 } catch (Exception e) {
165 e.printStackTrace();
166 }
167
168 }
169 }
170 }
171