1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jdiagnose.runtime;
17
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Stack;
22
23 import org.jdiagnose.DiagnosticContainer;
24 import org.jdiagnose.MessageFactory;
25 import org.jdiagnose.ResultInfo;
26 import org.jdiagnose.concurrent.QueuedExecutor;
27 import org.jdiagnose.message.ExceptionMessageFactory;
28
29 /***
30 * The DiagnosticRunner is responsible for running a diagnostic and all
31 * of it's children. It has been design to support synchronous and
32 * asynchronous running. Usage is usually:
33 *
34 * <code>
35 * SucceedingDiagnostic diagnostic = new SucceedingDiagnostic();
36 * DiagnosticRunner runner = new DiagnosticRunner(diagnostic);
37 * runner.run();
38 * if(runnner.getResult().getState() == ResultState.FAILURE) {
39 * log.warn("Diagnostics failed");
40 * }
41 * </code>
42 *
43 * TODO jamie there is an issue with diagnostic results and concurrency
44 * TODO jamie consider attaching the listeners to the inner class
45 * TODO jamie consider creating new diagnostic results per run
46 */
47 public class DefaultDiagnosticRunner implements DiagnosticRunner {
48
49 private DiagnosticContainerResult containerResult;
50 private Object runLock = new Object();
51 private boolean running = false;
52 private QueuedExecutor executor = new QueuedExecutor();
53 private ArrayList runListeners = new ArrayList();
54 private ArrayList resultListeners = new ArrayList();
55 private MessageFactory messageFactory = ExceptionMessageFactory.DEFAULT_EXCEPTION_MESSAGE_FACTORY;
56
57 public DefaultDiagnosticRunner(DiagnosticContainer container) {
58 this.containerResult = new DefaultDiagnosticContainerResult(messageFactory, container);
59 }
60
61 private ResultInfo[] convert(Stack stack) {
62 return (ResultInfo[]) stack.toArray(new ResultInfo[stack.size()]);
63 }
64
65 protected void runDiagnosticContainerResult(Stack stack, DiagnosticContainerResult container) {
66 try {
67 stack.push(container);
68 fireDiagnosticResultStarted(new ResultEvent(this, container, convert(stack)));
69 for (Iterator containerIterator = container.getContainerResults().iterator(); containerIterator.hasNext();) {
70 DiagnosticContainerResult childContainerResult = (DiagnosticContainerResult) containerIterator.next();
71 runDiagnosticContainerResult(stack, childContainerResult);
72 }
73 for (Iterator resultIterator = container.getResults().iterator(); resultIterator.hasNext();) {
74 DiagnosticResult result = (DiagnosticResult) resultIterator.next();
75 try {
76 stack.push(result);
77 fireDiagnosticResultStarted(new ResultEvent(this, result, convert(stack)));
78 result.diagnose();
79 } finally {
80 fireDiagnosticResultFinished(new ResultEvent(this, result, convert(stack)));
81 stack.pop();
82 }
83 }
84 fireDiagnosticResultFinished(new ResultEvent(this, container, convert(stack)));
85 } finally {
86 stack.pop();
87 }
88 }
89
90 protected void realRun() {
91 try {
92 fireDiagnosticRunStarted(new RunEvent(this, this));
93
94 runDiagnosticContainerResult(new Stack(), containerResult);
95
96 } finally {
97 fireDiagnosticRunFinished(new RunEvent(this, this));
98 }
99 }
100
101 public DiagnosticContainerResult run() {
102 synchronized (runLock) {
103 if (!running) {
104 try {
105 running = true;
106 realRun();
107 } finally {
108 running = false;
109 }
110 }
111 return containerResult;
112 }
113 }
114
115 public DiagnosticContainerResult runAsynchronously() throws InterruptedException {
116 synchronized (runLock) {
117 if(!running) {
118 running = true;
119 executor.execute(new Runnable() {
120 public void run() {
121 try {
122 DefaultDiagnosticRunner.this.realRun();
123 } finally {
124 running = false;
125 }
126 }
127 });
128 }
129 return containerResult;
130 }
131 }
132
133 protected void fireDiagnosticRunStarted(RunEvent event) {
134 List clonedListeners = (ArrayList) runListeners.clone();
135 for (Iterator iterator = clonedListeners.iterator(); iterator.hasNext();) {
136 RunListener listener = (RunListener) iterator.next();
137 listener.runStarted(event);
138 }
139 }
140
141 protected void fireDiagnosticRunFinished(RunEvent event) {
142 List clonedListeners = (ArrayList) runListeners.clone();
143 for (Iterator iterator = clonedListeners.iterator(); iterator.hasNext();) {
144 RunListener listener = (RunListener) iterator.next();
145 listener.runFinished(event);
146 }
147 }
148
149 protected void fireDiagnosticResultStarted(ResultEvent event) {
150 List clonedListeners = (ArrayList) resultListeners.clone();
151 for (Iterator iterator = clonedListeners.iterator(); iterator.hasNext();) {
152 ResultListener listener = (ResultListener) iterator.next();
153 listener.diagnosticStarted(event);
154 }
155 }
156
157 protected void fireDiagnosticResultFinished(ResultEvent event) {
158 List clonedListeners = (ArrayList) resultListeners.clone();
159 for (Iterator iterator = clonedListeners.iterator(); iterator.hasNext();) {
160 ResultListener listener = (ResultListener) iterator.next();
161 listener.diagnosticFinished(event);
162 }
163 }
164
165 public void addRunListener(RunListener runListener) {
166 this.runListeners.add(runListener);
167 }
168
169 public void removeRunListener(RunListener runListener) {
170 this.runListeners.remove(runListener);
171 }
172
173 public void addResultListener(ResultListener resultListener) {
174 this.resultListeners.add(resultListener);
175 }
176
177 public void removeResultListener(ResultListener resultListener) {
178 this.resultListeners.remove(resultListener);
179 }
180
181 public boolean isRunning() {
182 return running;
183 }
184
185 public DiagnosticContainerResult getContainerResult() {
186 return containerResult;
187 }
188
189
190
191
192 public void setRunListeners(List runListeners) {
193 this.runListeners.clear();
194 this.runListeners.addAll(runListeners);
195 }
196
197
198
199
200 public void setResultListeners(List resultListeners) {
201 this.resultListeners.clear();
202 this.resultListeners.addAll(resultListeners);
203 }
204 }