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 * https://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.PrintWriter; 020import java.text.DateFormat; 021import java.text.SimpleDateFormat; 022import java.time.Instant; 023import java.time.format.DateTimeFormatter; 024 025/** 026 * CallStack strategy that uses the stack trace from a {@link Throwable}. This strategy, while slower than the 027 * SecurityManager implementation, provides call stack method names and other metadata in addition to the call stack 028 * of classes. 029 * 030 * @see Throwable#fillInStackTrace() 031 * @since 2.4.3 032 */ 033public class ThrowableCallStack implements CallStack { 034 035 /** 036 * A snapshot of a throwable. 037 */ 038 private static final class Snapshot extends Throwable { 039 040 private static final long serialVersionUID = 1L; 041 private final Instant timestamp; 042 043 /** 044 * Constructs a new instance with its message set to the now instant. 045 */ 046 private Snapshot() { 047 this(Instant.now()); 048 } 049 050 /** 051 * Constructs a new instance and use the timestamp as the message with using {@link DateTimeFormatter#ISO_INSTANT} for more precision. 052 * 053 * @param timestamp normally the now instant. 054 */ 055 private Snapshot(final Instant timestamp) { 056 super(timestamp.toString()); 057 this.timestamp = timestamp; 058 } 059 } 060 061 private final String messageFormat; 062 063 // We keep the SimpleDateFormat for backward compatibility instead of a DateTimeFormatter. 064 //@GuardedBy("dateFormat") 065 private final DateFormat dateFormat; 066 067 private volatile Snapshot snapshot; 068 069 /** 070 * Creates a new instance. 071 * 072 * @param messageFormat message format 073 * @param useTimestamp whether to format the dates in the output message or not 074 */ 075 public ThrowableCallStack(final String messageFormat, final boolean useTimestamp) { 076 this.messageFormat = messageFormat; 077 this.dateFormat = useTimestamp ? new SimpleDateFormat(messageFormat) : null; 078 } 079 080 @Override 081 public void clear() { 082 snapshot = null; 083 } 084 085 @Override 086 public void fillInStackTrace() { 087 snapshot = new Snapshot(); 088 } 089 090 @Override 091 public synchronized boolean printStackTrace(final PrintWriter writer) { 092 final Snapshot snapshotRef = this.snapshot; 093 if (snapshotRef == null) { 094 return false; 095 } 096 final String message; 097 if (dateFormat == null) { 098 message = messageFormat; 099 } 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}