* Implement app.invokeAsync() using public FutureResult interface.
This commit is contained in:
parent
a0ea3b31de
commit
7f58c102bf
2 changed files with 146 additions and 73 deletions
59
src/helma/framework/FutureResult.java
Normal file
59
src/helma/framework/FutureResult.java
Normal 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;
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ import helma.util.CronJob;
|
||||||
import helma.util.SystemMap;
|
import helma.util.SystemMap;
|
||||||
import helma.util.WrappedMap;
|
import helma.util.WrappedMap;
|
||||||
import helma.framework.repository.*;
|
import helma.framework.repository.*;
|
||||||
|
import helma.framework.FutureResult;
|
||||||
import helma.main.Server;
|
import helma.main.Server;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -33,7 +34,8 @@ import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
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 {
|
public class ApplicationBean implements Serializable {
|
||||||
Application app;
|
Application app;
|
||||||
|
@ -682,11 +684,11 @@ public class ApplicationBean implements Serializable {
|
||||||
* this long, we will try to interrupt the invocation
|
* this long, we will try to interrupt the invocation
|
||||||
* @return an object with the properties described above
|
* @return an object with the properties described above
|
||||||
*/
|
*/
|
||||||
public Object invokeAsync(Object thisObject,
|
public FutureResult invokeAsync(Object thisObject,
|
||||||
final Object function,
|
final Object function,
|
||||||
final Object[] args) {
|
final Object[] args) {
|
||||||
// default timeout of 15 minutes
|
// 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
|
* this long, we will try to interrupt the invocation
|
||||||
* @return an object with the properties described above
|
* @return an object with the properties described above
|
||||||
*/
|
*/
|
||||||
public Object invokeAsync(final Object thisObject,
|
public FutureResult invokeAsync(Object thisObject, Object function,
|
||||||
final Object function,
|
Object[] args, long timeout) {
|
||||||
final Object[] args,
|
return new AsyncInvoker(thisObject, function, args, timeout);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -791,4 +726,83 @@ public class ApplicationBean implements Serializable {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[Application " + app.getName() + "]";
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue