/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You under the Apache License, Version 2.0 | |
* (the "License"); you may not use this file except in compliance with | |
* the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.apache.commons.dbcp2; | |
import java.io.PrintWriter; | |
import java.io.StringWriter; | |
import java.util.ArrayList; | |
import java.util.EmptyStackException; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Stack; | |
import java.util.concurrent.locks.Lock; | |
import java.util.concurrent.locks.ReentrantLock; | |
import org.apache.commons.logging.impl.SimpleLog; | |
/** | |
* A logger that pushes log messages onto a stack. The stack itself is static. | |
* To get a log exclusive to a test case, use explicit lock / unlock and clear. | |
*/ | |
public class StackMessageLog extends SimpleLog { | |
private static final long serialVersionUID = 1L; | |
private static final Stack<String> MESSAGE_STACK = new Stack<>(); | |
private static final Lock LOCK = new ReentrantLock(); | |
public static void clear() { | |
LOCK.lock(); | |
try { | |
MESSAGE_STACK.clear(); | |
} finally { | |
LOCK.unlock(); | |
} | |
} | |
/** | |
* Note: iterator is fail-fast, lock the stack first. | |
*/ | |
public static List<String> getAll() { | |
final Iterator<String> iterator = MESSAGE_STACK.iterator(); | |
final List<String> messages = new ArrayList<>(); | |
while (iterator.hasNext()) { | |
messages.add(iterator.next()); | |
} | |
return messages; | |
} | |
public static boolean isEmpty() { | |
return MESSAGE_STACK.isEmpty(); | |
} | |
/** | |
* Obtains an exclusive lock on the log. | |
*/ | |
public static void lock() { | |
LOCK.lock(); | |
} | |
/** | |
* @return the most recent log message, or null if the log is empty | |
*/ | |
public static String popMessage() { | |
LOCK.lock(); | |
try { | |
return MESSAGE_STACK.pop(); | |
} catch (final EmptyStackException ex) { | |
// ignore, return null | |
return null; | |
} finally { | |
LOCK.unlock(); | |
} | |
} | |
/** | |
* Relinquishes exclusive lock on the log. | |
*/ | |
public static void unLock() { | |
try { | |
LOCK.unlock(); | |
} catch (final IllegalMonitorStateException ex) { | |
// ignore | |
} | |
} | |
public StackMessageLog(final String name) { | |
super(name); | |
} | |
/** | |
* Ignores type. Pushes message followed by stack trace of t onto the stack. | |
*/ | |
@Override | |
protected void log(final int type, final Object message, final Throwable t) { | |
LOCK.lock(); | |
try { | |
final StringBuilder buf = new StringBuilder(); | |
buf.append(message.toString()); | |
if (t != null) { | |
buf.append(" <"); | |
buf.append(t.toString()); | |
buf.append(">"); | |
final java.io.StringWriter sw = new StringWriter(1024); | |
try (final java.io.PrintWriter pw = new PrintWriter(sw)) { | |
t.printStackTrace(pw); | |
} | |
buf.append(sw.toString()); | |
} | |
MESSAGE_STACK.push(buf.toString()); | |
} finally { | |
LOCK.unlock(); | |
} | |
} | |
} |