/**
* Copyright 2008 - CommonCrawl Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
**/
package org.commoncrawl.service.pagerank.slave;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.commoncrawl.async.Callback;
import org.commoncrawl.async.CallbackWithResult;
import org.commoncrawl.util.CCStringUtils;
public abstract class PageRankTask<ResultType extends PageRankTask.PageRankTaskResult> implements CancelableTask {
private static final Log LOG = LogFactory.getLog(PageRankTask.class);
PageRankSlaveServer _server;
CallbackWithResult<ResultType> _callback;
boolean _cancelling = false;
Thread _taskThread = null;
ResultType _result;
public float _percentComplete = 0.0f;
public long _startTime;
public static class PageRankTaskResult {
protected boolean _failed = false;
protected String _failureReason = null;
public boolean succeeded() {
return !_failed;
}
public void setFailed(String failureReason) {
_failed = true;
_failureReason = failureReason;
}
public String getErrorDesc() {
return _failureReason;
}
}
public PageRankTask(PageRankSlaveServer server,Class<ResultType> resultTypeClass,CallbackWithResult<ResultType> completionCallback) {
_server = server;
_callback = completionCallback;
try {
_result = resultTypeClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/** get the task description **/
public abstract String getDescription();
/** cancel check **/
public synchronized boolean isCancelled() {
return _cancelling;
}
/** start the task thread **/
public void start() {
_startTime = System.currentTimeMillis();
LOG.info("Task start called");
_server.taskStarting(this);
_taskThread = new Thread(new Runnable() {
@Override
public void run() {
LOG.info("Task Thread Running");
// start the actual task
try {
LOG.info("Entering runTask");
_result = runTask();
LOG.info("Exiting runTask");
} catch (Exception e) {
LOG.error(CCStringUtils.stringifyException(e));
_result.setFailed(CCStringUtils.stringifyException(e));
}
boolean doCallback = true;
// now synchronize on this
synchronized(this) {
// if NOT cancelling ...
if (!_cancelling) {
LOG.info("Exiting Task Thread Normally");
// set done to true ...
_taskThread = null;
}
// otherwise skip callback ...
else {
LOG.info("Exiting Task via Cancel");
doCallback = false;
}
}
// now if callback is required ...
if (doCallback) {
LOG.info("Task Thread Queueing Callback");
// schedule an async callback with result ...
_server.getEventLoop().queueAsyncCallback(new Callback() {
@Override
public void execute() {
LOG.info("Task Thread Executing Async Callback");
_callback.execute(_result);
_server.taskComplete(PageRankTask.this);
}
});
}
}
});
LOG.info("starting Task Thread");
_taskThread.start();
}
protected abstract ResultType runTask() throws IOException;
protected abstract void cancelTask();
public void cancel(final Callback cancelCompleteCallback) {
// synchronize on this ...
synchronized(this) {
_cancelling = true;
// if the underlying task is already done, then we are late to the party ...
if (_taskThread == null) {
cancelCompleteCallback.execute();
}
// otherwise ... set the cancelling flag ...
}
if (_taskThread != null) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// cancel the task ...
cancelTask();
// and wait for task thread to exit
_taskThread.join();
// and now null task thread ...
synchronized(this) {
_taskThread = null;
}
} catch (InterruptedException e) {
}
_server.getEventLoop().queueAsyncCallback(new Callback() {
@Override
public void execute() {
cancelCompleteCallback.execute();
}
});
}
}).start();
}
else {
cancelCompleteCallback.execute();
}
}
}