View Javadoc

1   // 
2   // Copyright (c) 2003, Caltha - Gajda, Krzewski, Mach, Potempski Sp.J. 
3   // All rights reserved. 
4   // 
5   // Redistribution and use in source and binary forms, with or without modification,  
6   // are permitted provided that the following conditions are met: 
7   //  
8   // * Redistributions of source code must retain the above copyright notice,  
9   //	 this list of conditions and the following disclaimer. 
10  // * Redistributions in binary form must reproduce the above copyright notice,  
11  //	 this list of conditions and the following disclaimer in the documentation  
12  //	 and/or other materials provided with the distribution. 
13  // * Neither the name of the Caltha - Gajda, Krzewski, Mach, Potempski Sp.J.  
14  //	 nor the names of its contributors may be used to endorse or promote products  
15  //	 derived from this software without specific prior written permission. 
16  // 
17  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"  
18  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED  
19  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
20  // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  
21  // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  
22  // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
23  // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
24  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)  
25  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE  
26  // POSSIBILITY OF SUCH DAMAGE. 
27  // 
28  package org.objectledge.threads.impl;
29  
30  import org.jcontainer.dna.Logger;
31  import org.objectledge.context.Context;
32  import org.objectledge.pipeline.Valve;
33  import org.objectledge.threads.Task;
34  import org.picocontainer.Startable;
35  
36  /***
37   * A daemon thread helper object.
38   * 
39   * @author <a href="mailto:rafal@caltha.pl">Rafal Krzewski</a>
40   * @version $Id: Daemon.java,v 1.4 2005/02/10 17:46:53 rafal Exp $
41   */
42  public class Daemon
43      implements Runnable, Startable
44  {
45      private Thread thread;
46      
47      private Logger log;
48      
49      private Task task; 
50      
51      private Context context;
52      
53      private Valve cleanup;
54      
55      private boolean shutdown = false;
56      
57      private boolean running = false;
58      
59      /***
60       * Creates a daemon thread.
61       * 
62       * @param task the task to run.
63       * @param priority the task's priority (see {@link java.lang.Thread} description)
64       * @param threadGroup the thread group where the thread should belong.
65       * @param log the logger to use.
66       * @param context thread's processing context.
67       * @param cleanup cleanup valve to invoke, should the task terminate.
68       */
69      public Daemon(Task task, int priority, 
70          ThreadGroup threadGroup, Logger log, Context context, Valve cleanup)
71      {
72          this.log = log;
73          this.context = context;
74          this.task = task;
75          this.cleanup = cleanup;
76          thread = new Thread(threadGroup, this, task.getName());
77          thread.setPriority(priority);
78          thread.setDaemon(true);
79          thread.start();
80      }
81  
82      /***
83       * {@inheritDoc}
84       */    
85      public void run()
86      {
87          log.info("starting "+task.getName());
88          try
89          {
90              running = true;
91              task.process(context);
92          }
93          ///CLOVER:OFF
94          catch(VirtualMachineError e)
95          {
96              throw e;
97          }
98          ///CLOVER:ON
99          catch(ThreadDeath e)
100         {
101             if(!shutdown)
102             {
103                 log.warn(task.getName()+" was forcibly stopped", e);
104             }
105             else
106             {
107                 log.info("finished "+task.getName());
108             }
109             throw e;
110         }
111         catch(Throwable e)
112         {
113             log.error("unhandled exception in "+task.getName(), e);
114         }
115         finally
116         {
117             running = false;
118         }
119         
120         if(shutdown)
121         {
122             log.info("finished "+task.getName());
123         }
124         else
125         {
126             log.error(task.getName()+" has quit");
127         }
128         
129         // cleanup
130         if(cleanup != null)
131         {
132             try
133             {
134                 cleanup.process(context);
135             }
136             ///CLOVER:OFF
137             catch(VirtualMachineError e)
138             {
139                 throw e;
140             }
141             catch(ThreadDeath e)
142             {
143                 throw e;
144             }
145             ///CLOVER:ON
146             catch(Throwable e)
147             {
148                 log.error("error in cleanup after "+task.getName(), e);
149             }
150         }
151     }
152 
153     /***
154      * {@inheritDoc}
155      */    
156     public void start()
157     {
158         // Startable interface should really be split
159     }
160     
161     /***
162      * {@inheritDoc}
163      */    
164     public void stop()
165     {
166         shutdown = true;
167         if(running)
168         {
169             log.info("asking "+task.getName()+" to terminate");
170             task.terminate(thread);
171         }
172         else
173         {
174             log.warn(task.getName()+" is not running");
175         }
176     }
177 }