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.PrintWriter;
020import java.text.DateFormat;
021import java.text.SimpleDateFormat;
022
023/**
024 * CallStack strategy that uses the stack trace from a {@link Throwable}. This strategy, while slower than the
025 * SecurityManager implementation, provides call stack method names and other metadata in addition to the call stack
026 * of classes.
027 *
028 * @see Throwable#fillInStackTrace()
029 * @since 2.4.3
030 */
031public class ThrowableCallStack implements CallStack {
032
033    /**
034     * A snapshot of a throwable.
035     */
036    private static class Snapshot extends Throwable {
037        private static final long serialVersionUID = 1L;
038        private final long timestampMillis = System.currentTimeMillis();
039    }
040
041    private final String messageFormat;
042
043    //@GuardedBy("dateFormat")
044    private final DateFormat dateFormat;
045
046    private volatile Snapshot snapshot;
047
048    /**
049     * Creates a new instance.
050     *
051     * @param messageFormat message format
052     * @param useTimestamp whether to format the dates in the output message or not
053     */
054    public ThrowableCallStack(final String messageFormat, final boolean useTimestamp) {
055        this.messageFormat = messageFormat;
056        this.dateFormat = useTimestamp ? new SimpleDateFormat(messageFormat) : null;
057    }
058
059    @Override
060    public void clear() {
061        snapshot = null;
062    }
063
064    @Override
065    public void fillInStackTrace() {
066        snapshot = new Snapshot();
067    }
068
069    @Override
070    public synchronized boolean printStackTrace(final PrintWriter writer) {
071        final Snapshot snapshotRef = this.snapshot;
072        if (snapshotRef == null) {
073            return false;
074        }
075        final String message;
076        if (dateFormat == null) {
077            message = messageFormat;
078        } else {
079            synchronized (dateFormat) {
080                message = dateFormat.format(Long.valueOf(snapshotRef.timestampMillis));
081            }
082        }
083        writer.println(message);
084        snapshotRef.printStackTrace(writer);
085        return true;
086    }
087}