/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.piazza.commons.module;
import java.util.Properties;
import hk.hku.cecid.piazza.commons.util.StringUtilities;
/**
* ActiveModule is a runnable module which runs as a separated thread after
* started. Subclasses are expected to implement the run() method in the
* Runnable interface.
*
* @author Hugo Y. K. Lam
*
*/
public abstract class ActiveModule extends Module implements Runnable {
private Thread thread;
private String groupExecution;
private long executionInterval = 60000;
private long stopTimeout;
private boolean isStopping;
/**
* Creates a new instance of ActiveModule.
*
* @param descriptorLocation the module descriptor.
* @throws ModuleException if errors encountered when loading the module descriptor.
*/
public ActiveModule(String descriptorLocation) {
super(descriptorLocation);
}
/**
* Creates a new instance of ActiveModule.
*
* @param descriptorLocation the module descriptor.
* @param shouldInitialize true if the module should be initialized.
* @throws ModuleException if errors encountered when loading the module descriptor.
*/
public ActiveModule(String descriptorLocation, boolean shouldInitialize) {
super(descriptorLocation, shouldInitialize);
}
/**
* Creates a new instance of ActiveModule.
*
* @param descriptorLocation the module descriptor.
* @param loader the class loader for this module.
* @throws ModuleException if errors encountered when loading the module descriptor.
*/
public ActiveModule(String descriptorLocation, ClassLoader loader) {
super(descriptorLocation, loader);
}
/**
* Creates a new instance of ActiveModule.
*
* @param descriptorLocation the module descriptor.
* @param loader the class loader for this module.
* @param shouldInitialize true if the module should be initialized.
* @throws ModuleException if errors encountered when loading the module descriptor.
*/
public ActiveModule(String descriptorLocation, ClassLoader loader,
boolean shouldInitialize) {
super(descriptorLocation, loader, shouldInitialize);
}
/**
* Checks if this module should be started by its group, if any.
*
* @return true if this module should be started by its group.
*/
public boolean isGroupStart() {
return groupExecution.equalsIgnoreCase("all") ||
groupExecution.equalsIgnoreCase("start");
}
/**
* Checks if this module should be stopped by its group, if any.
*
* @return true if this module should be stopped by its group.
*/
public boolean isGroupStop() {
return groupExecution.equalsIgnoreCase("all") ||
groupExecution.equalsIgnoreCase("stop");
}
/**
* Initializes this module by the following module parameters:
*
* <ul>
* <li>group-execution: all - started and stopped by its group;
* start - only started by its group;
* stop - only stopped by its group;
* none - not started or stopped by its group.
* <li>execution-interval: the interval (milliseconds) that this module
* should wait until the next execution. A
* negative number indicates a one-time execution.
* <li>stop-timeout: the maximum time (milliseconds) to wait for
* stopping this module.
* </ul>
*/
public void init() {
super.init();
Properties params = getParameters();
groupExecution = params.getProperty("group-execution", "all");
executionInterval = StringUtilities.parseLong(params.getProperty("execution-interval"), -1);
stopTimeout = StringUtilities.parseLong(params.getProperty("stop-timeout"), 0);
}
/**
* Set the execution interval in the module.
*
*/
public void setExecutionInterval(long newInterval){
this.executionInterval = newInterval;
}
/**
* Starts this module. This method will invoke onStart() before starting its
* own thread.
*
* @see java.lang.Thread#start()
* @see #onStart()
*/
public synchronized void start() {
if (thread == null) {
thread = new Thread(this);
onStart();
thread.start();
}
}
/**
* Stops this module. This method will invoke onStop() before waiting for
* its thread to die.
*
* @see #waitForStop()
* @see #onStop()
*/
public synchronized void stop() {
if (thread != null) {
if (thread.isAlive()) {
isStopping = true;
onStop();
thread.interrupt();
waitForStop();
isStopping = false;
}
thread = null;
}
}
/**
* Waits for this module's thread to die.
*/
public synchronized void waitForStop() {
try {
thread.join(stopTimeout);
}
catch (Exception e) {
return;
}
}
/**
* Invoked when this module starts.
*
* @see #start()
*/
public void onStart() {
}
/**
* Invoked when this module stops.
*
* @see #stop()
*/
public void onStop() {
}
/**
* Gets the thread of this module.
*
* @return the thread of this module.
*/
public Thread getThread() {
return thread;
}
/**
* Invoked by the start() method and will continuously call the execute()
* method to carry out the execution. This method should not be invoked
* directly.
*
* @see #start()
* @see #execute()
* @see java.lang.Runnable#run()
*/
public void run() {
do {
if (!execute()) {
break;
}
try {
if (!isStopping && executionInterval>0) {
Thread.sleep(executionInterval);
}
} catch (InterruptedException e) {
}
}
while (!isStopping && executionInterval>-1);
}
/**
* Invoked by the run() method to execute this module's job.
*
* @return true if this method should be invoked again after a defined interval.
*/
public abstract boolean execute();
}