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