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 */ 017package org.apache.commons.dbcp2; 018 019import java.lang.ref.WeakReference; 020import java.util.ArrayList; 021import java.util.Iterator; 022import java.util.List; 023 024import org.apache.commons.pool2.TrackedUse; 025 026/** 027 * Tracks db connection usage for recovering and reporting 028 * abandoned db connections. 029 * 030 * The JDBC Connection, Statement, and ResultSet classes 031 * extend this class. 032 * 033 * @author Glenn L. Nielsen 034 * @version $Revision: 1572242 $ $Date: 2014-02-26 20:34:39 +0000 (Wed, 26 Feb 2014) $ 035 * @since 2.0 036 */ 037public class AbandonedTrace implements TrackedUse { 038 039 /** A list of objects created by children of this object */ 040 private final List<WeakReference<AbandonedTrace>> traceList = new ArrayList<>(); 041 /** Last time this connection was used */ 042 private volatile long lastUsed = 0; 043 044 /** 045 * Create a new AbandonedTrace without config and 046 * without doing abandoned tracing. 047 */ 048 public AbandonedTrace() { 049 init(null); 050 } 051 052 /** 053 * Construct a new AbandonedTrace with a parent object. 054 * 055 * @param parent AbandonedTrace parent object 056 */ 057 public AbandonedTrace(AbandonedTrace parent) { 058 init(parent); 059 } 060 061 /** 062 * Initialize abandoned tracing for this object. 063 * 064 * @param parent AbandonedTrace parent object 065 */ 066 private void init(AbandonedTrace parent) { 067 if (parent != null) { 068 parent.addTrace(this); 069 } 070 } 071 072 /** 073 * Get the last time this object was used in ms. 074 * 075 * @return long time in ms 076 */ 077 @Override 078 public long getLastUsed() { 079 return lastUsed; 080 } 081 082 /** 083 * Set the time this object was last used to the 084 * current time in ms. 085 */ 086 protected void setLastUsed() { 087 lastUsed = System.currentTimeMillis(); 088 } 089 090 /** 091 * Set the time in ms this object was last used. 092 * 093 * @param time time in ms 094 */ 095 protected void setLastUsed(long time) { 096 lastUsed = time; 097 } 098 099 /** 100 * Add an object to the list of objects being 101 * traced. 102 * 103 * @param trace AbandonedTrace object to add 104 */ 105 protected void addTrace(AbandonedTrace trace) { 106 synchronized (this.traceList) { 107 this.traceList.add(new WeakReference<>(trace)); 108 } 109 setLastUsed(); 110 } 111 112 /** 113 * Clear the list of objects being traced by this 114 * object. 115 */ 116 protected void clearTrace() { 117 synchronized(this.traceList) { 118 this.traceList.clear(); 119 } 120 } 121 122 /** 123 * Get a list of objects being traced by this object. 124 * 125 * @return List of objects 126 */ 127 protected List<AbandonedTrace> getTrace() { 128 ArrayList<AbandonedTrace> result = new ArrayList<>(traceList.size()); 129 synchronized (this.traceList) { 130 Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator(); 131 while (iter.hasNext()) { 132 WeakReference<AbandonedTrace> ref = iter.next(); 133 if (ref.get() == null) { 134 // Clean-up since we are here anyway 135 iter.remove(); 136 } else { 137 result.add(ref.get()); 138 } 139 } 140 } 141 return result; 142 } 143 144 /** 145 * Remove a child object this object is tracing. 146 * 147 * @param trace AbandonedTrace object to remove 148 */ 149 protected void removeTrace(AbandonedTrace trace) { 150 synchronized(this.traceList) { 151 Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator(); 152 while (iter.hasNext()) { 153 WeakReference<AbandonedTrace> ref = iter.next(); 154 if (trace.equals(ref.get())) { 155 iter.remove(); 156 break; 157 } else if (ref.get() == null) { 158 // Clean-up since we are here anyway 159 iter.remove(); 160 } 161 } 162 } 163 } 164}