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 }