View Javadoc
1   package org.codehaus.plexus.util;
2   
3   /*
4    * Copyright The Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  /**
20   * A thread which is registered with a ThreadRegistry and notifies it when it has completed running. Collects any errors
21   * and makes it available for analysis.
22   * <p>
23   * Created on 1/07/2003
24   * </p>
25   *
26   * @author <a href="mailto:bert@tuaworks.co.nz">Bert van Brakel</a>
27   * @version $Id: $Id
28   * @since 3.4.0
29   */
30  public abstract class AbstractTestThread implements Runnable {
31      // ~ Instance fields ----------------------------------------------------------------------------
32      private String name;
33  
34      /** Constant <code>DEBUG=true</code> */
35      public static final boolean DEBUG = true;
36  
37      private boolean isRunning = false;
38  
39      /** Error msg provided by implementing class (of why the test failed) */
40      private String errorMsg = null;
41  
42      /** The registry to notify on completion */
43      private TestThreadManager registry;
44  
45      /**
46       * The error thrown when running the test. Not necessarily a test failure as some tests may test for an exception
47       */
48      private Throwable error;
49  
50      /** If the thread has been run */
51      private boolean hasRun = false;
52  
53      /**
54       * Flag indicating if the test has passed. Some test might require an exception so using the error to determine if
55       * the test has passed is not sufficient.
56       */
57      private boolean passed = false;
58  
59      // ~ Constructors -------------------------------------------------------------------------------
60  
61      /**
62       * Constructor
63       * <p>
64       * Remember to call <code>setThreadRegistry(ThreadRegistry)</code>
65       */
66      public AbstractTestThread() {
67          super();
68      }
69  
70      /**
71       * <p>Constructor for AbstractTestThread.</p>
72       *
73       * @param registry a {@link org.codehaus.plexus.util.TestThreadManager} object.
74       */
75      public AbstractTestThread(TestThreadManager registry) {
76          super();
77          setThreadRegistry(registry);
78      }
79  
80      // ~ Methods ------------------------------------------------------------------------------------
81  
82      /**
83       * <p>Getter for the field <code>error</code>.</p>
84       *
85       * @return a {@link java.lang.Throwable} object.
86       */
87      public Throwable getError() {
88          return error;
89      }
90  
91      /**
92       * Resets the test back to it's state before starting. If the test is currently running this method will block until
93       * the test has finished running. Subclasses should call this method if overriding it.
94       */
95      public void reset() {
96          // shouldn't reset until the test has finished running
97          synchronized (this) {
98              while (isRunning) {
99                  try {
100                     wait();
101                 } catch (InterruptedException e) {
102 
103                 }
104             }
105             errorMsg = null;
106             error = null;
107             hasRun = false;
108             passed = false;
109         }
110     }
111 
112     /**
113      * Start this TestThread running. If the test is currently running then this method does nothing.
114      */
115     public final void start() {
116         // shouldn't have multiple threads running this test at the same time
117         synchronized (this) {
118             if (isRunning == false) {
119                 isRunning = true;
120                 Thread t = new Thread(this);
121                 t.start();
122             }
123         }
124     }
125 
126     /**
127      * <p>Getter for the field <code>errorMsg</code>.</p>
128      *
129      * @return a {@link java.lang.String} object.
130      */
131     public String getErrorMsg() {
132         return errorMsg;
133     }
134 
135     /**
136      * <p>hasFailed.</p>
137      *
138      * @return a boolean.
139      */
140     public boolean hasFailed() {
141         return !passed;
142     }
143 
144     /**
145      * DOCUMENT ME!
146      *
147      * @return DOCUMENT ME!
148      */
149     public boolean hasPassed() {
150         return passed;
151     }
152 
153     /**
154      * Don't override this. Calls <code>doRun()</code>
155      *
156      * @see java.lang.Runnable#run()
157      */
158     public final void run() {
159         if (registry == null) {
160             throw new IllegalArgumentException(
161                     "The ThreadRegistry is null. Ensure this is set before running this thread");
162         }
163         passed = false;
164         try {
165             doRun();
166         } catch (Throwable t) {
167             error = t;
168         }
169 
170         registry.completed(this);
171         hasRun = true;
172         isRunning = false;
173         // notify objects with blocked methods which are waiting
174         // on this test to complete running
175         synchronized (this) {
176             notifyAll();
177         }
178     }
179 
180     /**
181      * Override this to run your custom test
182      *
183      * @throws java.lang.Throwable
184      */
185     public abstract void doRun() throws Throwable;
186 
187     /**
188      * Set the registry this thread should notify when it has completed running
189      *
190      * @param registry a {@link org.codehaus.plexus.util.TestThreadManager} object.
191      */
192     public void setThreadRegistry(TestThreadManager registry) {
193 
194         this.registry = registry;
195     }
196 
197     /**
198      * Test if the test has run
199      *
200      * @return a boolean.
201      */
202     public boolean hasRun() {
203         return hasRun;
204     }
205 
206     /**
207      * <p>Setter for the field <code>error</code>.</p>
208      *
209      * @param throwable a {@link java.lang.Throwable} object.
210      */
211     public void setError(Throwable throwable) {
212         error = throwable;
213     }
214 
215     /**
216      * <p>Setter for the field <code>errorMsg</code>.</p>
217      *
218      * @param string a {@link java.lang.String} object.
219      */
220     public void setErrorMsg(String string) {
221         errorMsg = string;
222     }
223 
224     /**
225      * <p>Setter for the field <code>passed</code>.</p>
226      *
227      * @param b a boolean.
228      */
229     public void setPassed(boolean b) {
230         passed = b;
231     }
232 
233     /**
234      * <p>Getter for the field <code>name</code>.</p>
235      *
236      * @return a {@link java.lang.String} object.
237      */
238     public String getName() {
239         return name;
240     }
241 
242     /**
243      * <p>Setter for the field <code>name</code>.</p>
244      *
245      * @param string a {@link java.lang.String} object.
246      */
247     public void setName(String string) {
248         name = string;
249     }
250 
251     private final void debug(String msg) {
252         if (DEBUG) {
253             System.out.println(this + ":" + msg);
254         }
255     }
256 }