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.text.SimpleDateFormat;
21 import java.util.ArrayList;
22 import java.util.Date;
23 import java.util.Iterator;
24 import java.util.List;
25
26 /**
27 * Tracks db connection usage for recovering and reporting
28 * abandoned db connections.
29 *
30 * The JDBC Connection, Statement, and ResultSet classes
31 * extend this class.
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 AbandonedTrace {
38
39 /** Date format */
40 private static SimpleDateFormat format = new SimpleDateFormat
41 ("'DBCP object created' yyyy-MM-dd HH:mm:ss " +
42 "'by the following code was never closed:'");
43
44 /** DBCP AbandonedConfig */
45 private AbandonedConfig config = null;
46 /** Parent object */
47 private AbandonedTrace parent;
48 /** A stack trace of the code that created me (if in debug mode) */
49 private Exception createdBy;
50 /** Time created */
51 private long createdTime;
52 /** A list of objects created by children of this object */
53 private List trace = new ArrayList();
54 /** Last time this connection was used */
55 private long lastUsed = 0;
56
57 /**
58 * Create a new AbandonedTrace without config and
59 * without doing abandoned tracing.
60 */
61 public AbandonedTrace() {
62 init(parent);
63 }
64
65 /**
66 * Construct a new AbandonedTrace with no parent object.
67 *
68 * @param config AbandonedConfig
69 */
70 public AbandonedTrace(AbandonedConfig config) {
71 this.config = config;
72 init(parent);
73 }
74
75 /**
76 * Construct a new AbandonedTrace with a parent object.
77 *
78 * @param parent AbandonedTrace parent object
79 */
80 public AbandonedTrace(AbandonedTrace parent) {
81 this.config = parent.getConfig();
82 init(parent);
83 }
84
85 /**
86 * Initialize abandoned tracing for this object.
87 *
88 * @param parent AbandonedTrace parent object
89 */
90 private void init(AbandonedTrace parent) {
91 if (parent != null) {
92 parent.addTrace(this);
93 }
94
95 if (config == null) {
96 return;
97 }
98 if (config.getLogAbandoned()) {
99 createdBy = new Exception();
100 createdTime = System.currentTimeMillis();
101 }
102 }
103
104 /**
105 * Get the abandoned config for this object.
106 *
107 * @return AbandonedConfig for this object
108 */
109 protected AbandonedConfig getConfig() {
110 return config;
111 }
112
113 /**
114 * Get the last time this object was used in ms.
115 *
116 * @return long time in ms
117 */
118 protected long getLastUsed() {
119 if (parent != null) {
120 return parent.getLastUsed();
121 }
122 return lastUsed;
123 }
124
125 /**
126 * Set the time this object was last used to the
127 * current time in ms.
128 */
129 protected void setLastUsed() {
130 if (parent != null) {
131 parent.setLastUsed();
132 } else {
133 lastUsed = System.currentTimeMillis();
134 }
135 }
136
137 /**
138 * Set the time in ms this object was last used.
139 *
140 * @param time time in ms
141 */
142 protected void setLastUsed(long time) {
143 if (parent != null) {
144 parent.setLastUsed(time);
145 } else {
146 lastUsed = time;
147 }
148 }
149
150 /**
151 * If logAbandoned=true generate a stack trace
152 * for this object then add this object to the parent
153 * object trace list.
154 */
155 protected void setStackTrace() {
156 if (config == null) {
157 return;
158 }
159 if (config.getLogAbandoned()) {
160 createdBy = new Exception();
161 createdTime = System.currentTimeMillis();
162 }
163 if (parent != null) {
164 parent.addTrace(this);
165 }
166 }
167
168 /**
169 * Add an object to the list of objects being
170 * traced.
171 *
172 * @param trace AbandonedTrace object to add
173 */
174 protected void addTrace(AbandonedTrace trace) {
175 synchronized (this) {
176 this.trace.add(trace);
177 }
178 setLastUsed();
179 }
180
181 /**
182 * Clear the list of objects being traced by this
183 * object.
184 */
185 protected synchronized void clearTrace() {
186 if (this.trace != null) {
187 this.trace.clear();
188 }
189 }
190
191 /**
192 * Get a list of objects being traced by this object.
193 *
194 * @return List of objects
195 */
196 protected List getTrace() {
197 return trace;
198 }
199
200 /**
201 * If logAbandoned=true, print a stack trace of the code that
202 * created this object.
203 */
204 public void printStackTrace() {
205 if (createdBy != null) {
206 System.out.println(format.format(new Date(createdTime)));
207 createdBy.printStackTrace(System.out);
208 }
209 synchronized(this) {
210 Iterator it = this.trace.iterator();
211 while (it.hasNext()) {
212 AbandonedTrace at = (AbandonedTrace)it.next();
213 at.printStackTrace();
214 }
215 }
216 }
217
218 /**
219 * Remove a child object this object is tracing.
220 *
221 * @param trace AbandonedTrace object to remvoe
222 */
223 protected synchronized void removeTrace(AbandonedTrace trace) {
224 if (this.trace != null) {
225 this.trace.remove(trace);
226 }
227 }
228
229 }