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 */
017
018package org.apache.commons.pool2.impl;
019
020import java.io.OutputStreamWriter;
021import java.io.PrintWriter;
022import java.nio.charset.Charset;
023import java.time.Duration;
024
025import org.apache.commons.pool2.TrackedUse;
026import org.apache.commons.pool2.UsageTracking;
027
028/**
029 * Configuration settings for abandoned object removal.
030 *
031 * @since 2.0
032 */
033public class AbandonedConfig {
034
035    private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT = Duration.ofSeconds(300);
036
037    /**
038     * Whether or not borrowObject performs abandoned object removal.
039     */
040    private boolean removeAbandonedOnBorrow;
041
042    /**
043     * Whether or not pool maintenance (evictor) performs abandoned object
044     * removal.
045     */
046    private boolean removeAbandonedOnMaintenance;
047
048    /**
049     * Timeout before an abandoned object can be removed.
050     */
051    private Duration removeAbandonedTimeout = DEFAULT_REMOVE_ABANDONED_TIMEOUT;
052
053    /**
054     * Determines whether or not to log stack traces for application code
055     * which abandoned an object.
056     */
057    private boolean logAbandoned = false;
058
059    /**
060     * Determines whether or not to log full stack traces when logAbandoned is true.
061     * If disabled, then a faster method for logging stack traces with only class data
062     * may be used if possible.
063     *
064     * @since 2.5
065     */
066    private boolean requireFullStackTrace = true;
067
068    /**
069     * PrintWriter to use to log information on abandoned objects.
070     * Use of default system encoding is deliberate.
071     */
072    private PrintWriter logWriter = new PrintWriter(new OutputStreamWriter(System.out, Charset.defaultCharset()));
073
074    /**
075     * If the pool implements {@link UsageTracking}, should the pool record a
076     * stack trace every time a method is called on a pooled object and retain
077     * the most recent stack trace to aid debugging of abandoned objects?
078     */
079    private boolean useUsageTracking = false;
080
081    /**
082     * Flag to log stack traces for application code which abandoned
083     * an object.
084     *
085     * Defaults to false.
086     * Logging of abandoned objects adds overhead for every object created
087     * because a stack trace has to be generated.
088     *
089     * @return boolean true if stack trace logging is turned on for abandoned
090     * objects
091     *
092     */
093    public boolean getLogAbandoned() {
094        return this.logAbandoned;
095    }
096
097    /**
098     * Gets the log writer being used by this configuration to log
099     * information on abandoned objects. If not set, a PrintWriter based on
100     * System.out with the system default encoding is used.
101     *
102     * @return log writer in use
103     */
104    public PrintWriter getLogWriter() {
105        return logWriter;
106    }
107
108    /**
109     * <p>Flag to remove abandoned objects if they exceed the
110     * removeAbandonedTimeout when borrowObject is invoked.</p>
111     *
112     * <p>The default value is false.</p>
113     *
114     * <p>If set to true, abandoned objects are removed by borrowObject if
115     * there are fewer than 2 idle objects available in the pool and
116     * {@code getNumActive() &gt; getMaxTotal() - 3}</p>
117     *
118     * @return true if abandoned objects are to be removed by borrowObject
119     */
120    public boolean getRemoveAbandonedOnBorrow() {
121        return this.removeAbandonedOnBorrow;
122    }
123
124    /**
125     * <p>Flag to remove abandoned objects if they exceed the
126     * removeAbandonedTimeout when pool maintenance (the "evictor")
127     * runs.</p>
128     *
129     * <p>The default value is false.</p>
130     *
131     * <p>If set to true, abandoned objects are removed by the pool
132     * maintenance thread when it runs.  This setting has no effect
133     * unless maintenance is enabled by setting
134     *{@link GenericObjectPool#getTimeBetweenEvictionRuns() timeBetweenEvictionRuns}
135     * to a positive number.</p>
136     *
137     * @return true if abandoned objects are to be removed by the evictor
138     */
139    public boolean getRemoveAbandonedOnMaintenance() {
140        return this.removeAbandonedOnMaintenance;
141    }
142
143    /**
144     * <p>Timeout in seconds before an abandoned object can be removed.</p>
145     *
146     * <p>The time of most recent use of an object is the maximum (latest) of
147     * {@link TrackedUse#getLastUsed()} (if this class of the object implements
148     * TrackedUse) and the time when the object was borrowed from the pool.</p>
149     *
150     * <p>The default value is 300 seconds.</p>
151     *
152     * @return the abandoned object timeout in seconds
153     * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
154     */
155    @Deprecated
156    public int getRemoveAbandonedTimeout() {
157        return (int) this.removeAbandonedTimeout.getSeconds();
158    }
159
160    /**
161     * <p>Timeout before an abandoned object can be removed.</p>
162     *
163     * <p>The time of most recent use of an object is the maximum (latest) of
164     * {@link TrackedUse#getLastUsed()} (if this class of the object implements
165     * TrackedUse) and the time when the object was borrowed from the pool.</p>
166     *
167     * <p>The default value is 300 seconds.</p>
168     *
169     * @return the abandoned object timeout.
170     * @since 2.10.0
171     */
172    public Duration getRemoveAbandonedTimeoutDuration() {
173        return this.removeAbandonedTimeout;
174    }
175
176    /**
177     * Indicates if full stack traces are required when {@link #getLogAbandoned() logAbandoned}
178     * is true. Defaults to true. Logging of abandoned objects requiring a full stack trace will
179     * generate an entire stack trace to generate for every object created. If this is disabled,
180     * a faster but less informative stack walking mechanism may be used if available.
181     *
182     * @return true if full stack traces are required for logging abandoned connections, or false
183     * if abbreviated stack traces are acceptable
184     * @see CallStack
185     * @since 2.5
186     */
187    public boolean getRequireFullStackTrace() {
188        return requireFullStackTrace;
189    }
190
191    /**
192     * If the pool implements {@link UsageTracking}, should the pool record a
193     * stack trace every time a method is called on a pooled object and retain
194     * the most recent stack trace to aid debugging of abandoned objects?
195     *
196     * @return {@code true} if usage tracking is enabled
197     */
198    public boolean getUseUsageTracking() {
199        return useUsageTracking;
200    }
201
202    /**
203     * Sets the flag to log stack traces for application code which abandoned
204     * an object.
205     *
206     * @param logAbandoned true turns on abandoned stack trace logging
207     * @see #getLogAbandoned()
208     *
209     */
210    public void setLogAbandoned(final boolean logAbandoned) {
211        this.logAbandoned = logAbandoned;
212    }
213
214    /**
215     * Sets the log writer to be used by this configuration to log
216     * information on abandoned objects.
217     *
218     * @param logWriter The new log writer
219     */
220    public void setLogWriter(final PrintWriter logWriter) {
221        this.logWriter = logWriter;
222    }
223
224    /**
225     * <p>Flag to remove abandoned objects if they exceed the
226     * removeAbandonedTimeout when borrowObject is invoked.</p>
227     *
228     * @param removeAbandonedOnBorrow true means abandoned objects will be
229     *   removed by borrowObject
230     * @see #getRemoveAbandonedOnBorrow()
231     */
232    public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
233        this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
234    }
235
236    /**
237     * <p>Flag to remove abandoned objects if they exceed the
238     * removeAbandonedTimeout when pool maintenance runs.</p>
239     *
240     * @param removeAbandonedOnMaintenance true means abandoned objects will be
241     *   removed by pool maintenance
242     * @see #getRemoveAbandonedOnMaintenance
243     */
244    public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
245        this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
246    }
247
248    /**
249     * <p>Sets the timeout before an abandoned object can be
250     * removed</p>
251     *
252     * <p>Setting this property has no effect if
253     * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
254     * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
255     * are both false.</p>
256     *
257     * @param removeAbandonedTimeout new abandoned timeout
258     * @see #getRemoveAbandonedTimeout()
259     * @since 2.10.0
260     */
261    public void setRemoveAbandonedTimeout(final Duration removeAbandonedTimeout) {
262        this.removeAbandonedTimeout = removeAbandonedTimeout;
263    }
264
265    /**
266     * <p>Sets the timeout in seconds before an abandoned object can be
267     * removed</p>
268     *
269     * <p>Setting this property has no effect if
270     * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
271     * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
272     * are both false.</p>
273     *
274     * @param removeAbandonedTimeout new abandoned timeout in seconds
275     * @see #getRemoveAbandonedTimeout()
276     * @deprecated Use {@link #setRemoveAbandonedTimeout(Duration)}.
277     */
278    @Deprecated
279    public void setRemoveAbandonedTimeout(final int removeAbandonedTimeout) {
280        setRemoveAbandonedTimeout(Duration.ofSeconds(removeAbandonedTimeout));
281    }
282
283    /**
284     * Sets the flag to require full stack traces for logging abandoned connections when enabled.
285     *
286     * @param requireFullStackTrace indicates whether or not full stack traces are required in
287     *                              abandoned connection logs
288     * @see CallStack
289     * @see #getRequireFullStackTrace()
290     * @since 2.5
291     */
292    public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
293        this.requireFullStackTrace = requireFullStackTrace;
294    }
295
296    /**
297     * If the pool implements {@link UsageTracking}, configure whether the pool
298     * should record a stack trace every time a method is called on a pooled
299     * object and retain the most recent stack trace to aid debugging of
300     * abandoned objects.
301     *
302     * @param   useUsageTracking    A value of {@code true} will enable
303     *                              the recording of a stack trace on every use
304     *                              of a pooled object
305     */
306    public void setUseUsageTracking(final boolean useUsageTracking) {
307        this.useUsageTracking = useUsageTracking;
308    }
309
310    /**
311     * @since 2.4.3
312     */
313    @Override
314    public String toString() {
315        final StringBuilder builder = new StringBuilder();
316        builder.append("AbandonedConfig [removeAbandonedOnBorrow=");
317        builder.append(removeAbandonedOnBorrow);
318        builder.append(", removeAbandonedOnMaintenance=");
319        builder.append(removeAbandonedOnMaintenance);
320        builder.append(", removeAbandonedTimeout=");
321        builder.append(removeAbandonedTimeout);
322        builder.append(", logAbandoned=");
323        builder.append(logAbandoned);
324        builder.append(", logWriter=");
325        builder.append(logWriter);
326        builder.append(", useUsageTracking=");
327        builder.append(useUsageTracking);
328        builder.append("]");
329        return builder.toString();
330    }
331}