KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > util > log > AbstractTreeLogger


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.util.log;
17
18 import com.google.gwt.core.ext.TreeLogger;
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.HashSet JavaDoc;
22
23 /**
24  * Abstract base class for TreeLoggers.
25  */

26 public abstract class AbstractTreeLogger implements TreeLogger {
27
28   // This message is package-protected so that the unit test can access it.
29
static final String JavaDoc OUT_OF_MEMORY_MSG = "Out of memory; to increase the "
30       + "amount of memory, use the -Xmx flag at startup (java -Xmx128M ...)";
31
32   private static class UncommittedBranchData {
33
34     public final Throwable JavaDoc caught;
35
36     public final String JavaDoc message;
37     public final TreeLogger.Type type;
38
39     public UncommittedBranchData(Type type, String JavaDoc message, Throwable JavaDoc exception) {
40       caught = exception;
41       this.message = message;
42       this.type = type;
43     }
44   }
45
46   public static String JavaDoc getStackTraceAsString(Throwable JavaDoc e) {
47     // For each cause, print the requested number of entries of its stack trace,
48
// being careful to avoid getting stuck in an infinite loop.
49
//
50
StringBuffer JavaDoc message = new StringBuffer JavaDoc();
51     Throwable JavaDoc currentCause = e;
52     String JavaDoc causedBy = "";
53     HashSet JavaDoc seenCauses = new HashSet JavaDoc();
54     while (currentCause != null && !seenCauses.contains(currentCause)) {
55       seenCauses.add(currentCause);
56
57       StackTraceElement JavaDoc[] trace = currentCause.getStackTrace();
58       message.append(causedBy);
59       causedBy = "\nCaused by: "; // after 1st, all say "caused by"
60
message.append(currentCause.getClass().getName());
61       message.append(": " + currentCause.getMessage());
62       StackTraceElement JavaDoc[] stackElems = findMeaningfulStackTraceElements(trace);
63       if (stackElems != null) {
64         for (int i = 0; i < stackElems.length; ++i) {
65           message.append("\n\tat ");
66           message.append(stackElems[i].toString());
67         }
68       }
69
70       currentCause = currentCause.getCause();
71     }
72     return message.toString();
73   }
74
75   private static StackTraceElement JavaDoc[] findMeaningfulStackTraceElements(
76       StackTraceElement JavaDoc[] elems) {
77     ArrayList JavaDoc goodElems = new ArrayList JavaDoc();
78     StackTraceElement JavaDoc prevElem = null;
79     for (int i = 0; i < elems.length; i++) {
80       StackTraceElement JavaDoc elem = elems[i];
81       if (elem.getLineNumber() > 0) {
82         goodElems.add(elem);
83         if (goodElems.size() < 10
84             || prevElem.getClassName().equals(elem.getClassName())) {
85           // Keep going.
86
prevElem = elem;
87         } else {
88           // That's enough.
89
break;
90         }
91       }
92     }
93     if (goodElems.size() > 0) {
94       return (StackTraceElement JavaDoc[]) goodElems.toArray(new StackTraceElement JavaDoc[goodElems.size()]);
95     } else {
96       return null;
97     }
98   }
99
100   public int indexWithinMyParent;
101
102   private TreeLogger.Type logLevel = TreeLogger.ALL;
103
104   private int nextChildIndex;
105
106   private final Object JavaDoc nextChildIndexLock = new Object JavaDoc();
107
108   private AbstractTreeLogger parent;
109
110   private UncommittedBranchData uncommitted;
111
112   /**
113    * The constructor used when creating a top-level logger.
114    */

115   protected AbstractTreeLogger() {
116   }
117
118   /**
119    * Implements branching behavior that supports lazy logging for low-priority
120    * branched loggers.
121    */

122   public final synchronized TreeLogger branch(TreeLogger.Type type, String JavaDoc msg,
123       Throwable JavaDoc caught) {
124
125     if (msg == null) {
126       msg = "(Null branch message)";
127     }
128
129     // Compute at which index the new child will be placed.
130
//
131
int childIndex = allocateNextChildIndex();
132
133     // The derived class creates the child logger.
134
AbstractTreeLogger childLogger = doBranch();
135
136     // Set up the child logger.
137
childLogger.logLevel = logLevel;
138
139     // Take a snapshot of the index that the branched child should have.
140
//
141
childLogger.indexWithinMyParent = childIndex;
142
143     // Have the child hang onto this (its parent logger).
144
//
145
childLogger.parent = this;
146
147     // We can avoid committing this branch entry until and unless some
148
// child (or grandchild) tries to log something that is loggable,
149
// in which case there will be cascading commits of the parent branches.
150
//
151
childLogger.uncommitted = new UncommittedBranchData(type, msg, caught);
152
153     // This logic is intertwined with log(). If a log message is associated
154
// with an out-of-memory condition, then we turn it into a branch,
155
// so this method can be called directly from log(). It is of course
156
// also possible for someone to call branch() directly. In either case, we
157
// (1) turn the original message into an ERROR and
158
// (2) drop an extra log message that explains how to recover
159
if (causedByOutOfMemory(caught)) {
160       type = TreeLogger.ERROR;
161       childLogger.log(type, OUT_OF_MEMORY_MSG, null);
162     }
163
164     // Decide whether we want to log the branch message eagerly or lazily.
165
//
166
if (isLoggable(type)) {
167       // We can commit this branch entry eagerly since it is a-priori loggable.
168
// Commit the parent logger if necessary before continuing.
169
//
170
childLogger.commitMyBranchEntryInMyParentLogger();
171     }
172
173     return childLogger;
174   }
175
176   public final int getBranchedIndex() {
177     return indexWithinMyParent;
178   }
179
180   public final AbstractTreeLogger getParentLogger() {
181     return parent;
182   }
183
184   public final synchronized boolean isLoggable(TreeLogger.Type type) {
185     return !type.isLowerPriorityThan(logLevel);
186   }
187
188   /**
189    * Immediately logs or ignores the specified messages, based on the specified
190    * message type and this logger's settings. If the message is loggable, then
191    * parent branches may be lazily created before the log can take place.
192    */

193   public final synchronized void log(TreeLogger.Type type, String JavaDoc msg,
194       Throwable JavaDoc caught) {
195
196     if (msg == null) {
197       msg = "(Null log message)";
198     }
199
200     // If this log message is caused by being out of memory, we
201
// provide a little extra help by creating a child log message.
202
if (causedByOutOfMemory(caught)) {
203       branch(TreeLogger.ERROR, msg, caught);
204       return;
205     }
206
207     int childIndex = allocateNextChildIndex();
208     if (isLoggable(type)) {
209       commitMyBranchEntryInMyParentLogger();
210       doLog(childIndex, type, msg, caught);
211     }
212   }
213
214   /**
215    * @param type the log type representing the most detailed level of logging
216    * that the caller is interested in, or <code>null</code> to choose
217    * the default level.
218    */

219   public final synchronized void setMaxDetail(TreeLogger.Type type) {
220     if (type == null) {
221       type = TreeLogger.INFO;
222     }
223     logLevel = type;
224   }
225
226   public String JavaDoc toString() {
227     return getLoggerId();
228   }
229
230   /**
231    * Derived classes should override this method to return a branched logger.
232    */

233   protected abstract AbstractTreeLogger doBranch();
234
235   /**
236    * Derived classes should override this method to actually commit the
237    * specified message associated with this the root of this branch.
238    */

239   protected abstract void doCommitBranch(
240       AbstractTreeLogger childBeingCommitted, TreeLogger.Type type, String JavaDoc msg,
241       Throwable JavaDoc caught);
242
243   /**
244    * Dervied classes should override this method to actually write a log
245    * message. Note that {@link #isLoggable(TreeLogger.Type)} will have already
246    * been called.
247    */

248   protected abstract void doLog(int indexOfLogEntryWithinParentLogger,
249       TreeLogger.Type type, String JavaDoc msg, Throwable JavaDoc caught);
250
251   private int allocateNextChildIndex() {
252     synchronized (nextChildIndexLock) {
253       // postincrement because we want indices to start at 0
254
return nextChildIndex++;
255     }
256   }
257
258   /**
259    * Scans <code>t</code> and its causes for {@link OutOfMemoryError}.
260    *
261    * @param t a possibly null {@link Throwable}
262    * @return true if {@link OutOfMemoryError} appears anywhere in the cause list
263    * or if <code>t</code> is an {@link OutOfMemoryError}.
264    */

265   private boolean causedByOutOfMemory(Throwable JavaDoc t) {
266
267     while (t != null) {
268       if (t instanceof OutOfMemoryError JavaDoc) {
269         return true;
270       }
271       t = t.getCause();
272     }
273
274     return false;
275   }
276
277   /**
278    * Commits the branch after ensuring that the parent logger (if there is one)
279    * has been committed first.
280    */

281   private synchronized void commitMyBranchEntryInMyParentLogger() {
282     // (Only the root logger doesn't have a parent.)
283
//
284
if (parent != null) {
285       if (uncommitted != null) {
286         // Commit the parent first.
287
//
288
parent.commitMyBranchEntryInMyParentLogger();
289
290         // Let the subclass do its thing to commit this branch.
291
//
292
parent.doCommitBranch(this, uncommitted.type, uncommitted.message,
293             uncommitted.caught);
294
295         // Release the uncommitted state.
296
//
297
uncommitted = null;
298       }
299     }
300   }
301
302   private String JavaDoc getLoggerId() {
303     if (parent != null) {
304       if (parent.parent == null) {
305         // Top-level
306
return parent.getLoggerId() + getBranchedIndex();
307       } else {
308         // Nested
309
return parent.getLoggerId() + "." + getBranchedIndex();
310       }
311     } else {
312       // The root
313
return "#";
314     }
315   }
316 }
317
Popular Tags