* Implement app.invokeAsync() using public FutureResult interface.

This commit is contained in:
hns 2007-04-02 15:51:02 +00:00
parent a0ea3b31de
commit 7f58c102bf
2 changed files with 146 additions and 73 deletions

View file

@ -0,0 +1,59 @@
/*
* Copyright 2006 Hannes Wallnoefer <hannes@helma.at>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package helma.framework;
/**
* A handle for an asynchronous request execution. This allows to wait for
* request termination, get the result or the exception of the execution.
*/
public interface FutureResult {
/**
* Get the result of the execution. If the execution is still active,
* or if the invocation threw an exception, this method immediately returns null.
* @return the result, or null
*/
Object getResult();
/**
* Get the exception of the execution, if one was thrown. If the execution
* is still active, or if no exception was thrown, this method immediately returns null.
* @return the exception, or null
*/
Exception getException();
/**
* Returns true if the execution is still active, and false if not.
* @return true if the execution is still active
*/
boolean getRunning();
/**
* Wait for execution to terminat, returning the execution result, if one is available.
* @return the execution result, or null
* @throws InterruptedException if we were interrupted by some other thread
*/
Object waitForResult() throws InterruptedException;
/**
* Wait for a specific ammount of thime for the execution to terminate, returning
* the execution result, if one is available.
* @param timeout the number of milliseconds to wait
* @return the execution result, or null
* @throws InterruptedException if we were interrupted by some other thread
*/
Object waitForResult(long timeout) throws InterruptedException;
}

View file

@ -22,6 +22,7 @@ import helma.util.CronJob;
import helma.util.SystemMap;
import helma.util.WrappedMap;
import helma.framework.repository.*;
import helma.framework.FutureResult;
import helma.main.Server;
import java.io.File;
@ -33,7 +34,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* Application bean that provides a handle to the scripting environment to
* application specific functionality.
*/
public class ApplicationBean implements Serializable {
Application app;
@ -682,11 +684,11 @@ public class ApplicationBean implements Serializable {
* this long, we will try to interrupt the invocation
* @return an object with the properties described above
*/
public Object invokeAsync(Object thisObject,
public FutureResult invokeAsync(Object thisObject,
final Object function,
final Object[] args) {
// default timeout of 15 minutes
return invokeAsync(thisObject, function, args, 60000L * 15);
return new AsyncInvoker(thisObject, function, args, 60000L * 15);
}
/**
@ -712,76 +714,9 @@ public class ApplicationBean implements Serializable {
* this long, we will try to interrupt the invocation
* @return an object with the properties described above
*/
public Object invokeAsync(final Object thisObject,
final Object function,
final Object[] args,
final long timeout) {
Thread thread = new Thread() {
private Object result;
private Exception exception;
private boolean running = true;
public void run() {
RequestEvaluator reval = null;
try {
reval = app.getEvaluator();
setResult(reval.invokeInternal(thisObject, function, args, timeout));
} catch (Exception x) {
setException(x);
} finally {
running = false;
app.releaseEvaluator(reval);
}
}
public synchronized boolean getRunning() {
return running;
}
private synchronized void setResult(Object obj) {
result = obj;
running = false;
notifyAll();
}
public synchronized Object getResult() {
return result;
}
public synchronized Object waitForResult() throws InterruptedException {
if (!running)
return result;
wait();
return result;
}
public synchronized Object waitForResult(long timeout)
throws InterruptedException {
if (!running)
return result;
wait(timeout);
return result;
}
private synchronized void setException(Exception x) {
exception = x;
running = false;
notifyAll();
}
public synchronized Exception getException() {
return exception;
}
public String toString() {
return new StringBuffer("AsyncInvokeThread{running: ").append(running)
.append(", result: ").append(result).append(", exception: ")
.append(exception).append("}").toString();
}
};
thread.start();
return thread;
public FutureResult invokeAsync(Object thisObject, Object function,
Object[] args, long timeout) {
return new AsyncInvoker(thisObject, function, args, timeout);
}
/**
@ -791,4 +726,83 @@ public class ApplicationBean implements Serializable {
public String toString() {
return "[Application " + app.getName() + "]";
}
class AsyncInvoker extends Thread implements FutureResult {
private Object thisObject;
private Object function;
private Object[] args;
private long timeout;
private Object result;
private Exception exception;
private boolean running = true;
private AsyncInvoker(Object thisObj, Object func, Object[] args, long timeout) {
thisObject = thisObj;
function = func;
this.args = args;
this.timeout = timeout;
start();
}
public void run() {
RequestEvaluator reval = null;
try {
reval = app.getEvaluator();
setResult(reval.invokeInternal(thisObject, function, args, timeout));
} catch (Exception x) {
setException(x);
} finally {
running = false;
app.releaseEvaluator(reval);
}
}
public synchronized boolean getRunning() {
return running;
}
private synchronized void setResult(Object obj) {
result = obj;
running = false;
notifyAll();
}
public synchronized Object getResult() {
return result;
}
public synchronized Object waitForResult() throws InterruptedException {
if (!running)
return result;
wait();
return result;
}
public synchronized Object waitForResult(long timeout)
throws InterruptedException {
if (!running)
return result;
wait(timeout);
return result;
}
private synchronized void setException(Exception x) {
exception = x;
running = false;
notifyAll();
}
public synchronized Exception getException() {
return exception;
}
public String toString() {
return new StringBuffer("AsyncInvokeThread{running: ").append(running)
.append(", result: ").append(result).append(", exception: ")
.append(exception).append("}").toString();
}
}
}