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    public boolean getLogAbandoned() {
129        return this.logAbandoned;
130    }
131
132    /**
133     * Gets the log writer being used by this configuration to log
134     * information on abandoned objects. If not set, a PrintWriter based on
135     * System.out with the system default encoding is used.
136     *
137     * @return log writer in use
138     */
139    public PrintWriter getLogWriter() {
140        return logWriter;
141    }
142
143    /**
144     * <p>Flag to remove abandoned objects if they exceed the
145     * removeAbandonedTimeout when borrowObject is invoked.</p>
146     *
147     * <p>The default value is false.</p>
148     *
149     * <p>If set to true, abandoned objects are removed by borrowObject if
150     * there are fewer than 2 idle objects available in the pool and
151     * {@code getNumActive() &gt; getMaxTotal() - 3}</p>
152     *
153     * @return true if abandoned objects are to be removed by borrowObject
154     */
155    public boolean getRemoveAbandonedOnBorrow() {
156        return this.removeAbandonedOnBorrow;
157    }
158
159    /**
160     * <p>Flag to remove abandoned objects if they exceed the
161     * removeAbandonedTimeout when pool maintenance (the "evictor")
162     * runs.</p>
163     *
164     * <p>The default value is false.</p>
165     *
166     * <p>If set to true, abandoned objects are removed by the pool
167     * maintenance thread when it runs.  This setting has no effect
168     * unless maintenance is enabled by setting
169     * {@link GenericObjectPool#getDurationBetweenEvictionRuns()}
170     * to a positive number.</p>
171     *
172     * @return true if abandoned objects are to be removed by the evictor
173     */
174    public boolean getRemoveAbandonedOnMaintenance() {
175        return this.removeAbandonedOnMaintenance;
176    }
177
178    /**
179     * <p>Timeout in seconds before an abandoned object can be removed.</p>
180     *
181     * <p>The time of most recent use of an object is the maximum (latest) of
182     * {@link TrackedUse#getLastUsedInstant()} (if this class of the object implements
183     * TrackedUse) and the time when the object was borrowed from the pool.</p>
184     *
185     * <p>The default value is 300 seconds.</p>
186     *
187     * @return the abandoned object timeout in seconds.
188     * @deprecated Use {@link #getRemoveAbandonedTimeoutDuration()}.
189     */
190    @Deprecated
191    public int getRemoveAbandonedTimeout() {
192        return (int) this.removeAbandonedTimeoutDuration.getSeconds();
193    }
194
195    /**
196     * <p>Timeout before an abandoned object can be removed.</p>
197     *
198     * <p>The time of most recent use of an object is the maximum (latest) of
199     * {@link TrackedUse#getLastUsedInstant()} (if this class of the object implements
200     * TrackedUse) and the time when the object was borrowed from the pool.</p>
201     *
202     * <p>The default value is 300 seconds.</p>
203     *
204     * @return the abandoned object timeout.
205     * @since 2.10.0
206     */
207    public Duration getRemoveAbandonedTimeoutDuration() {
208        return this.removeAbandonedTimeoutDuration;
209    }
210
211    /**
212     * Indicates if full stack traces are required when {@link #getLogAbandoned() logAbandoned}
213     * is true. Defaults to true. Logging of abandoned objects requiring a full stack trace will
214     * generate an entire stack trace to generate for every object created. If this is disabled,
215     * a faster but less informative stack walking mechanism may be used if available.
216     *
217     * @return true if full stack traces are required for logging abandoned connections, or false
218     * if abbreviated stack traces are acceptable
219     * @see CallStack
220     * @since 2.5
221     */
222    public boolean getRequireFullStackTrace() {
223        return requireFullStackTrace;
224    }
225
226    /**
227     * If the pool implements {@link UsageTracking}, should the pool record a
228     * stack trace every time a method is called on a pooled object and retain
229     * the most recent stack trace to aid debugging of abandoned objects?
230     *
231     * @return {@code true} if usage tracking is enabled
232     */
233    public boolean getUseUsageTracking() {
234        return useUsageTracking;
235    }
236
237    /**
238     * Sets the flag to log stack traces for application code which abandoned
239     * an object.
240     *
241     * @param logAbandoned true turns on abandoned stack trace logging
242     * @see #getLogAbandoned()
243     */
244    public void setLogAbandoned(final boolean logAbandoned) {
245        this.logAbandoned = logAbandoned;
246    }
247
248    /**
249     * Sets the log writer to be used by this configuration to log
250     * information on abandoned objects.
251     *
252     * @param logWriter The new log writer
253     */
254    public void setLogWriter(final PrintWriter logWriter) {
255        this.logWriter = logWriter;
256    }
257
258    /**
259     * Flag to remove abandoned objects if they exceed the
260     * removeAbandonedTimeout when borrowObject is invoked.
261     *
262     * @param removeAbandonedOnBorrow true means abandoned objects will be
263     *   removed by borrowObject
264     * @see #getRemoveAbandonedOnBorrow()
265     */
266    public void setRemoveAbandonedOnBorrow(final boolean removeAbandonedOnBorrow) {
267        this.removeAbandonedOnBorrow = removeAbandonedOnBorrow;
268    }
269
270    /**
271     * Flag to remove abandoned objects if they exceed the
272     * removeAbandonedTimeout when pool maintenance runs.
273     *
274     * @param removeAbandonedOnMaintenance true means abandoned objects will be
275     *   removed by pool maintenance
276     * @see #getRemoveAbandonedOnMaintenance
277     */
278    public void setRemoveAbandonedOnMaintenance(final boolean removeAbandonedOnMaintenance) {
279        this.removeAbandonedOnMaintenance = removeAbandonedOnMaintenance;
280    }
281
282    /**
283     * Sets the timeout before an abandoned object can be
284     * removed.
285     *
286     * <p>Setting this property has no effect if
287     * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
288     * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
289     * are both false.</p>
290     *
291     * @param removeAbandonedTimeout new abandoned timeout
292     * @see #getRemoveAbandonedTimeoutDuration()
293     * @since 2.10.0
294     */
295    public void setRemoveAbandonedTimeout(final Duration removeAbandonedTimeout) {
296        this.removeAbandonedTimeoutDuration = PoolImplUtils.nonNull(removeAbandonedTimeout, DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION);
297    }
298
299    /**
300     * Sets the timeout in seconds before an abandoned object can be
301     * removed.
302     *
303     * <p>Setting this property has no effect if
304     * {@link #getRemoveAbandonedOnBorrow() removeAbandonedOnBorrow} and
305     * {@link #getRemoveAbandonedOnMaintenance() removeAbandonedOnMaintenance}
306     * are both false.</p>
307     *
308     * @param removeAbandonedTimeoutSeconds new abandoned timeout in seconds
309     * @see #getRemoveAbandonedTimeoutDuration()
310     * @deprecated Use {@link #setRemoveAbandonedTimeout(Duration)}.
311     */
312    @Deprecated
313    public void setRemoveAbandonedTimeout(final int removeAbandonedTimeoutSeconds) {
314        setRemoveAbandonedTimeout(Duration.ofSeconds(removeAbandonedTimeoutSeconds));
315    }
316
317    /**
318     * Sets the flag to require full stack traces for logging abandoned connections when enabled.
319     *
320     * @param requireFullStackTrace indicates whether or not full stack traces are required in
321     *                              abandoned connection logs
322     * @see CallStack
323     * @see #getRequireFullStackTrace()
324     * @since 2.5
325     */
326    public void setRequireFullStackTrace(final boolean requireFullStackTrace) {
327        this.requireFullStackTrace = requireFullStackTrace;
328    }
329
330    /**
331     * If the pool implements {@link UsageTracking}, configure whether the pool
332     * should record a stack trace every time a method is called on a pooled
333     * object and retain the most recent stack trace to aid debugging of
334     * abandoned objects.
335     *
336     * @param   useUsageTracking    A value of {@code true} will enable
337     *                              the recording of a stack trace on every use
338     *                              of a pooled object
339     */
340    public void setUseUsageTracking(final boolean useUsageTracking) {
341        this.useUsageTracking = useUsageTracking;
342    }
343
344    /**
345     * @since 2.4.3
346     */
347    @Override
348    public String toString() {
349        final StringBuilder builder = new StringBuilder();
350        builder.append("AbandonedConfig [removeAbandonedOnBorrow=");
351        builder.append(removeAbandonedOnBorrow);
352        builder.append(", removeAbandonedOnMaintenance=");
353        builder.append(removeAbandonedOnMaintenance);
354        builder.append(", removeAbandonedTimeoutDuration=");
355        builder.append(removeAbandonedTimeoutDuration);
356        builder.append(", logAbandoned=");
357        builder.append(logAbandoned);
358        builder.append(", logWriter=");
359        builder.append(logWriter);
360        builder.append(", useUsageTracking=");
361        builder.append(useUsageTracking);
362        builder.append("]");
363        return builder.toString();
364    }
365}