View Javadoc
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    *      https://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.PrintWriter;
20  import java.text.DateFormat;
21  import java.text.SimpleDateFormat;
22  import java.time.Instant;
23  import java.time.format.DateTimeFormatter;
24  
25  /**
26   * CallStack strategy that uses the stack trace from a {@link Throwable}. This strategy, while slower than the
27   * SecurityManager implementation, provides call stack method names and other metadata in addition to the call stack
28   * of classes.
29   *
30   * @see Throwable#fillInStackTrace()
31   * @since 2.4.3
32   */
33  public class ThrowableCallStack implements CallStack {
34  
35      /**
36       * A snapshot of a throwable.
37       */
38      private static final class Snapshot extends Throwable {
39  
40          private static final long serialVersionUID = 1L;
41          private final Instant timestamp;
42  
43          /**
44           * Constructs a new instance with its message set to the now instant.
45           */
46          private Snapshot() {
47              this(Instant.now());
48          }
49  
50          /**
51           * Constructs a new instance and use the timestamp as the message with using {@link DateTimeFormatter#ISO_INSTANT} for more precision.
52           *
53           * @param timestamp normally the now instant.
54           */
55          private Snapshot(final Instant timestamp) {
56              super(timestamp.toString());
57              this.timestamp = timestamp;
58          }
59      }
60  
61      private final String messageFormat;
62  
63      // We keep the SimpleDateFormat for backward compatibility instead of a DateTimeFormatter.
64      //@GuardedBy("dateFormat")
65      private final DateFormat dateFormat;
66  
67      private volatile Snapshot snapshot;
68  
69      /**
70       * Creates a new instance.
71       *
72       * @param messageFormat message format
73       * @param useTimestamp whether to format the dates in the output message or not
74       */
75      public ThrowableCallStack(final String messageFormat, final boolean useTimestamp) {
76          this.messageFormat = messageFormat;
77          this.dateFormat = useTimestamp ? new SimpleDateFormat(messageFormat) : null;
78      }
79  
80      @Override
81      public void clear() {
82          snapshot = null;
83      }
84  
85      @Override
86      public void fillInStackTrace() {
87          snapshot = new Snapshot();
88      }
89  
90      @Override
91      public synchronized boolean printStackTrace(final PrintWriter writer) {
92          final Snapshot snapshotRef = this.snapshot;
93          if (snapshotRef == null) {
94              return false;
95          }
96          final String message;
97          if (dateFormat == null) {
98              message = messageFormat;
99          } else {
100             synchronized (dateFormat) {
101                 // The throwable message is in {@link DateTimeFormatter#ISO_INSTANT} format for more precision.
102                 message = dateFormat.format(Long.valueOf(snapshotRef.timestamp.toEpochMilli()));
103             }
104         }
105         writer.println(message);
106         snapshotRef.printStackTrace(writer);
107         return true;
108     }
109 }