001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2002 Janne Jalkanen (Janne.Jalkanen@iki.fi)
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.util;
021:
022: import com.ecyrd.jspwiki.InternalWikiException;
023: import com.ecyrd.jspwiki.WikiEngine;
024: import com.ecyrd.jspwiki.event.WikiEngineEvent;
025: import com.ecyrd.jspwiki.event.WikiEvent;
026: import com.ecyrd.jspwiki.event.WikiEventListener;
027:
028: /**
029: * Abstract Thread subclass that operates in the background;
030: * when it detects the {@link WikiEngineEvent#SHUTDOWN} event,
031: * it terminates itself. Subclasses of this method need only
032: * implement the method {@link #backgroundTask()}, instead of
033: * the normal {@link Thread#run()}, and provide a constructor that
034: * passes the WikiEngine and sleep interval. This class is
035: * thread-safe.
036: * @author Andrew Jaquith
037: */
038: public abstract class WikiBackgroundThread extends Thread implements
039: WikiEventListener {
040: private volatile boolean m_killMe = false;
041: private final WikiEngine m_engine;
042: private final int m_interval;
043: private static final long POLLING_INTERVAL = 1000L;
044:
045: /**
046: * Constructs a new instance of this background thread with
047: * a specified sleep interval, and adds the new instance to the
048: * wiki engine's event listeners.
049: * @param engine the wiki engine
050: * @param sleepInterval the interval between invocations of
051: * the thread's {@link Thread#run()} method, in seconds
052: */
053: public WikiBackgroundThread(WikiEngine engine, int sleepInterval) {
054: super ();
055: m_engine = engine;
056: m_interval = sleepInterval;
057: engine.addWikiEventListener(this );
058: setDaemon(false);
059:
060: }
061:
062: /**
063: * Listens for {@link com.ecyrd.jspwiki.event.WikiEngineEvent#SHUTDOWN}
064: * and, if detected, marks the thread for death.
065: * @see com.ecyrd.jspwiki.event.WikiEventListener#actionPerformed(com.ecyrd.jspwiki.event.WikiEvent)
066: */
067: public final void actionPerformed(WikiEvent event) {
068: if (event instanceof WikiEngineEvent) {
069: if (((WikiEngineEvent) event).getType() == WikiEngineEvent.SHUTDOWN) {
070: System.out
071: .println("Detected wiki engine shutdown: killing "
072: + getName() + ".");
073: m_killMe = true;
074: }
075: }
076: }
077:
078: /**
079: * Abstract method that performs the actual work for this
080: * background thread; subclasses must implement this method.
081: */
082: public abstract void backgroundTask() throws Exception;
083:
084: /**
085: * Returns the WikiEngine that created this background thread.
086: * @return the wiki engine
087: */
088: public WikiEngine getEngine() {
089: return m_engine;
090: }
091:
092: /**
093: * Requests the shutdown of this background thread. Note that the shutdown
094: * is not immediate.
095: *
096: * @since 2.4.92
097: *
098: */
099: public void shutdown() {
100: m_killMe = true;
101: }
102:
103: /**
104: * Runs the background thread's {@link #backgroundTask()} method
105: * at the interval specified at construction.
106: * The thread will initially pause for a full sleep interval
107: * before starting, after which it will execute
108: * {@link #startupTask()}. This method will cleanly
109: * terminates the thread if the it has previously
110: * been marked for death, before which it will execute
111: * {@link #shutdownTask()}. If any of the three methods
112: * return an exception, it will be re-thrown as a
113: * {@link com.ecyrd.jspwiki.InternalWikiException}.
114: * @see java.lang.Thread#run()
115: */
116: public final void run() {
117: try {
118: // Perform the initial startup task
119: final String name = getName();
120: System.out.println("Starting up background thread: " + name
121: + ".");
122: startupTask();
123:
124: // Perform the background task; check every
125: // second for thread death
126: while (!m_killMe) {
127: // Perform the background task
128: // log.debug( "Running background task: " + name + "." );
129: backgroundTask();
130:
131: // Sleep for the interval we're supposed do, but
132: // wake up every second to see if thread should die
133: boolean interrupted = false;
134: try {
135: for (int i = 0; i < m_interval; i++) {
136: Thread.sleep(POLLING_INTERVAL);
137: if (m_killMe) {
138: interrupted = true;
139: System.out
140: .println("Interrupted background thread: "
141: + name + ".");
142: break;
143: }
144: }
145: if (interrupted) {
146: break;
147: }
148: } catch (Throwable t) {
149: System.err
150: .println("Background thread error: (stack trace follows)");
151: t.printStackTrace();
152: }
153: }
154:
155: // Perform the shutdown task
156: shutdownTask();
157: } catch (Throwable t) {
158: System.err
159: .println("Background thread error: (stack trace follows)");
160: t.printStackTrace();
161: throw new InternalWikiException(t.getMessage());
162: }
163: }
164:
165: /**
166: * Executes a task after shutdown signal was detected.
167: * By default, this method does nothing; override it
168: * to implement custom functionality.
169: */
170: public void shutdownTask() throws Exception {
171: }
172:
173: /**
174: * Executes a task just after the thread's {@link Thread#run()}
175: * method starts, but before the {@link #backgroundTask()}
176: * task executes. By default, this method does nothing;
177: * override it to implement custom functionality.
178: */
179: public void startupTask() throws Exception {
180: }
181:
182: }
|