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