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    *      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  
18  package org.apache.commons.dbcp2;
19  
20  import java.io.PrintWriter;
21  import java.io.StringWriter;
22  import java.util.ArrayList;
23  import java.util.EmptyStackException;
24  import java.util.List;
25  import java.util.Stack;
26  import java.util.concurrent.locks.Lock;
27  import java.util.concurrent.locks.ReentrantLock;
28  
29  import org.apache.commons.logging.impl.SimpleLog;
30  
31  /**
32   * A logger that pushes log messages onto a stack. The stack itself is static.
33   * To get a log exclusive to a test case, use explicit lock / unlock and clear.
34   */
35  public class StackMessageLog extends SimpleLog {
36  
37      private static final long serialVersionUID = 1L;
38      private static final Stack<String> MESSAGE_STACK = new Stack<>();
39      private static final Lock LOCK = new ReentrantLock();
40  
41      public static void clear() {
42          LOCK.lock();
43          try {
44              MESSAGE_STACK.clear();
45          } finally {
46              LOCK.unlock();
47          }
48      }
49  
50      /**
51       * Gets a copy of the message stack.
52       * <p>
53       * Note: lock the stack first.
54       * </p>
55       *
56       * @return a new list.
57       */
58      public static List<String> getAll() {
59          return new ArrayList<>(MESSAGE_STACK);
60      }
61  
62      public static boolean isEmpty() {
63          return MESSAGE_STACK.isEmpty();
64      }
65  
66      /**
67       * Obtains an exclusive lock on the log.
68       */
69      public static void lock() {
70          LOCK.lock();
71      }
72  
73      /**
74       * @return the most recent log message, or null if the log is empty
75       */
76      public static String popMessage() {
77          LOCK.lock();
78          try {
79              return MESSAGE_STACK.pop();
80          } catch (final EmptyStackException ex) {
81              // ignore, return null
82              return null;
83          } finally {
84              LOCK.unlock();
85          }
86      }
87  
88      /**
89       * Relinquishes exclusive lock on the log.
90       */
91      public static void unLock() {
92          try {
93              LOCK.unlock();
94          } catch (final IllegalMonitorStateException ex) {
95              // ignore
96          }
97      }
98  
99      public StackMessageLog(final String name) {
100         super(name);
101     }
102 
103     /**
104      * Ignores type.  Pushes message followed by stack trace of t onto the stack.
105      */
106     @Override
107     protected void log(final int type, final Object message, final Throwable t) {
108         LOCK.lock();
109         try {
110             final StringBuilder buf = new StringBuilder();
111             buf.append(message.toString());
112             if (t != null) {
113                 buf.append(" <");
114                 buf.append(t.toString());
115                 buf.append(">");
116                 final java.io.StringWriter sw = new StringWriter(1024);
117                 try (final java.io.PrintWriter pw = new PrintWriter(sw)) {
118                     t.printStackTrace(pw);
119                 }
120                 buf.append(sw.toString());
121             }
122             MESSAGE_STACK.push(buf.toString());
123         } finally {
124             LOCK.unlock();
125         }
126     }
127 }