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