I am trying to search when GTA5.exe ends. It launches with "steam://rungameid" protocol, so I can't use Process#waitFor(); method.
The method below checks if (currently) the process is running
public static boolean isProcessRunning(String processName) throws IOException {
ProcessBuilder processBuilder = new ProcessBuilder("tasklist.exe");
Process process = processBuilder.start();
String tasksList = toString(process.getInputStream());
return tasksList.contains(processName);
}
But what I want is something like
waitUntilProcessEnds(String processname) {
}
It could be
while (isProcessRunning) {
Thread.sleep(1000);
}
And, as expected, my JavaFX app freezes.
If I try to run the while method in another Thread, my JavaFX App gives this error:
java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-6
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:444)
at javafx.scene.control.Dialog.show(Dialog.java:294)
at com.thunderstorm.gta5.mod_installer.app.AppController$1$1.run(AppController.java:101)
at java.lang.Thread.run(Thread.java:748)
I also tried this
Platform.runLater();
and this
Platform.setImplicitExit(false);
But nothing different...
How to fix this
This question is edited
There is an API, but it requires Java 9 or newer. Then, you can do it smoothly:
String name = "GTA5.exe";
ProcessHandle.allProcesses()
.filter(ph -> ph.info().command()
.filter(s -> s.regionMatches(true,s.length()-name.length(),name,0,name.length()))
.isPresent())
.findAny()
.ifPresentOrElse(ph -> {
System.out.println("Waiting for "+ph.pid()+" "+ph.info().command().get());
ph.onExit().thenRunAsync(() -> {
// your actual action
}, Platform::runLater);
}, () -> System.out.println("No matching process found"));
ProcessHandle.onExit() returns a CompletableFuture which allows to chain dependent actions, to be performed on the process’ completion. So you don’t need to poll the process yourself.
Further note that Platform.runLater(Runnable) matches the functional signature of the Executor interface which allows us to use thenRunAsync(…, Platform::runLater) to mandate that the dependent action (Runnable) should be executed in the JavaFX Application Thread, once the process has exited.
I think your design is ok, but you're a bit confused by the threads. First when you start your wait method, go ahead and start a new Thread.
new Thread( ()->{
waitUntilProcessEnds(processname);
Platform.runLater( ()-> callBackOnPlatformThread() );
}).start();
Then you need.
public void callBackOnPlatformThread(){
System.out.println("go ahead and modify fx components.");
}
This will start waiting for the process to end on a new thread, so your javafx UI will continue to be responsive. When it is finished, it calls back on the javafx Platform thread, so you can modify components.
This doesn't check if the thread has already been started, so if you have a button that starts the thread, you could start a bunch of them.
What are you trying to achieve? If you want to execute some code when your application ends then you can add a shutdown hook:
Runtime.getRuntime().addShutdownHook(() -> { ... });
If you want to wait until the external process ends, then you can use:
process.waitFor()
This will block your current thread until the external process exits.
Not if your program didn't create the process in the first place.
Java does not provide operating-system level facilities that are not provided in the underlying OS in the first place. In Unix-like systems, for example, "wait for process exit" can only be executed by an ancestor of the process in question. In Windows, for another example, you have to possess a handle on the process, which you would have obtained from creating the process.
You'll have to roll your own. Create a thread which periodically checks for the existence of the process you are monitoring, by whatever means is suitable to that process and your operating environment. Worst-case you'll have to fork a 'ps' command (or similar) and parse the output.
I can't advise on the JavaFX issue; not my area.
Related
I am using SparkLauncher in Spark v1.6.0. My problem is that when I use this class to launch my Spark jobs, it returns immediately and no job is submitted. My code is as follows.
new SparkLauncher()
.setAppName("test word count")
.setAppResource("file://c:/temp/my.jar")
.setMainClass("my.spark.app.Main")
.setMaster("spark://master:7077")
.startApplication(new SparkAppHandler.Listener() {
#Override public void stateChanged(SparkAppHandle h) { }
#Override public void infoChanged(SparkAppHandle h) { }
});
When I debug into the code, I notice, to my surprise, that all this clazz really does is calls a script spark-submit.cmd using ProcessBuilder.
[C:/tmp/spark-1.6.0-bin-hadoop2.6/bin/spark-submit.cmd, --master, spark://master:7077, --name, "test word count", --class, my.spark.appMain, C:/temp/my.jar]
However, if I run this command (the one that is run by ProcessBuilder) directly on the console, a Spark job is submitted. Any ideas on what's going on?
There's another method SparkLauncher.launch() that is available, but the javadocs say to avoid this method.
Any idea what's going on?
If it works in the console but not from your program, you may need to tell the SparkLauncher where your Spark home is by:
.setSparkHome("C:/tmp/spark-1.6.0-bin-hadoop2.6")
But there could be other things going wrong. You may want to capture additional debugging information by using:
.addSparkArg("--verbose")
and
Map<String, String> env = Maps.newHashMap();
env.put("SPARK_PRINT_LAUNCH_COMMAND", "1");
Pass the env object to the SparkLauncher constructor:
new SparkLauncher(env)
How do you place the new SparkLauncher() statement in the program?
If the main program/unit test immediately finishes after invoking .startApplication(), then the child-process created by it is terminated as well.
You can check the state of the job with the handle created
SparkAppHandle handle = new SparkLauncher()
.setAppName("test word count")
.setAppResource("file://c:/temp/my.jar")
.setMainClass("my.spark.app.Main")
.setMaster("spark://master:7077")
.startApplication();
handle.getState(); // immediately returns UNKNOWN
Thread.sleep(1000); // wait a little bit...
handle.getState(); // the state may have changed to CONNECTED or others
I think that it is because the application takes a certain time to connect to the master, if the program ends before the connection is established, then no job is submitted.
You need to wait for the launcher to get connected to driver nd get you app id and status. For that you can do while loop or something similar.
eg.
while(!handle.getState().isFinal()) {
logger.info("Current state: "+ handle.getState())
logger.info("App Id "+ handle.getAppId());
Thread.sleep(1000L);
// other stuffs you want to do
//
}
In the code below i have javascript running in a separate thread from the main one. That script is an infinite loop, so it needs to be terminated somehow. How?
Calling .cancel() is not working AFTER the script begins running. But if i call .cancel() just after the thread initialization, it will terminate it (the commented out line).
package testscriptterminate;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.Timer;
import java.util.TimerTask;
public class TestScriptTerminate extends TimerTask{
private ExecutorService threads;
private Future runScript;
private Timer t;
public TestScriptTerminate(){
t = new Timer();
t.schedule(this, 6000); //let the script run for a while before attempt to cancel
threads = Executors.newFixedThreadPool(1);
runScript = threads.submit(new ScriptExec());
//runScript.cancel(true); //will cancel here, before the script had a change to run, but useless, i want to cancel at any time on demand
}
#Override
public void run(){
//after script has fully initialized and ran for a while - attempt to cancel.
//DOESN'T WORK, thread still active
System.out.println("Canceling now...");
runScript.cancel(true);
}
public static void main(String[] args) {
new TestScriptTerminate();
}
}
class ScriptExec implements Runnable{
private ScriptEngine js;
private ScriptEngineManager scriptManager;
public ScriptExec(){
init();
}
#Override
public void run() {
try {
js.eval("while(true){}");
} catch (ScriptException ex) {
System.out.println(ex.toString());
}
}
private void init(){
scriptManager = new ScriptEngineManager();
js = scriptManager.getEngineByName("nashorn");
}
}
So this is old, but i just wrote this up and thought it would probably be valuable to share. By default there is ~nothing you can do to stop a Nashorn script executing, .cancel() Thread.stop() Thread.interrupt() do nothing, but if you are willing to put in a bit of effort and are ok with rewriting some bytecode, it is achieveable. Details:
http://blog.getsandbox.com/2018/01/15/nashorn-interupt/
JavaScript (under Nashorn), like Java, will not respond to an interrupt in the middle of a tight loop. The script needs to poll for interruption and terminate the loop voluntarily, or it can call something that checks for interruption and let InterruptedException propagate.
You might think that Nashorn is "just running a script" and that it should be interrupted immediately. This doesn't apply, for the same reason that it doesn't apply in Java: asynchronous interruption risks corruption of the application's data structures, and there is essentially no way to avoid it or recover from it.
Asynchronous interruption brings in the same problems as the long-deprecated Thread.stop method. This is explained in this document, which is an updated version of the document linked in the comments.
Java Thread Primitive Deprecation
See also Goetz, Java Concurrency In Practice, Chapter 7, Cancellation and Shutdown.
The easiest way to check for interruption is to call Thread.interrupted(). You can call this quite easily from JavaScript. Here's a rewrite of the example program that cancels the running script after five seconds:
public class TestScriptTerminate {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
void script() {
ScriptEngineManager scriptManager = new ScriptEngineManager();
ScriptEngine js = scriptManager.getEngineByName("nashorn");
try {
System.out.println("Script starting.");
js.eval("while (true) { if (java.lang.Thread.interrupted()) break; }");
System.out.println("Script finished.");
} catch (ScriptException ex) {
ex.printStackTrace();
}
}
void init() throws Exception {
Future<?> scriptTask = pool.submit(this::script);
pool.schedule(() -> {
System.out.println("Canceling now...");
scriptTask.cancel(true);
}, 5, TimeUnit.SECONDS);
pool.shutdown();
}
public static void main(String[] args) throws Exception {
new TestScriptTerminate().init();
}
}
Since we're starting up a thread pool, might as well make it a scheduled thread pool so that we can use it for both the script task and the timeout. That way we can avoid Timer and TimerTask, which are mostly replaced by ScheduledExecutorService anyway.
The usual convention when handling and interrupt is either to restore the interrupt bit or to let an InterruptedException propagate. (One should never ignore an interrupt.) Since breaking out of the loop can be considered to have completed the handling of the interrupt, neither is necessary, and it seems sufficient simply to let the script exit normally.
This rewrite also moves a lot of work out of the constructor into an init() method. This prevents the instance from being leaked to other threads from within the constructor. There is no obvious danger from this in the original example code -- in fact, there almost never is -- but it's always good practice to avoid leaking the instance from the constructor.
Unfortunately it does not work for simple infinite loops: while (true) { }. I tried Thread.cancel(); does not cause the thread to exit. I wanted something foolproof for running scripts in an IntelliJ plugin where a user can make a mistake an cause an infinite loop, hanging the plugin.
The only thing I found to work in most cases is Thread.stop(). Even that does not work for a script like this:
while(true) {
try {
java.lang.Thread.sleep(100);
} catch (e) {
}
}
javascript catches the java.lang.ThreadDeath exception and keeps going. I found that the above sample is impossible to interrupt even with several Thread.stop() issued one after the other. Why would I use several? Hoping that one of them will catch the thread in its exception processing code and abort it. Which does work if there is something in the catch block to process as simple as var i = "" + e; that is enough to cause the second Thread.stop() to end it.
So the moral of the story is there is no fail safe way of ending a runaway script in Nashorn, but there is something that will work on most cases.
My implementation issues a Thread.interrupt(), then politely waits 2 seconds for the thread to terminate and if that fails then it issues Thread.stop() twice. If that does not work, then nothing else will either.
Hope it helps someone eliminate hours of experimentation to find a more reliable method to stop nashorn runaway scripts than hoping on the cooperation of the running script to respect Thread.cancel().
I have a similar problem where I let users write their own scripts.
But before I allow the script to be executed, I parse the script.
and if I find any of the following
(System.sleep. Exit, Thread.sleep, goto) etc
I don't even start the script, and I give user an error.
and then I do a search for all
(for,loops, while, doWhile), and I inject a method.
checkForLoop() just after the loop identifier.
I inject checkForLoop(); into allow user submitted script.
while(users code)
{
}
becomes
while ( checkForLoop() && users code )
{
}
This way before every iteration of their loop, my method is called.
and I can count how many times I was called or check internal timers.
Than I can stop the loops or timers from inside checkForLoop();
Honestly I think its a big security issue anyway, just to blindly let users write script and just execute it.
You need to build in a system that injects your code into their code loops.
Which is not that hard.
There are 100s of safety mechanisms you can apply to users submitted code, there is no RULE that says you need to run their code as is.
I have edited this answer to include a very simple example.
//Step 1
put the users submitted JS code into a Java String called userJSCode;
Step 2
//inject code at the start of their code.
String safeWhile ="var sCount=0; var sMax=10;
function safeWhileCheck(){ sCount++;
if ( return ( sCount > sMax )}";
userJSCode = safeWhile + userJSCode;
//Step 3: inject the custom while code
String injectSsafeWHile = "while( safeWhileCheck() && ";
userJSCode = userJSCode.replace("while(", injectSsafeWHile);
//Step 4: execute custom JS code
nashhorn.execute(injectSsafeWHile);
//Here is users bad submitted code, note no i increment in the loop, it would go on for ever.
var i=0;
while ( i <1000 )
console.log("I am number " + i);
using the steps above we end up with
var sCount=0;var sMax=10;
function safeWhileCheck(){
sCount++;
return ( sCount > sMax )};
var i=0;
while ( safeWhileCheck() && i <1000 )
console.log("I am number " + i)"
Here the while loop only executes a max of 10 times, so whatever you set the limit to.
This is a spinoff of this thread: Killing a JFrame/Java when process finishes
I know this question has been asked various times here on SO but none of the answers seem to solve my problem. The issue I am having is this: I have a java program that calls a batch file. I need the batch file to finish before the Java program continues. For this I use the waitFor() method, which should wait until the process finishes. However, it doesn't. I found this thread, which suggests that the process waitFor() is actually waiting for is simply cmd.exe, which returns before the actual process does.
Runtime.exec().waitFor() doesn't wait until process is done
That thread recommends using the /wait command, but when I do it makes no difference. My code is very in-depth with several classes that all rely on one another, but here is an attempted SSCCE:
public class BatchFileRun(){
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
list.add("cmd.exe");
list.add("/C");
list.add("Start");
list.add("/wait");
list.add(("C:\\.....\\scripts\\myBatchFile.bat"));
list.add("batchVariable");
String[] commands = new String[list.size()];
commands = list.toArray(commands);
Process p = Runtime.getRuntime().exec(commands);
p.waitFor();
closeWindow();
}
void closeWindow(){
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
System.exit(0);
}
}
The batch file simply operates on the variable passed into it as a parameter (batchVariable). All prior commands should be used to simply run the batch file. The problem is that the closeWindow() method is called before the process in the batch file is finished. Therefore, the Java process that appears in the Windows task manager remains running, even though it should close when closeWindow() is called (if I am using it correctly). I really need said process to close when the process running from the batch file is complete. I have tried different ways of running the batch file (using ProcessBuilder, for example), but no matter what I try I have the same problem.
You can modify the batch file so it only finishes when the process it launches finishes.
I'm using LuaJ to run user-created Lua scripts in Java. However, running a Lua script that never returns causes the Java thread to freeze. This also renders the thread uninterruptible. I run the Lua script with:
JsePlatform.standardGlobals().loadFile("badscript.lua").call();
badscript.lua contains while true do end.
I'd like to be able to automatically terminate scripts which are stuck in unyielding loops and also allow users to manually terminate their Lua scripts while they are running. I've read about debug.sethook and pcall, though I'm not sure how I'd properly use them for my purposes. I've also heard that sandboxing is a better alternative, though that's a bit out of my reach.
This question might also be extended to Java threads alone. I've not found any definitive information on interrupting Java threads stuck in a while (true);.
The online Lua demo was very promising, but it seems the detection and termination of "bad" scripts is done in the CGI script and not Lua. Would I be able to use Java to call a CGI script which in turn calls the Lua script? I'm not sure that would allow users to manually terminate their scripts, though. I lost the link for the Lua demo source code but I have it on hand. This is the magic line:
tee -a $LOG | (ulimit -t 1 ; $LUA demo.lua 2>&1 | head -c 8k)
Can someone point me in the right direction?
Some sources:
Embedded Lua - timing out rogue scripts (e.g. infinite loop) - an example anyone?
Prevent Lua infinite loop
Embedded Lua - timing out rogue scripts (e.g. infinite loop) - an example anyone?
How to interrupt the Thread when it is inside some loop doing long task?
Killing thread after some specified time limit in Java
I struggled with the same issue and after some digging through the debug library's implementation, I created a solution similar to the one proposed by David Lewis, but did so by providing my own DebugLibrary:
package org.luaj.vm2.lib;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
public class CustomDebugLib extends DebugLib {
public boolean interrupted = false;
#Override
public void onInstruction(int pc, Varargs v, int top) {
if (interrupted) {
throw new ScriptInterruptException();
}
super.onInstruction(pc, v, top);
}
public static class ScriptInterruptException extends RuntimeException {}
}
Just execute your script from inside a new thread and set interrupted to true to stop the execution. The exception will be encapsulated as the cause of a LuaError when thrown.
There are problems, but this goes a long way towards answering your question.
The following proof-of-concept demonstrates a basic level of sandboxing and throttling of arbitrary user code. It runs ~250 instructions of poorly crafted 'user input' and then discards the coroutine. You could use a mechanism like the one in this answer to query Java and conditionally yield inside a hook function, instead of yielding every time.
SandboxTest.java:
public static void main(String[] args) {
Globals globals = JsePlatform.debugGlobals();
LuaValue chunk = globals.loadfile("res/test.lua");
chunk.call();
}
res/test.lua:
function sandbox(fn)
-- read script and set the environment
f = loadfile(fn, "t")
debug.setupvalue(f, 1, {print = print})
-- create a coroutine and have it yield every 50 instructions
local co = coroutine.create(f)
debug.sethook(co, coroutine.yield, "", 50)
-- demonstrate stepped execution, 5 'ticks'
for i = 1, 5 do
print("tick")
coroutine.resume(co)
end
end
sandbox("res/badfile.lua")
res/badfile.lua:
while 1 do
print("", "badfile")
end
Unfortunately, while the control flow works as intended, something in the way the 'abandoned' coroutine should get garbage collected is not working correctly. The corresponding LuaThread in Java hangs around forever in a wait loop, keeping the process alive. Details here:
How can I abandon a LuaJ coroutine LuaThread?
I've never used Luaj before, but could you not put your one line
JsePlatform.standardGlobals().loadFile("badscript.lua").call();
Into a new thread of its own, which you can then terminate from the main thread?
This would require you to make some sort of a supervisor thread (class) and pass any started scripts to it to supervise and eventually terminate if they don't terminate on their own.
EDIT: I've not found any way to safely terminate LuaJ's threads without modifying LuaJ itself. The following was what I came up with, though it doesn't work with LuaJ. However, it can be easily modified to do its job in pure Lua. I may be switching to a Python binding for Java since LuaJ threading is so problematic.
--- I came up with the following, but it doesn't work with LuaJ ---
Here is a possible solution. I register a hook with debug.sethook that gets triggered on "count" events (these events occur even in a while true do end). I also pass a custom "ScriptState" Java object I created which contains a boolean flag indicating whether the script should terminate or not. The Java object is queried in the Lua hook which will throw an error to close the script if the flag is set (edit: throwing an error doesn't actually terminate the script). The terminate flag may also be set from inside the Lua script.
If you wish to automatically terminate unyielding infinite loops, it's straightforward enough to implement a timer system which records the last time a call was made to the ScriptState, then automatically terminate the script if sufficient time passes without an API call (edit: this only works if the thread can be interrupted). If you want to kill infinite loops but not interrupt certain blocking operations, you can adjust the ScriptState object to include other state information that allows you to temporarily pause auto-termination, etc.
Here is my interpreter.lua which can be used to call another script and interrupt it if/when necessary. It makes calls to Java methods so it will not run without LuaJ (or some other Lua-Java library) unless it's modified (edit: again, it can be easily modified to work in pure Lua).
function hook_line(e)
if jthread:getDone() then
-- I saw someone else use error(), but an infinite loop still seems to evade it.
-- os.exit() seems to take care of it well.
os.exit()
end
end
function inithook()
-- the hook will run every 100 million instructions.
-- the time it takes for 100 million instructions to occur
-- is based on computer speed and the calling environment
debug.sethook(hook_line, "", 1e8)
local ret = dofile(jLuaScript)
debug.sethook()
return ret
end
args = { ... }
if jthread == nil then
error("jthread object is nil. Please set it in the Java environment.",2)
elseif jLuaScript == nil then
error("jLuaScript not set. Please set it in the Java environment.",2)
else
local x,y = xpcall(inithook, debug.traceback)
end
Here's the ScriptState class that stores the flag and a main() to demonstrate:
public class ScriptState {
private AtomicBoolean isDone = new AtomicBoolean(true);
public boolean getDone() { return isDone.get(); }
public void setDone(boolean v) { isDone.set(v); }
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
System.out.println("J: Lua script started.");
ScriptState s = new ScriptState();
Globals g = JsePlatform.debugGlobals();
g.set("jLuaScript", "res/main.lua");
g.set("jthread", CoerceJavaToLua.coerce(s));
try {
g.loadFile("res/_interpreter.lua").call();
} catch (Exception e) {
System.err.println("There was a Lua error!");
e.printStackTrace();
}
}
};
t.start();
try { t.join(); } catch (Exception e) { System.err.println("Error waiting for thread"); }
System.out.println("J: End main");
}
}
res/main.lua contains the target Lua code to be run. Use environment variables or parameters to pass additional information to the script as usual. Remember to use JsePlatform.debugGlobals() instead of JsePlatform.standardGlobals() if you want to use the debug library in Lua.
EDIT: I just noticed that os.exit() not only terminates the Lua script but also the calling process. It seems to be the equivalent of System.exit(). error() will throw an error but will not cause the Lua script to terminate. I'm trying to find a solution for this now.
Thanks to #Seldon for suggesting the use of custom DebugLib. I implemented a simplified version of that by just checking before every instruction if a predefined amount of time is elapsed. This is of course not super accurate because there is some time between class creation and script execution. Requires no separate threads.
class DebugLibWithTimeout(
timeout: Duration,
) : DebugLib() {
private val timeoutOn = Instant.now() + timeout
override fun onInstruction(pc: Int, v: Varargs, top: Int) {
val timeoutElapsed = Instant.now() > timeoutOn
if (timeoutElapsed)
throw Exception("Timeout")
super.onInstruction(pc, v, top)
}
}
Important note: if you sandbox an untrusted script calling load function on Lua-code and passing a separate environment to it, this will not work. onInstruction() seems to be called only if the function environment is a reference to _G. I dealt with that by stripping everything from _G and then adding whitelisted items back.
-- whitelisted items
local sandbox_globals = {
print = print
}
local original_globals = {}
for key, value in pairs(_G) do
original_globals[key] = value
end
local sandbox_env = _G
-- Remove everything from _G
for key, _ in pairs(sandbox_env) do
sandbox_env[key] = nil
end
-- Add whitelisted items back.
-- Global pairs-function cannot be used now.
for key, value in original_globals.pairs(sandbox_globals) do
sandbox_env[key] = value
end
local function run_user_script(script)
local script_function, message = original_globals.load(script, nil, 't', sandbox_env)
if not script_function then
return false, message
end
return pcall(script_function)
end
I need to find a way to execute mutually dependent tasks.
First task has to download a zip file from remote server.
Second tasks goal is to unzip the file downloaded by the first task.
Third task has to process files extracted from zip.
so, third is dependent on second and second on first task.
Naturally if one of the tasks fails, others shouldn't be executed. Since the first task downloads files from remote server, there should be a mechanism for restarting the task is server is not available.
Tasks have to be executed daily.
Any suggestions, patterns or java API?
Regards!
It seems that you do not want to devide them into tasks, just do like this:
process(unzip(download(uri)));
It depends a bit on external requirements. Is there any user involvement? Monitoring? Alerting?...
The simplest would obviously be just methods that check if the previous has done what it should.
download() downloads file to specified place.
unzip() extracts the file to a specified place if the downloaded file is in place.
process() processes the data if it has been extracted.
A more "formal" way of doing it would be to use a workflow engine. Depending on requirements, you can get some that do everything from fancy UIs, to some that follow formal standardised .XML-definitions of the workflow - and any in between.
http://java-source.net/open-source/workflow-engines
Create one public method to execute the full chain and private methods for the tasks:
public void doIt() {
if (download() == false) {
// download failed
} else if (unzip() == false) {
// unzip failed;
} else (process() == false)
// processing failed
}
}
private boolean download() {/* ... */}
private boolean unzip() {/* ... */}
private boolean process() {/* ... */}
So you have an API that gurantees that all steps are executed in the correct sequence and that a step is only executed if certain conditions are met (the above example just illustrates this pattern)
For daily execution you can use the Quartz Framework.
As the tasks are depending on each other I would recommend to evaluate the error codes or exceptions the tasks are returning. Then just continue if the previous task was successful.
The normal way to perform these tasks is to; call each task in order, and throw an exception when you have a failure which prevents the following tasks being performed. Something like
try {
download();
unzip();
process();
} catch(Exception failed) {
failed.printStackTrace();
}
I think what you are interested in is some kind of transaction definition.
I.e.
- Define TaskA (e.g. download)
- Define TaskB (e.g. unzip)
- Define TaskC (e.g. process)
Assuming that you intention is to have tasks working independent as well, e.g. only download a file (not execute also TaskB, TaskC) you should define Transaction1 composed of TaskA,TaskB,TaskC or Transaction2 composed of only TaskA.
The semantics e.g. concerning Transaction1 that TaskA,TaskB and TaskC should be executed sequentially and all or none could be captured in your transaction definitions.
The definitions can be in xml configuration files and you can use a framework e.g. Quartz for scheduling.
A higher construct shall check for the transactions and execute them as defined.
Dependent tasks execution made easy with Dexecutor
Disclaimer : I am the owner of the library
Basically you need the following pattern
Use Dexecutor.addDependency method
DefaultDexecutor<Integer, Integer> executor = newTaskExecutor();
//Building
executor.addDependency(1, 2);
executor.addDependency(2, 3);
executor.addDependency(3, 4);
executor.addDependency(4, 5);
//Execution
executor.execute(ExecutionConfig.TERMINATING);