View Javadoc

1   package com.explosion.utilities.process.threads;
2   
3   /*
4    * =============================================================================
5    * 
6    * Copyright 2004 Stephen Cowx
7    * 
8    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9    * use this file except in compliance with the License. You may obtain a copy of
10   * the License at
11   * 
12   * http://www.apache.org/licenses/LICENSE-2.0
13   * 
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   * 
20   * =============================================================================
21   */
22  
23  import java.util.Date;
24  
25  import org.apache.log4j.LogManager;
26  import org.apache.log4j.Logger;
27  
28  import com.explosion.utilities.process.ProcessMonitor;
29  /***
30   * This class provides a simple way to control processes.  IE start stop etc.
31   * It provides very simple logic too; the run method does the following
32   * 
33   * 1) process.initialise
34   * 2) while alive or not finished, process.process()
35   * 3) process.finalise
36   * 
37   * @author Stephen
38   * Created on 26-Jun-2004
39   */
40  public class SimpleProcessThread implements ProcessThread
41  {
42      private static Logger log = LogManager.getLogger(SimpleProcessThread.class);
43  
44      /* Thread controls */
45      private int interval = 10;
46  
47      private int priority = Thread.NORM_PRIORITY;
48  
49      private Thread executionThread;
50  
51      private Thread thisThread;
52  
53      /* Control elements */
54      private boolean finalised = false;
55  
56      private com.explosion.utilities.process.threads.SimpleProcess process;
57  
58      private Date startTime = null;
59  
60      private Date endTime = null;
61  
62      private int status = THREAD_NOT_YET_STARTED;
63  
64      private boolean wasKilled = false;
65      
66      private boolean join = false;
67      
68      /***
69       * For an explanation on implementing safely stoppable and suspendable
70       * threads please see
71       * 
72       * @see http://java.sun.com/products/jdk/1.2/docs/guide/misc/threadPrimitiveDeprecation.html
73       */
74      public void run()
75      {
76          try
77          {
78              thisThread = Thread.currentThread();
79              
80              checkSuspended();
81  
82              if (process == null)
83              {
84                 log.warn("No process specified, exiting simple process control.");
85                 return;
86              }
87              
88              ProcessMonitor.registerProcess(this, process.isUserProcess());
89              
90              process.initialise();
91  
92              checkSuspended();
93  
94              /* Perform processing */
95              while (executionThread == thisThread && process.getPercentComplete() < 100)
96              {
97                  checkSuspended();
98                  if (status == THREAD_STOPPED) break;
99  
100                 process.process();
101 
102                 checkSuspended();
103                 if (status == THREAD_STOPPED) break;
104 
105                 /* Sleep for required interval */
106                 try
107                 {
108                     if (interval > 0) Thread.sleep(interval);
109                 } catch (InterruptedException e)
110                 {}
111             }
112 
113             process.finalise();
114         } catch (Exception ex)
115         {
116             if (process != null)
117                 process.finalise(ex);
118         }
119 
120         try {
121 			stop();
122 		} catch (InterruptedException e) {
123 			//ignore
124 			log.error("Interrupted",e);
125 		}
126 
127         /* Set the status to completed */
128         status = THREAD_COMPLETED;
129     }
130 
131     /***
132      * Performs suspend logic if the thread has been suspended
133      */
134     public void checkSuspended()
135     {
136         /* Suspend if required */
137         if (status == THREAD_SUSPENDED)
138         {
139             synchronized (this)
140             {
141                 while (status == THREAD_SUSPENDED && executionThread == thisThread)
142                 {
143                     try
144                     {
145                         wait();
146                     } catch (InterruptedException e)
147                     {}
148                 }
149             }
150         }
151     }
152 
153     /***
154      * Starts the job.  If join has been specified then this method will not return until the job has finished.
155      */
156     public void start()
157     {
158         status = THREAD_STARTED;
159         startTime = new Date();
160 
161         executionThread = new Thread(this);
162         executionThread.setPriority(priority);
163         executionThread.start();
164         
165         try
166         {
167             if (join)
168                 executionThread.join();
169         }
170         catch (InterruptedException e)
171         {
172         }
173     }
174     
175     /***
176      * This parameter needs to be set before the process is started.  If set to true, the 
177      * process will call thread.join and will not return from the start method until the run thread is finished.
178      * @param join
179      */
180     public void setJoin(boolean join)
181     {
182         this.join = join;
183     }
184     
185 
186     /***
187      * Stop the job
188      */
189     public synchronized void stop() throws InterruptedException
190     {
191         if (!(status == THREAD_STOPPED))
192         {
193             executionThread = null;
194             notify();
195             endTime = new Date();
196             status = THREAD_STOPPED;
197         }
198         
199         thisThread.interrupt();
200         if (executionThread != null)
201            executionThread.interrupt();
202         
203         if (executionThread != null && executionThread.isAlive())
204         {
205         	executionThread.stop();
206         }
207     }
208 
209     /***
210      * Ssuspend the job.
211      */
212     public synchronized void suspend()
213     {
214         status = THREAD_SUSPENDED;
215     }
216 
217     /***
218      * Restart the job.
219      */
220     public synchronized void resume()
221     {
222         status = THREAD_STARTED;
223         notifyAll();
224     }
225 
226     /***
227      * This method allows the user to set the Thread priority of this
228      * controllable object. Possible priorities are: a) Thread.NORM_PRIORITY, b)
229      * Thread.MAX_PRIORITY c) Thread.MIN_PRIORITY The default priority is
230      * Thread.NORM_PRIORITY.
231      */
232     public void setPriority(int priority)
233     {
234         this.priority = priority;
235     }
236 
237     /***
238      * This method allows the user to set the interval between each thread loop.
239      * Default is 10 (0.001 seconds);
240      */
241     public void setInterval(int interval)
242     {
243         this.interval = interval;
244     }
245 
246     /***
247      * Set the UnitisedProcess for this UnitisedProcess
248      */
249     public void setProcess(com.explosion.utilities.process.threads.Process process)
250     {
251         this.process = (SimpleProcess) process;
252     }
253 
254     /***
255      * Gets the process for this UnitisedProcess
256      */
257     public com.explosion.utilities.process.threads.Process getProcess()
258     {
259         return process;
260     }
261 
262     /***
263      * This method returns the actual thread object upon which this Runnable
264      * object is operating.
265      */
266     public Thread getRunThread()
267     {
268         return thisThread;
269     }
270 
271     /***
272      * This method returns status of the thread
273      */
274     public int getStatus()
275     {
276         return status;
277     }
278 
279     /***
280      * Kills the job
281      */
282     public void kill()
283     {
284         try {
285 			stop();
286 		} catch (InterruptedException e) {
287 			//ignore
288 			log.error("Interrupted",e);
289 		}
290         wasKilled = true;
291     }
292 
293     /***
294      * Returns whether or not the job was killed
295      */
296     public boolean wasKilled()
297     {
298         return wasKilled;
299     }
300 
301 }
302