1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.pool2.impl;
18  
19  import java.io.OutputStreamWriter;
20  import java.io.PrintWriter;
21  import java.nio.charset.Charset;
22  import java.time.Duration;
23  
24  import org.apache.commons.pool2.TrackedUse;
25  import org.apache.commons.pool2.UsageTracking;
26  
27  /**
28   * Configuration settings for abandoned object removal.
29   *
30   * @since 2.0
31   */
32  public class AbandonedConfig {
33  
34      /**
35       * The 5 minutes Duration.
36       */
37      private static final Duration DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION = Duration.ofMinutes(5);
38  
39      /**
40       * Creates a new instance with values from the given instance.
41       *
42       * @param abandonedConfig the source, may be null.
43       * @return A new instance or null if the input is null.
44       * @since 2.11.0
45       */
46      public static AbandonedConfig copy(final AbandonedConfig abandonedConfig) {
47          return abandonedConfig == null ? null : new AbandonedConfig(abandonedConfig);
48      }
49  
50      /**
51       * Whether or not borrowObject performs abandoned object removal.
52       */
53      private boolean removeAbandonedOnBorrow;
54  
55      /**
56       * Whether or not pool maintenance (evictor) performs abandoned object
57       * removal.
58       */
59      private boolean removeAbandonedOnMaintenance;
60  
61      /**
62       * Timeout before an abandoned object can be removed.
63       */
64      private Duration removeAbandonedTimeoutDuration = DEFAULT_REMOVE_ABANDONED_TIMEOUT_DURATION;
65  
66      /**
67       * Determines whether or not to log stack traces for application code
68       * which abandoned an object.
69       */
70      private boolean logAbandoned;
71  
72      /**
73       * Determines whether or not to log full stack traces when logAbandoned is true.
74       * If disabled, then a faster method for logging stack traces with only class data
75       * may be used if possible.
76       *
77       * @since 2.5
78       */
79      private boolean requireFullStackTrace = true;
80  
81      /**
82       * PrintWriter to use to log information on abandoned objects.
83       * Use of default system encoding is deliberate.
84       */
85      private PrintWriter logWriter = new PrintWriter(new OutputStreamWriter(System.out, Charset.defaultCharset()));
86  
87      /**
88       * If the pool implements {@link UsageTracking}, should the pool record a
89       * stack trace every time a method is called on a pooled object and retain
90       * the most recent stack trace to aid debugging of abandoned objects?
91       */
92      private boolean useUsageTracking;
93  
94      /**
95       * Creates a new instance.
96       */
97      public AbandonedConfig() {
98          // empty
99      }
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() > 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 }