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 * @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(final 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(final 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(final 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(final 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 final int size = traceList.size(); 129 if (size == 0) { 130 return Collections.emptyList(); 131 } 132 final ArrayList<AbandonedTrace> result = new ArrayList<>(size); 133 synchronized (this.traceList) { 134 final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator(); 135 while (iter.hasNext()) { 136 final WeakReference<AbandonedTrace> ref = iter.next(); 137 if (ref.get() == null) { 138 // Clean-up since we are here anyway 139 iter.remove(); 140 } else { 141 result.add(ref.get()); 142 } 143 } 144 } 145 return result; 146 } 147 148 /** 149 * Remove a child object this object is tracing. 150 * 151 * @param trace AbandonedTrace object to remove 152 */ 153 protected void removeTrace(final AbandonedTrace trace) { 154 synchronized(this.traceList) { 155 final Iterator<WeakReference<AbandonedTrace>> iter = traceList.iterator(); 156 while (iter.hasNext()) { 157 final WeakReference<AbandonedTrace> ref = iter.next(); 158 if (trace.equals(ref.get())) { 159 iter.remove(); 160 break; 161 } else if (ref.get() == null) { 162 // Clean-up since we are here anyway 163 iter.remove(); 164 } 165 } 166 } 167 } 168}