This document shall help you to get familiar with quExec by walking through some examples that can easily be reproduced in your environment with the binary distribution of quExec. The sample cases are also used for release tests of quExec and can be applied to check the proper integration of quExec in a new runtime environment (e.g. when changing the JMS broker software).
So far the samples only refer to scenarios where quExec is used by running the net.sourceforge.quexec.OSCommandExecutor at the command-line, even though quExec is primarily intended to be used through its API as a library for Java applications. Nevertheless, the examples show you directly how quExec works and the code used by OSCommandExecutor can be taken as a blueprint for your accessing the quExec API in your own applications.
The following descriptions assume that you use the start script
bin/quExec-test.sh <tag> <arguments to OSCommandExecutor>
to execute the tests. This script only uses dependencies that are bundled with quExec. In particular, it is based on a simple embedded ActiveMQ message broker.
If you want to use your own execution environment (JMS broker, JNDI), you can use the script bin/quExec.sh and setup your environment ($CLASSPATH) to point to all necessary resources. Adapting the start script to your specific environment should also be a very simple task.
bin/quExec-test.sh only works in a Unix environment. Writing a similar Windows script should be easy. However, since quExec is currently developed under Linux and is thus not regularly tested under Windows, such a script is not provided as part of the official quExec release.
The tests assume that the commands are run in the root directory of the quExec distribution.
quExec uses Jakarta Commons Logging and quExec-test.sh makes use of Log4J. The standard log4j.properties file that is bundled with quExec shows some messages (level INFO and above) at the command-line. Debug output that contains valuable information for identifying errors is printed to a file named quexecTAG.log.
The tag part is variable and can be defined through the system property quexec.tag such that multiple (possibly parallel) runs of quExec-test.sh do not write to the same log file. quExec-test.sh takes the tag as first argument.
Of course, you would not need quExec to run a command locally on your computer. However, the following examples provide a gentle introduction to quExec and do not require a JMS environment.
Option -l runs a command locally.
> bin/quExec-test.sh Local -l echo "Hello world!" Starting quExec process with tag 'Local' Hello world! > bin/quExec-test.sh Local -l ls *xml Starting quExec process with tag 'Local' build.xml pom.xml
Option -f connects the I/O of the command executor process to the I/O of the executed native process. The following examples shows how cat is run as native command while input is entered in the terminal and the terminal reprints the same test as output by the cat process. The process is terminated by entering CTRL-d.
> bin/quExec-test.sh Local -l -f cat Starting quExec process with tag 'Local' aaaa aaaa ccccc ccccc
For example, this suffices to start a shell and to execute some commands.
> bin/quExec-test.sh Local -l -f bash Starting quExec process with tag 'Local' ls *xml build.xml pom.xml
Even though it is easy to start a native process from a Java program, it may make sense to use quExec for that. Suppose you need to read the output of the subprocess and have to make sure that your Java program does not hang for too long if the subprocess does not terminate within a reasonable amount of time.
In such a case, running the subprocess through quExec with a suitably defined timeout will solve your problem. quExec takes special care not to block the execution thread when reading from the subprocess and is thus always responsive to interrupts. This helps to shield the Java process from instabie behavior of native subprocesses.
The following example demonstrates this feature at the command-line (even though you would never use it at the command-line since your shell has much provides much more powerful tools for controlling your processes).
> bin/quExec-test.sh Local -l -t 5000 -- bash -c 'while true; do echo foo; sleep 1;done' Starting quExec process with tag 'Local' foo foo foo foo foo Timeout occurred while waiting for OS process to terminate.
The following examples show the actual business of quExec - starting commands remotely via an execution server that is accessed via JMS (or possibly other remote communication techniques) and communicating with the started native processes via JMS.
For this purpose we need an JMS broker. quExec comes with a test-level dependency on ActiveMQ. The starting the test ActiveMQ broker is done as follows.
mvn activemq:run
Then, we need to start the command execution server
> bin/quExec-test.sh Server -s -q dynamicQueues/exec Starting quExec process with tag 'Server' 448 INFO (main) @[server.ProcessExecutorServiceBean] process executor service initialized: launcherTimeout=10000, defaultTimeout=60000
Now we have an execution server running that listens at the dynamically created JMS queue 'exec'.
Let's use the execution server to launch a simple ls command remotely.
> bin/quExec-test.sh Remote -x -- ls -l *xml Starting quExec process with tag 'Remote' 445 INFO (main) @[main.OSCommandExecutor] Running command: '[ls, -l, build.xml, pom.xml]' HANDLE: procInQueue='dynamicQueues/quexec0', procOutQueue='dynamicQueues/quexec1
The execution server has executed the ls-command and has connected the standard input and output of the ls-process to the dynamically created JMS queues quexec0 and quexec1. We will now connect to these queues and retrieve the output of the ls-command.
> bin/quExec-test.sh Remote -c -i dynamicQueues/quexec0 -o dynamicQueues/quexec1 Starting quExec process with tag 'Remote' -rw-r--r-- 1 schickin users 1175 25. Okt 22:50 build.xml -rw-r--r-- 1 schickin users 11214 26. Okt 22:11 pom.xml
Since it is common to execute a command and then to connect to its input and output, the options -x and -c can be combined.
> bin/quExec-test.sh Remote -x -c echo 'Hello world!' Starting quExec process with tag 'Remote' 536 INFO (main) @[main.OSCommandExecutor] Running command: '[echo, Hello world!]' 953 INFO (main) @[main.OSCommandExecutor] Connecting to remote process via JMS Hello world!
Timeouts can also be specified for remotely executed commands.
> bin/quExec-test.sh Remote -x -c -t 2000 ping www.google.com Starting quExec process with tag 'Remote' 453 INFO (main) @[main.OSCommandExecutor] Running command: '[ping, www.google.com]' 11657 INFO (main) @[main.OSCommandExecutor] Connecting to remote process via JMS PING www.l.google.com (74.125.39.104) 56(84) bytes of data. 64 bytes from fx-in-f104.1e100.net (74.125.39.104): icmp_seq=1 ttl=56 time=74.1 ms 64 bytes from fx-in-f104.1e100.net (74.125.39.104): icmp_seq=2 ttl=56 time=76.6 ms
Local input can be forwarded to the remote process through option -f.
> bin/quExec-test.sh Remote -x -c -f bash Starting quExec process with tag 'Remote' 453 INFO (main) @[main.OSCommandExecutor] Running command: '[bash]' 991 INFO (main) @[main.OSCommandExecutor] Connecting to remote process via JMS ls *xml build.xml pom.xml exit