1 // Copyright 2008 The Apache Software Foundation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package org.apache.tapestry5.ioc.internal;
16
17 import org.apache.tapestry5.ioc.OperationTracker;
18 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
19 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
20 import org.apache.tapestry5.ioc.internal.util.Invokable;
21 import org.apache.tapestry5.ioc.util.Stack;
22 import org.slf4j.Logger;
23
24 /**
25 * Core implementation that manages a logger and catches and reports exception.
26 *
27 * @see org.apache.tapestry5.ioc.internal.PerThreadOperationTracker
28 */
29 public class OperationTrackerImpl implements OperationTracker
30 {
31 private final Logger logger;
32
33 private final Stack<String> operations = CollectionFactory.newStack();
34
35 private boolean logged;
36
37 public OperationTrackerImpl(Logger logger)
38 {
39 this.logger = logger;
40 }
41
42 public void run(String description, final Runnable operation)
43 {
44 operations.push(description);
45
46 try
47 {
48 operation.run();
49 }
50 catch (RuntimeException ex)
51 {
52 if (!logged)
53 {
54
55 logger.error(InternalUtils.toMessage(ex));
56 logger.error("Operations trace:");
57
58 Object[] snapshot = operations.getSnapshot();
59 String[] trace = new String[snapshot.length];
60
61 for (int i = 0; i < snapshot.length; i++)
62 {
63 trace[i] = snapshot[i].toString();
64
65 logger.error(String.format("[%2d] %s", i + 1, trace[i]));
66 }
67
68 logged = true;
69
70 throw new OperationException(ex, trace);
71 }
72
73 throw ex;
74 }
75 finally
76 {
77 operations.pop();
78
79 // We've finally backed out of the operation stack ... but there may be more to come!
80
81 if (operations.isEmpty()) logged = false;
82 }
83 }
84
85 public <T> T invoke(String description, Invokable<T> operation)
86 {
87 InvokableToRunnable<T> i2r = new InvokableToRunnable<T>(operation);
88
89 run(description, i2r);
90
91 return i2r.getResult();
92 }
93
94 boolean isEmpty() { return operations.isEmpty(); }
95 }