Launch commands without using fork from the JVM.
authorgumartinm <gu.martinm@gmail.com>
Wed, 18 Jan 2012 01:19:01 +0000 (02:19 +0100)
committergumartinm <gu.martinm@gmail.com>
Wed, 18 Jan 2012 01:19:01 +0000 (02:19 +0100)
Sometimes you may receive a nice OutofMemory exception because of the overcommitting memory allocation,
although you could have still enough memory.
Issues related to fork and virtual memory.
See: http://developers.sun.com/solaris/articles/subprocess/subprocess.html

JavaFork/Daemon/README.txt [new file with mode: 0644]
JavaFork/Daemon/javafork [new file with mode: 0755]
JavaFork/Daemon/javafork.c [new file with mode: 0644]
JavaFork/Daemon/javafork.h [new file with mode: 0644]
JavaFork/JavaExample/javafork-example/pom.xml [new file with mode: 0644]
JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkDaemon.java [new file with mode: 0644]
JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkParser.java [new file with mode: 0644]
JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/LauncherProcesses.java [new file with mode: 0644]
JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/MainJavaFork.java [new file with mode: 0644]
JavaFork/JavaExample/pom.xml [new file with mode: 0644]

diff --git a/JavaFork/Daemon/README.txt b/JavaFork/Daemon/README.txt
new file mode 100644 (file)
index 0000000..604f093
--- /dev/null
@@ -0,0 +1,3 @@
+Launch:
+
+javafork IPADDRESS TCP_PORT MAX_LISTEN
diff --git a/JavaFork/Daemon/javafork b/JavaFork/Daemon/javafork
new file mode 100755 (executable)
index 0000000..6ad9212
Binary files /dev/null and b/JavaFork/Daemon/javafork differ
diff --git a/JavaFork/Daemon/javafork.c b/JavaFork/Daemon/javafork.c
new file mode 100644 (file)
index 0000000..6d78c0c
--- /dev/null
@@ -0,0 +1,347 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+#include <signal.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <strings.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/wait.h>
+#include <sys/poll.h>
+#include <string.h>
+#include "javafork.h"
+
+
+int main (int argc, char *argv[]) {
+    pid_t pid;
+
+       if ((pid = fork()) == -1) {
+               perror("fork: ");
+       return -1;
+       }
+       else {
+               if (pid == 0) {
+                       /*child process*/
+                       main_child(argc, argv);
+               }
+       }
+
+       return 0;
+}
+
+
+int main_child (int argc, char *argv[]) {
+       struct protoent *protocol;
+       struct sockaddr_in addr_server;
+       struct sockaddr_in  addr_client;
+       int sockfd;
+    int sockclient;
+    pthread_t idThread;
+       int clilen;
+
+       
+       daemonize(argv[0], LOG_SYSLOG, LOG_PID);
+    setsid();
+
+       signal(SIGPIPE,SIG_IGN);
+
+       /*Retrieve protocol number from /etc/protocols file */
+    protocol=getprotobyname("tcp");
+       if (protocol == NULL) {
+               syslog(LOG_ERR, "cannot map \"tcp\" to protocol number");
+       exit (1);
+       }
+
+       bzero((char*) &addr_server, sizeof(addr_server));
+       addr_server.sin_family = AF_INET;
+    if (inet_pton(AF_INET, argv[1], &addr_server.sin_addr.s_addr) <= 0)
+        syslog (LOG_ERR, "error inet_pton");
+
+       addr_server.sin_port = htons(atol(argv[2]));
+
+       if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        syslog (LOG_ERR, "socket creation failed");
+               exit(1);
+       }
+
+       if (bind(sockfd, (struct sockaddr *) &addr_server, sizeof(addr_server)) < 0) {
+               syslog (LOG_ERR, "socket bind failed");
+        exit(1);
+       }
+
+       if (listen (sockfd, atoi(argv[3])) < 0 ) {
+               syslog (LOG_ERR, "socket listen failed");
+        exit(1);
+       }       
+
+       while(1) {
+               clilen =  sizeof(addr_client);
+               if ((sockclient = accept (sockfd, (struct sockaddr *) &addr_client, &clilen)) < 0) {
+                       syslog (LOG_ERR, "socket accept failed");
+               exit(1);
+               }
+               if (pthread_create (&idThread, NULL, serverThread, (void *)sockclient) != 0 ) {
+                       syslog (LOG_ERR, "thread creation failed");
+               }       
+       }
+}
+
+
+int daemonize(const char *pname, int facility, int option) {
+       int fd;
+
+       if ( (fd = open( "/dev/tty", O_RDWR, 0) ) == -1) {
+       /*We already have no tty control*/
+       close(fd);
+       return 0;
+       }
+
+    /*Sending messages to log*/
+    openlog(pname, option, facility);
+
+       ioctl(fd, TIOCNOTTY, (caddr_t)0);
+       close(fd);
+
+       if((fd = open( "/dev/null", O_RDWR, 0) ) == -1) {
+       close(fd);
+       return 0;
+       }
+       dup2(fd,0);
+       dup2(fd,1);
+       dup2(fd,2);
+       close(fd);
+
+       return 0;
+}
+
+void *serverThread (void * arg) {
+       int sockclient;
+    int n;
+    char buf[512];
+
+       sockclient = (int) arg;
+       pthread_detach(pthread_self());
+
+       n = recv(sockclient, buf, sizeof(buf), 0);
+       if(n > 0){
+       buf[n] = '\0';
+       fork_system(sockclient, buf);
+       }
+
+       close(sockclient);
+       
+       pthread_exit(0);
+}
+
+
+int fork_system(int socket, char *command) {
+       int pid;
+    int pfdOUT[2];
+    int pfdERR[2];
+       char buf[2000];
+    char string[100];
+       struct pollfd polls[2];
+       int returnstatus;
+       int n;
+
+       sem_t * semaphore;
+       /*Required variables in order to share memory between processes*/
+       key_t keyvalue;
+       int idreturnst;
+       int *returnst;
+
+       if (pipe(pfdOUT) == -1) {
+               syslog (LOG_ERR, "pipe for stdout failed");
+               close(pfdOUT[0]);
+        close(pfdOUT[1]);
+       return -1;
+       }
+       if (pipe(pfdERR) == -1) {
+               syslog (LOG_ERR, "pipe for stderr failed");
+       close(pfdOUT[0]);
+       close(pfdOUT[1]);
+               close(pfdERR[0]);
+        close(pfdERR[1]);
+       return -1;
+       }
+
+       if ((semaphore = sem_open("javaforksem", O_CREAT, 0644, 1)) == SEM_FAILED) {
+               syslog (LOG_ERR, "semaphore open failed");
+        close(pfdOUT[0]);
+        close(pfdOUT[1]);
+        close(pfdERR[0]);
+        close(pfdERR[1]);
+               if (sem_close(semaphore) <0 ) {
+                       syslog (LOG_ERR, "semaphore open failed and close failed");
+               }
+               if (sem_unlink("javaforksem") < 0) {
+                       syslog (LOG_ERR, "semaphore open failed and unlink failed");
+               }
+               return -1;
+       }
+
+       if (sem_init(semaphore, 1, 1) < 0) {
+               syslog (LOG_ERR, "semaphore initialization failed");
+               close(pfdOUT[0]);
+        close(pfdOUT[1]);
+        close(pfdERR[0]);
+        close(pfdERR[1]);
+        if (sem_close(semaphore) <0 ) {
+            syslog (LOG_ERR, "semaphore open failed and close failed");
+        }
+        if (sem_unlink("javaforksem") < 0) {
+            syslog (LOG_ERR, "semaphore open failed and unlink failed");
+        }
+       return -1;
+       }
+       
+       if (sem_wait(semaphore) < 0) {
+               syslog (LOG_ERR, "semaphore wait failed");
+       }
+
+       /*Allocate shared memory*/
+    keyvalue=ftok("/bin/ls", SHAREMEMKEY);  /*the /bin/ls must exist otherwise this does not work... */
+       if (keyvalue == -1) {
+               syslog (LOG_ERR, "ftok failed");
+               /*TODO: Close again pipes and semaphore.*/
+               return -1;
+       }
+       /*Attach shared memory*/
+       idreturnst=shmget(keyvalue,sizeof(int), 0660 | IPC_CREAT);
+    if (idreturnst == -1) {
+               syslog (LOG_ERR, "shmget failed");
+               /*TODO: Close again pipes and semaphore.*/
+               return -1;
+       }
+       returnst = (int *)shmat(idreturnst, (void *)0, 0);
+       if ((*returnst)== -1) {
+               syslog (LOG_ERR, "shmat failed");
+               /*TODO: Close again pipes and semaphore.*/
+               return -1;
+       }
+
+       /*By default*/
+       (*returnst) = 0;
+
+       if ((pid=fork()) == -1) {
+       perror("fork: ");
+               close(pfdOUT[0]);
+        close(pfdOUT[1]);
+        close(pfdERR[0]);
+        close(pfdERR[1]);
+               if (sem_close(semaphore) <0 ) {
+            syslog (LOG_ERR, "semaphore open failed and close failed");
+        }
+        if (sem_unlink("javaforksem") < 0) {
+            syslog (LOG_ERR, "semaphore open failed and unlink failed");
+        }
+       return -1;
+       }
+       else {
+               /*Child process*/
+               if (pid == 0) {
+                       if (dup2(pfdOUT[1],1) < 0) {    
+                               syslog (LOG_ERR, "child: dup2 pfdOUT failed");  
+                               exit(-1);
+                       }
+                       if (dup2(pfdERR[1],2) < 0) {    
+                syslog (LOG_ERR, "child: dup2 pfdERR failed");
+                               exit(-1);
+            }
+                       if (sem_wait(semaphore) < 0) {
+                       syslog (LOG_ERR, "child: semaphore wait failed");
+                   }
+                       returnstatus=system(command);
+                       if (WIFEXITED(returnstatus) == 1) {
+                               (*returnst) = WEXITSTATUS(returnstatus);
+                       }
+                       else {
+                               (*returnst) = -1;
+                       }
+                       exit(0);
+               }
+               else {
+                       /*Parent process*/
+                       polls[0].fd=pfdOUT[0];
+               polls[1].fd=pfdERR[0];
+               polls[0].events=POLLIN;
+               polls[1].events=POLLIN;
+               sprintf(string,"<?xml version=\"1.0\"?>");
+               send(socket,string,strlen(string),0);
+               sprintf(string,"<salida>");
+               send(socket,string,strlen(string),0);
+                       /*The child will be woken up*/
+                       if (sem_post(semaphore) < 0 ) {
+                               syslog (LOG_ERR, "error waiking up child process");
+                               /*TODO: exit closing the descriptors*/
+                       }
+                       while(1){
+                               if(poll(polls,2,100)){
+                               if(polls[0].revents&&POLLIN) {
+                               bzero(buf,2000);
+                                               n=read(pfdOUT[0],buf,1990);
+                                               sprintf(string,"<out><![CDATA[");
+                               send(socket,string,strlen(string),0);
+                                       send(socket,buf,n,0);
+                               sprintf(string,"]]></out>");
+                                       send(socket,string,strlen(string),0);
+                               } 
+                                       if(polls[1].revents&&POLLIN) {
+                                               bzero(buf,2000);
+                               n=read(pfdERR[0],buf,1990);
+                                               sprintf(string,"<error><![CDATA[");
+                                   send(socket,string,strlen(string),0);
+                               send(socket,buf,n,0);
+                               sprintf(string,"]]></error>");
+                               send(socket,string,strlen(string),0);
+                               }
+                                       if(!polls[0].revents&&POLLIN && !polls[1].revents&&POLLIN) {
+                                               syslog (LOG_ERR, "Error polling pipes");
+                                       break;
+                               }
+                               }
+                               else {
+                                       /*When timeout*/
+                                       if(waitpid(pid,NULL,WNOHANG)) {
+                                               /*Child is dead, we can finish the connection*/
+                                               break;
+                                       }
+                                       /*The child process is not dead, keep polling more data from stdout or stderr streams*/
+                               }
+                       }
+                       
+                       /*We reach this code when the child process is dead or because of an error polling pipes*/
+                       /*In the second case the result stored in *returnst could be wrong, anyway there was*/
+                       /*an error so, the result is unpredictable.*/
+                       /*TODO: if error while polling pipes do not reach this code an exit with -1*/
+                       sprintf(string,"<ret><![CDATA[%d]]></ret>", (*returnst));
+               send(socket,string,strlen(string),0);
+               sprintf(string,"</salida>");
+               send(socket,string,strlen(string),0);
+
+                       close(pfdOUT[0]);
+                       close(pfdOUT[1]);
+                       close(pfdERR[0]);
+                       close(pfdERR[1]);
+                       if (sem_close(semaphore) <0 ) {
+               syslog (LOG_ERR, "semaphore close failed");
+               }
+               if (sem_unlink("javaforksem") < 0) {
+               syslog (LOG_ERR, "semaphore unlink failed");
+               }
+       
+                       shmdt ((int *)returnst);
+               shmctl (idreturnst, IPC_RMID, (struct shmid_ds *)NULL);
+               }
+       }
+
+       return 0;
+}
diff --git a/JavaFork/Daemon/javafork.h b/JavaFork/Daemon/javafork.h
new file mode 100644 (file)
index 0000000..d6321a0
--- /dev/null
@@ -0,0 +1,7 @@
+/*System V IPC key*/
+#define SHAREMEMKEY 1
+
+void *serverThread (void *arg);
+int daemonize(const char *pname, int facility, int option);
+int main_child (int argc, char *argv[]);
+int fork_system(int socket, char *command);
diff --git a/JavaFork/JavaExample/javafork-example/pom.xml b/JavaFork/JavaExample/javafork-example/pom.xml
new file mode 100644 (file)
index 0000000..f24711c
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+       xmlns="http://maven.apache.org/POM/4.0.0" 
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+       
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <artifactId>javafork</artifactId>
+               <groupId>de.fork.java</groupId>
+               <version>2.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>javafork-example</artifactId>
+       <name>javafork-example</name>
+       <url>http://gumartinm.name</url>
+
+       <dependencies>
+               
+       </dependencies>
+</project>
diff --git a/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkDaemon.java b/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkDaemon.java
new file mode 100644 (file)
index 0000000..074318f
--- /dev/null
@@ -0,0 +1,166 @@
+package de.fork.java;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>
+ * With this class we can run processes using the intended daemon which is 
+ * waiting for TCP connections in a specified port.
+ * </p>
+ * <p>
+ * Receiving the results in a XML format from the daemon where we can find three
+ * kinds of different fields: error, out and ret. Every field is related to the
+ * stderr, stdout and return code respectively. <br>
+ * </p>
+ * <p>
+ * <pre>
+ * <b>Example, stream received from daemon:</b>
+ * {@code
+ * <?xml version="1.0"?><salida><error><![CDATA[ls: no se puede acceder a bbb: No existe el fichero o el directorio
+ * ls: no se puede acceder a aaa: No existe el fichero o el directorio
+ * ls: no se puede acceder a dddd: No existe el fichero o el directorio
+ * ]]></error><ret><![CDATA[2]]></ret></salida>
+ * }
+ * </pre>
+ * </p>
+ * <p>
+ * This class has to process the above stream and it offers two methods wich can be used
+ * to retrieve the stderr and stdout in a right way without having to know about the XML stream
+ * received from the daemon. The user does not have to know about how the daemon sends the data,
+ * he or she will work directly with the strings related to each stream. Those methods 
+ * are {@link ForkDaemon#getStdout()} and {@link ForkDaemon#getStderr()} The return code from the command 
+ * executed by the daemon can be retrieved as a return parameter from the method 
+ * {@link ForkDaemon#exec(String, String, int)}
+ * </p>
+ * <p>
+ * Instances of this class are mutable. To use them concurrently, clients must surround each
+ * method invocation (or invocation sequence) with external synchronization of the clients choosing.
+ * </p>
+ */
+public class ForkDaemon {
+       private final ForkParser handler;
+       
+       
+       /**
+        * Simple constructor.
+        * Nothing special here.
+        * 
+        */
+       public ForkDaemon () {
+               handler = new ForkParser();
+       }
+       
+       
+       /**
+        * This method sends commands to the daemon.
+        * <br>
+        * It uses a TCP connection in order to send commands to the daemon and receive
+        * the results related to that command. 
+        * <br>
+        * The mehtod retrieves the stdout, stderr and the return code of that command. 
+        * 
+     * <p> The host name can either be a machine name, such as
+     * "<code>java.sun.com</code>", or a textual representation of its
+     * IP address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     * </p>
+     * <p> For <code>host</code> specified in literal IPv6 address,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also
+     * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+        * </p>
+        * @param  command the command to be executed by the daemon.
+        * @param  host the specified host.
+        * @param  port the TCP port where the daemon accepts connections.
+        * 
+        * @return the executed command's return code.
+        * 
+     * @throws UnknownHostException  if no IP address for the
+     * <code>host</code> could be found, or if a scope_id was specified
+     * @throws SecurityException if a security manager exists
+     * and its checkConnect method doesn't allow the operation
+     * @throws IOException  if an I/O error occurs when creating the socket.
+        * @throws SAXException 
+        * @throws FactoryConfigurationError if the implementation is not available or cannot be instantiated.
+     * @throws SAXException If any SAX errors occur during processing.
+        * @throws ParserConfigurationException 
+        */
+       public int exec(final String command, String host, int port) 
+                       throws UnknownHostException, IOException, SAXException, ParserConfigurationException  {
+               final SAXParserFactory spf = SAXParserFactory.newInstance();
+               final SAXParser saxParser = spf.newSAXParser(); 
+               PrintWriter out = null;
+               
+               final Socket socket = new Socket(InetAddress.getByName(host), port);
+               try {
+                       out = new PrintWriter(socket.getOutputStream(), true);
+                       out.println(command);
+                       saxParser.parse(socket.getInputStream(), handler);
+               } 
+               finally {
+                       if (out != null) {
+                               out.close();
+                       }
+                       socket.close();
+               }
+               
+               //Just for testing the parser by using a file instead of a TCP connection.
+               //InputSource input = new InputSource(new FileReader("/tmp/xmlfromdaemon.xml"));
+               //saxParser.parse(input, handler);
+               
+               return new Integer(handler.getReturnValue()).intValue();
+       }
+
+       
+       /**
+        * Retrieve the standard output.
+        * 
+        * @see {@link ForkDaemon#getStderr()}
+        * @return stdout
+        */
+       public String getStdout() {
+               return handler.getStdout();
+       }
+       
+       
+       /**
+        * <p>
+        * Retrieve the standard error.
+        * </p>
+        * <p>
+        * <pre>
+        * <b>Example, stream received from daemon:</b>
+        * {@code
+        * <?xml version="1.0"?><salida><error><![CDATA[ls: no se puede acceder a bbb: No existe el fichero o el directorio
+        * ls: no se puede acceder a aaa: No existe el fichero o el directorio
+        * ls: no se puede acceder a dddd: No existe el fichero o el directorio
+        * ]]></error><ret><![CDATA[2]]></ret></salida>
+        * }
+        * </pre>
+        * </p>
+        * <p>
+        * <pre>
+        * <b>From that example with this method we are going to obtain this return parameter:</b>
+        * {@code
+        * ls: no se puede acceder a bbb: No existe el fichero o el directorio
+        * ls: no se puede acceder a aaa: No existe el fichero o el directorio
+        * ls: no se puede acceder a dddd: No existe el fichero o el directorio
+        * }
+        * </pre>
+        * </p>
+        * @return stderr
+        */
+       public String getStderr() {
+               return handler.getStderr();
+       }
+}
\ No newline at end of file
diff --git a/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkParser.java b/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/ForkParser.java
new file mode 100644 (file)
index 0000000..c20ba15
--- /dev/null
@@ -0,0 +1,141 @@
+package de.fork.java;
+
+import org.apache.log4j.Logger;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.ext.DefaultHandler2;
+
+/**
+ * <p>
+ * Class intended to parse the XML stream received from the daemon which is
+ * waiting to run commands. These commands are sent by the method 
+ * {@link es.dia.pos.n2a.util.os.unix.ForkDaemon#exec(String, String, int)} 
+ * </p>
+ * <p>
+ * After processing one command the daemon sends a XML stream with the stderr,
+ * stdout and return status of that command. With this class we extract those values
+ * and we can retrieve them using the methods {@link #getStderr() }, {@link #getStdout()}
+ * and {@link #getReturnValue()}
+ * </p>
+ * <p>
+ * <pre>
+ * <b>Example, stream received from daemon:</b>
+ * {@code
+ * <?xml version="1.0"?><salida><error><![CDATA[ls: no se puede acceder a bbb: No existe el fichero o el directorio
+ * ls: no se puede acceder a aaa: No existe el fichero o el directorio
+ * ls: no se puede acceder a dddd: No existe el fichero o el directorio
+ * ]]></error><ret><![CDATA[2]]></ret></salida>
+ * }
+ * </pre>
+ * </p>
+ */
+public class ForkParser extends DefaultHandler2{
+       private static final Logger logger = Logger.getLogger(ForkParser.class);
+    private StringBuffer accumulator = new StringBuffer();
+       private String stderr = new String();
+       private String stdout = new String();
+       private String returnCode = new String();
+
+       
+       @Override
+       public void endElement (String uri, String localName, String qName) {
+               if (qName.equals("error")) {
+                       // After </error>, we've got the stderror
+                       stderr = stderr + accumulator.toString();
+               } else if (qName.equals("out")) {
+                       // After </out>, we've got the stdout
+                       stdout = stdout + accumulator.toString();
+               } else if (qName.equals("ret")) {
+                       returnCode = returnCode + accumulator.toString();
+               }
+       }
+
+       
+       @Override
+       public void endDocument () throws SAXException
+       {
+               if (stderr.length() != 0) {
+                       String lastStderr = stderr.replaceFirst("\\\n$", "");
+                       stderr = lastStderr;
+               }
+               else {
+                       stderr = null;
+               }
+               if (stdout.length() != 0) {
+                       String lastStdout = stdout.replaceFirst("\\\n$", "");
+                       stdout = lastStdout;
+               }
+               else {
+                       stdout = null;
+               }
+       }
+       
+       /**
+        * Retrieve the standard error.
+        * 
+        * <pre>
+        * <b>From the above example with this method we are going to obtain this return parameter:</b>
+        * {@code
+        * ls: no se puede acceder a bbb: No existe el fichero o el directorio
+        * ls: no se puede acceder a aaa: No existe el fichero o el directorio
+        * ls: no se puede acceder a dddd: No existe el fichero o el directorio
+        * }
+        * </pre>
+        * 
+        * @return stderr
+        */
+       public String getStderr() {
+               return stderr;
+               
+       }
+       
+       
+       /**
+        * Retrieve the standard output.
+        * 
+        * @see {@link ForkParser#getStderr()}
+        * @return stdout
+        */
+       public String getStdout() {
+               return stdout;
+       }
+       
+       
+       /**
+        * Retrieve the return code from the executed command.
+        * 
+        * @return return status, usually <code>0<code> means the command went OK.
+        */
+       public String getReturnValue() {
+               return returnCode;
+       }
+       
+       
+       @Override
+       public void startElement (String uri, String localName, String qName, Attributes attributes) {
+               accumulator.setLength(0);
+       }
+       
+       
+       @Override
+       public void characters(char[] buffer, int start, int length) {
+           accumulator.append(buffer, start, length);
+       }
+       
+       @Override
+       public void warning(SAXParseException exception) {
+               logger.error("WARNING line:" + exception.getLineNumber(), exception);
+       }
+       
+       @Override
+       public void error(SAXParseException exception) {
+               logger.error("ERROR line:" + exception.getLineNumber(), exception);
+       }
+       
+       @Override
+       public void fatalError(SAXParseException exception) throws SAXException {
+               logger.error("FATAL ERROR line:" + exception.getLineNumber(), exception);
+               throw (exception);
+       }
+}
\ No newline at end of file
diff --git a/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/LauncherProcesses.java b/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/LauncherProcesses.java
new file mode 100644 (file)
index 0000000..0f93fe2
--- /dev/null
@@ -0,0 +1,275 @@
+package de.fork.java;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.UnknownHostException;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.log4j.Logger;
+import org.xml.sax.SAXException;
+
+
+public class LauncherProcesses {
+
+       private static final Logger logger = Logger.getLogger(LauncherProcesses.class);
+
+       // Exit process status
+       private static final int STATUS_ERR = -1;
+
+       private static final int DEFAULT_PORT = 5193;
+       private static final String DEFAULT_HOST = "127.0.0.1";
+       
+       /**
+        * Run a process.
+        * 
+        * @param command system command to be executed.
+        * 
+        * @return return code.
+        */
+       public static int exec(final String command) throws IOException, InterruptedException {
+
+               return exec(command, null, null);
+       }
+
+       /**
+        * Run a process.
+        * 
+        * @param command system command to execute.
+        * @param standarOutPut if not null, the standard output is redirected to this parameter.
+        *            
+        * @return return code.            
+        */
+       public static int exec(final String command, final PrintStream standarOutPut) throws IOException, InterruptedException {
+
+               return exec(command, standarOutPut, null);
+       }
+
+       
+       /**
+        * Run a process.
+        * 
+        * @param command system command to be executed.
+        * @param standarOutPut if not null, the standard output is redirected to this parameter.
+        * @param errorOutPut if not null, the error output is redirected to this parameter.
+        * 
+        * @return return code from the executed system command.     
+        */
+       public static int exec(final String command, final PrintStream standarOutPut, final PrintStream errorOutPut) throws IOException, InterruptedException {
+
+               return exec(command, standarOutPut, errorOutPut, DEFAULT_HOST, DEFAULT_PORT);
+       }
+
+       /**
+        * Run a process.
+        * 
+        * @param command system command to be executed.
+        * @param aLogger send the information to log.
+        */
+       public static int exec(final String command, final Logger aLogger) throws IOException, InterruptedException {
+
+               //calling private method to handle logger input/ouput in a common method
+               return execHandlingLogger(command, aLogger, DEFAULT_HOST, DEFAULT_PORT);
+       }
+       
+       
+       /**
+        * @param commandAndArguments String array containing system command and its 
+        * arguments to be executed.<br>
+        * <b>For example:</b> 
+        * <pre>
+        * commandAndArguments[0]="ls";
+        * commandAndArguments[1]="-lr";
+        * </pre>
+        * @param aLogger
+        * 
+        * @return return code from the executed system command.
+        * 
+        * @throws IOException
+        * @throws InterruptedException
+        */
+       public static int exec(final String[] commandAndArguments, final Logger aLogger) throws IOException, InterruptedException {
+               String wholeCommand="";
+               
+               for(String argument : commandAndArguments) {
+                       wholeCommand = wholeCommand + " " + argument;
+               }
+               
+               //calling private method to handle logger input/ouput in a common method
+               return execHandlingLogger(wholeCommand, aLogger, DEFAULT_HOST, DEFAULT_PORT);
+       }
+       
+       
+       /**
+        * 
+        * @param command system command to be executed.
+        * @param standarOutPut the stdout stream from that command as a <code>PrintStream</code>
+        * @param errorOutPut the stderr stream from that command as a <code>PrintStream</code>
+        * @param host the specified host.
+        * @param port the TCP port where the daemon accepts connections.
+        * 
+        * <p> The host name can either be a machine name, such as
+     * "<code>java.sun.com</code>", or a textual representation of its
+     * IP address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     * </p>
+     * <p> For <code>host</code> specified in literal IPv6 address,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also
+     * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+        * </p>
+        * 
+        * @return the executed command's return code.
+        * 
+        * @throws UnknownHostException
+        * @throws IOException
+        */
+       public static int exec(final String command, final PrintStream standarOutPut, 
+                       final PrintStream errorOutPut, final String host, int port) throws IOException {
+               int exitStatus = LauncherProcesses.STATUS_ERR;
+
+               ForkDaemon process = new ForkDaemon();
+               try {
+                       exitStatus = process.exec(command, host, port);
+               } catch (SAXException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       //[§EJ Item 61] Do not blame me.
+                       throw new IOException(e);
+               } catch (ParserConfigurationException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       //[§EJ Item 61] Do not blame me.
+                       throw new IOException(e);
+               }
+               
+               if (standarOutPut != null) {
+                       if (process.getStdout() != null) {
+                               standarOutPut.println(process.getStdout());
+                       }
+               }
+
+               if (errorOutPut != null) {
+                       if (process.getStderr() != null) {
+                               errorOutPut.println(process.getStderr());
+                       }
+               }
+
+               return exitStatus;
+       }
+       
+       
+       /**
+        * 
+        * @param command system command to be executed.
+        * @param aLogger
+        * @param host the specified host.
+        * @param port the TCP port where the daemon accepts connections.
+        * 
+        * @return the executed command's return code.
+        * 
+        * @throws IOException
+        * @throws InterruptedException
+        */
+       private static int execHandlingLogger(final String command, final Logger aLogger, 
+                               final String host, int port) throws IOException, InterruptedException {
+               int exitStatus = LauncherProcesses.STATUS_ERR;
+
+               ForkDaemon process = new ForkDaemon();
+               try {
+                       exitStatus = process.exec(command, host, port);
+               } catch (SAXException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       // Do not blame me.
+                       throw new IOException(e);
+               } catch (ParserConfigurationException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       // Do not blame me.
+                       throw new IOException(e);
+               }
+               
+               if (process.getStdout() != null) {
+                       aLogger.info(process.getStdout());
+               }
+               if (process.getStderr() != null) {
+                       aLogger.error(process.getStderr());
+               }
+
+               return exitStatus;
+       }
+       
+       
+       /**
+        * @param command command and its arguments to be executed.<br>
+        * <b>For example:</b> 
+        * <pre>
+        * commandAndArguments[0]="ls";
+        * commandAndArguments[1]="-lr";
+        * </pre>
+        * @param aLogger send information to log
+        * 
+        * @return the executed command's return code.
+        * 
+        * @throws IOException
+        * @throws InterruptedException
+        */
+       public static InputStream execStream (final String [] command, final Logger aLogger) 
+                                                                                                       throws IOException, InterruptedException {
+               int exitStatus = LauncherProcesses.STATUS_ERR;
+               
+               InputStream stdInput = null;
+       
+               String wholeCommand="";
+               for(String argument : command) {
+                       wholeCommand = wholeCommand + " " + argument;
+               }
+               
+               ForkDaemon process = new ForkDaemon();
+               try {
+                       exitStatus = process.exec(wholeCommand, DEFAULT_HOST, DEFAULT_PORT);
+               } catch (SAXException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       throw new IOException(e);
+               } catch (ParserConfigurationException e) {
+                       // This is not a crazy thing, we are trying to insert this new method without
+                       // breaking the old methods which did not throw SAXException or ParserConfigurationException
+                       throw new IOException(e);
+               }
+               
+               if(exitStatus == 0) {
+                       stdInput = new ByteArrayInputStream(process.getStdout().getBytes("UTF-8"));
+               }
+               else {
+                       aLogger.error(process.getStderr());
+               }
+               
+
+               return stdInput;
+       }
+       
+       /**
+        * <p>The <em>command</em> is lunched from <em>location</em>
+        * <li>#>cd <em>location</em></li>
+        * <li>#location> <em>command</em></li></p>
+        * 
+        * @param command the command to be executed by the daemon.
+        * @param location
+        * 
+        * @return the executed command's return code. <br>
+        * Usually <code>0</code> if execution is OK, otherwise <code>!=0</code> 
+        * 
+        * @throws IOException
+        * @throws InterruptedException
+        */
+       public static int execInLocation (final String command, final String location) throws IOException, InterruptedException {
+               int exitStatus = LauncherProcesses.STATUS_ERR;
+               final String wholeCommand = "cd " + location + " && " + command;
+               
+               exitStatus =  exec(wholeCommand, null, null, DEFAULT_HOST, DEFAULT_PORT);
+               return exitStatus;
+       }
+}
\ No newline at end of file
diff --git a/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/MainJavaFork.java b/JavaFork/JavaExample/javafork-example/src/main/java/de/fork/java/MainJavaFork.java
new file mode 100644 (file)
index 0000000..bed6b6a
--- /dev/null
@@ -0,0 +1,35 @@
+package de.fork.java;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintStream;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.SAXException;
+
+
+public class MainJavaFork  {
+
+       /**
+        * @param args
+        * @throws SAXException 
+        * @throws ParserConfigurationException 
+        * @throws FileNotFoundException 
+        */
+       public static void main(String[] args) 
+                       throws ParserConfigurationException, SAXException, FileNotFoundException, IOException {
+               
+               final ByteArrayOutputStream stdoutByteOut = new ByteArrayOutputStream();
+               final PrintStream stdout = new PrintStream(stdoutByteOut);
+               final String command = "ls -lah; ls -lah bbb aaa ccc; ls -lah";
+               final ByteArrayOutputStream stderrByteOut = new ByteArrayOutputStream();
+               final PrintStream stderr = new PrintStream(stderrByteOut);
+               int result;
+               
+               result = LauncherProcesses.exec(command,stdout, stderr, "127.0.0.1", 5193);
+               System.out.println(result);
+               System.out.println("Stdout: " +  stdoutByteOut.toString());
+               System.out.println("Stderr: " +  stderrByteOut.toString());
+       }
+
+}
\ No newline at end of file
diff --git a/JavaFork/JavaExample/pom.xml b/JavaFork/JavaExample/pom.xml
new file mode 100644 (file)
index 0000000..aaf5867
--- /dev/null
@@ -0,0 +1,663 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" 
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>de.fork.java</groupId>
+       <artifactId>javafork</artifactId>
+       <version>2.0-SNAPSHOT</version>
+       <name>javafork</name>
+       <url>http://www.gumartinm.name</url>
+       <description>Java fork with Linux daemon</description>
+       <organization>
+               <name>MyOrganization</name>
+               <url>http://www.gumartinm.name</url>
+       </organization>
+       <packaging>pom</packaging>
+       <issueManagement>
+               <system>trac</system>
+               <url>http://gumartinm.name/trac</url>
+       </issueManagement>
+       <ciManagement>
+               <system>jenkins</system>
+               <url>http://gumartinm.name//jenkins/</url>
+       </ciManagement>
+       <scm>
+               <developerConnection>scm:svn:http://gumartinm.name</developerConnection>
+               <url>http://gumartinm.name</url>
+       </scm>
+       <dependencies>
+               <dependency>
+                       <groupId>com.sun.jdmk</groupId>
+                       <artifactId>jmxtools</artifactId>
+                       <version>1.2.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>javax.activation</groupId>
+                       <artifactId>activation</artifactId>
+                       <version>1.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>log4j</groupId>
+                       <artifactId>log4j</artifactId>
+                       <version>1.2.15</version>
+                       <exclusions>
+                               <exclusion>
+                                       <groupId>com.sun.jdmk</groupId>
+                                       <artifactId>jmxtools</artifactId>
+                               </exclusion>
+                               <exclusion>
+                                       <groupId>com.sun.jmx</groupId>
+                                       <artifactId>jmxri</artifactId>
+                               </exclusion>
+                               <exclusion>
+                                       <groupId>javax.mail</groupId>
+                                       <artifactId>mail</artifactId>
+                               </exclusion>
+                               <exclusion>
+                                       <groupId>javax.jms</groupId>
+                                       <artifactId>jms</artifactId>
+                               </exclusion>
+                       </exclusions>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>4.4</version>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+       <dependencyManagement>
+               <dependencies>
+                       <dependency>
+                               <groupId>c3p0</groupId>
+                               <artifactId>c3p0</artifactId>
+                               <version>0.9.1.2</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>cglib</groupId>
+                               <artifactId>cglib-nodep</artifactId>
+                               <version>2.1_3</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-collections</groupId>
+                               <artifactId>commons-collections</artifactId>
+                               <version>3.2.1</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-configuration</groupId>
+                               <artifactId>commons-configuration</artifactId>
+                               <version>1.6</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-dbcp</groupId>
+                               <artifactId>commons-dbcp</artifactId>
+                               <version>1.2.2</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-io</groupId>
+                               <artifactId>commons-io</artifactId>
+                               <version>1.4</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-lang</groupId>
+                               <artifactId>commons-lang</artifactId>
+                               <version>2.4</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>commons-logging</groupId>
+                               <artifactId>commons-logging</artifactId>
+                               <version>1.1.1</version>
+                       </dependency>
+                        <dependency>
+                               <groupId>commons-net</groupId>
+                                <artifactId>commons-net</artifactId>
+                               <version>2.0</version>
+                        </dependency>
+                       <dependency>
+                               <groupId>commons-pool</groupId>
+                               <artifactId>commons-pool</artifactId>
+                               <version>1.3</version>
+                       </dependency> 
+                       <dependency>
+                               <groupId>com.h2database</groupId>
+                               <artifactId>h2</artifactId>
+                               <version>1.2.130</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>dom4j</groupId>
+                               <artifactId>dom4j</artifactId>
+                               <version>1.6.1</version>
+                               <exclusions>
+                                       <exclusion>
+                                               <groupId>xml-apis</groupId>
+                                               <artifactId>xml-apis</artifactId>
+                                       </exclusion>
+                               </exclusions>
+                       </dependency>
+                       <dependency>
+                               <groupId>hsqldb</groupId>
+                               <artifactId>hsqldb</artifactId>
+                               <version>1.8.0.7</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>javatar</groupId>
+                               <artifactId>javatar</artifactId>
+                               <version>2.5</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>jpos</groupId>
+                               <artifactId>jpos</artifactId>
+                               <version>1.12.2</version>
+                               <scope>provided</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>jpos</groupId>
+                               <artifactId>jpos-controls</artifactId>
+                               <version>1.12.2</version>
+                               <scope>provided</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.python</groupId>
+                               <artifactId>jython</artifactId>
+                               <version>2.5.2b2</version>
+                       </dependency>           
+                       <dependency>
+                               <groupId>urbanophile</groupId>
+                               <artifactId>java-getopt</artifactId>
+                               <version>1.0.13</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>mysql</groupId>
+                               <artifactId>mysql-connector-java</artifactId>
+                               <version>5.1.6</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.ibatis</groupId>
+                               <artifactId>ibatis-sqlmap</artifactId>
+                               <version>2.3.4.726</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.mina</groupId>
+                               <artifactId>mina-core</artifactId>
+                               <version>2.0.0-M6</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.aspectj</groupId>
+                               <artifactId>aspectjrt</artifactId>
+                               <version>1.6.5</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.aspectj</groupId>
+                               <artifactId>aspectjweaver</artifactId>
+                               <version>1.6.5</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.dbunit</groupId>
+                               <artifactId>dbunit</artifactId>
+                               <version>2.4.4</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-continuation</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-http</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-io</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-security</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-server</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-servlet</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-webapp</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-util</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.eclipse.jetty</groupId>
+                               <artifactId>jetty-xml</artifactId>
+                               <version>7.0.0.v20091005</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.slf4j</groupId>
+                               <artifactId>slf4j-api</artifactId>
+                               <version>1.5.2</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.slf4j</groupId>
+                               <artifactId>slf4j-log4j12</artifactId>
+                               <version>1.5.2</version>
+                               <exclusions>
+                                       <exclusion>
+                                               <groupId>log4j</groupId>
+                                               <artifactId>log4j</artifactId>
+                                       </exclusion>
+                               </exclusions>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-aop</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-beans</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-core</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-context</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-jdbc</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-tx</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-web</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-webmvc</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                                       <artifactId>spring-context-support</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-test</artifactId>
+                               <version>${spring.version}</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework.batch</groupId>
+                               <artifactId>spring-batch-test</artifactId>
+                               <version>2.0.4.RELEASE</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework.batch</groupId>
+                               <artifactId>spring-batch-core</artifactId>
+                               <version>2.0.4.RELEASE</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework.batch</groupId>
+                               <artifactId>spring-batch-infrastructure</artifactId>
+                               <version>2.0.4.RELEASE</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.springframework</groupId>
+                               <artifactId>spring-orm</artifactId>
+                               <version>${spring.version}</version>
+                       </dependency>
+                       <dependency>
+                           <groupId>net.sf.ehcache</groupId>
+                           <artifactId>ehcache</artifactId>
+                           <version>1.6.2</version>
+                       </dependency>
+                       <dependency>
+                           <groupId>org.springmodules</groupId>
+                           <artifactId>spring-modules-cache</artifactId>
+                           <version>0.9</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>p6spy</groupId>
+                               <artifactId>p6spy</artifactId>
+                               <version>1.3</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>javax.transaction</groupId>
+                               <artifactId>jta</artifactId>
+                               <version>1.0.1B</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>javax.servlet</groupId>
+                               <artifactId>servlet-api</artifactId>
+                               <version>2.5</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>com.caucho</groupId>
+                               <artifactId>hessian</artifactId>
+                               <version>3.1.6</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.codehaus.jettison</groupId>
+                               <artifactId>jettison</artifactId>
+                               <version>1.0</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>com.thoughtworks.xstream</groupId>
+                               <artifactId>xstream</artifactId>
+                               <version>1.3</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.ini4j</groupId>
+                               <artifactId>ini4j</artifactId>
+                               <version>0.5.1</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.easymock</groupId>
+                               <artifactId>easymock</artifactId>
+                               <version>2.4</version>
+                               <scope>test</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.easymock</groupId>
+                               <artifactId>easymockclassextension</artifactId>
+                               <version>2.4</version>
+                               <scope>test</scope>
+                       </dependency>
+
+                       <dependency>
+                               <groupId>org.apache.commons</groupId>
+                               <artifactId>commons-compress</artifactId>
+                               <version>1.0</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.commons</groupId>
+                               <artifactId>commons-math</artifactId>
+                               <version>2.0</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>dtgjpos_forms</groupId>
+                               <artifactId>dtgjpos_forms</artifactId>
+                               <version>1.4.12</version>
+                               <scope>provided</scope>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.codehaus.castor</groupId>
+                               <artifactId>castor-xml</artifactId>
+                               <version>1.3.1</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.xmlbeans</groupId>
+                               <artifactId>xmlbeans</artifactId>
+                               <version>2.5.0</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.velocity.tools</groupId>
+                               <artifactId>velocity-tools-generic</artifactId>
+                               <version>1.4</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.apache.velocity</groupId>
+                               <artifactId>velocity</artifactId>
+                               <version>1.6.2</version>
+                       </dependency>
+                       <dependency>
+                               <groupId>org.tmatesoft.svnkit</groupId>
+                               <artifactId>svnkit</artifactId>
+                               <version>1.3.1</version>
+                       </dependency>
+               </dependencies>
+       </dependencyManagement>
+       <modules>
+               <module>javafork-example</module>
+       </modules>
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <version>2.0.2</version>
+                               <configuration>
+                                       <source>1.6</source>
+                                       <target>1.6</target>
+                                       <encoding>${project.build.sourceEncoding}</encoding>
+                               </configuration>
+                       </plugin>
+                       <!-- Usually you will not need this plugin
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-resources-plugin</artifactId>
+                               <version>2.2</version>
+                               <configuration>
+                                       <encoding>${project.build.sourceEncoding}</encoding>
+                               </configuration>
+                       </plugin>
+                       -->
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-javadoc-plugin</artifactId>
+                               <version>2.6</version>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-surefire-plugin</artifactId>
+                               <version>2.4.2</version>
+                               <configuration>
+                                       <testFailureIgnore>true</testFailureIgnore>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>jdepend-maven-plugin</artifactId>
+                               <version>2.0-beta-2</version>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <version>2.3.1</version>
+                               <configuration>
+                                       <archive>
+                                               <manifestEntries>
+                                                       <Specification-Title>${project.description}</Specification-Title>
+                                                       <Specification-Version>${project.version}</Specification-Version>
+                                                       <Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                                                       <Implementation-Title>${project.description}</Implementation-Title>
+                                                       <Implementation-Version>${project.version}</Implementation-Version>
+                                                       <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                                                       <Implementation-Build>${BUILD_TAG}</Implementation-Build>
+                                                       <Implementation-Build-id>${BUILD_ID}</Implementation-Build-id>
+                                                       <Implementation-Build-number>${BUILD_NUMBER}</Implementation-Build-number>
+                                                       <scm-committed-revision>${prefix.committedRevision}</scm-committed-revision>
+                                                       <scm-repository>${prefix.repository}</scm-repository>
+                                                       <scm-path>${prefix.path}</scm-path>                                                           
+                                               </manifestEntries>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
+                               <artifactId>maven-svn-revision-number-plugin</artifactId>
+                               <version>1.6</version>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>revision</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                               <configuration>
+                                       <entries>
+                                               <entry>
+                                                       <prefix>prefix</prefix>
+                                               </entry>
+                                       </entries>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+       <!--We need this for the javadoc and reporting maven plugin -->
+       <distributionManagement>
+               <repository>
+                       <id>releases</id>
+                       <name>releases</name>
+                       <url>http://noserver/artifactory/custom-annotations-libs-releases-local</url>
+               </repository>
+               <snapshotRepository>
+                       <id>snapshots-releases</id>
+                       <name>snapshots-releases</name>
+                       <url>http://noserver/artifactory/custom-annotations-libs-snapshots-local</url>
+               </snapshotRepository>
+               <site>
+                       <id>noserver</id>
+                       <url>file:///mnt/sdb1/data/downloads/jenkins/</url>
+               </site>
+
+       </distributionManagement>
+       <reporting>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-project-info-reports-plugin</artifactId>
+                               <version>2.1.2</version>
+                               <reportSets>
+                                       <reportSet>
+                                               <reports>
+                                                       <report>index</report>
+                                                       <report>dependencies</report>
+                                                       <report>cim</report>
+                                                       <report>issue-tracking</report>
+                                                       <report>scm</report>
+                                                       <report>summary</report>
+                                                       <report>project-team</report>
+                                               </reports>
+                                       </reportSet>
+                               </reportSets>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-javadoc-plugin</artifactId>
+                               <version>2.6.1</version>
+                               <reportSets>
+                                       <reportSet>
+                                               <id>html</id>
+                                               <configuration>
+                                                       <doctitle>MYPROJECT API for ${project.name} ${project.version}</doctitle>
+                                                       <windowtitle>MYPROJECT API for ${project.name} ${project.version}</windowtitle>
+                                               </configuration>
+                                               <reports>
+                                                       <report>javadoc</report>
+                                                       <report>aggregate</report>
+                                               </reports>
+                                       </reportSet>
+                               </reportSets>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.codehaus.mojo</groupId>
+                               <artifactId>taglist-maven-plugin</artifactId>
+                               <version>2.3</version>
+                               <configuration>
+                                       <tags>
+                                               <tag>TODO</tag>
+                                               <tag>@todo</tag>
+                                               <tag>FIXME</tag>
+                                               <tag>XXX</tag>
+                                       </tags>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-surefire-report-plugin</artifactId>
+                               <version>2.4.3</version>
+                               <reportSets>
+                                       <reportSet>
+                                               <id>integration-tests</id>
+                                               <reports>
+                                                       <report>report-only</report>
+                                               </reports>
+                                               <configuration>
+                                                       <outputName>failsafe-report</outputName>
+                                                       <reportsDirectories>
+                                                               <reportsDirectory>target/failsafe-reports</reportsDirectory>
+                                                       </reportsDirectories>
+                                               </configuration>
+                                       </reportSet>
+                                       <reportSet>
+                                               <id>junit-tests</id>
+                                               <reports>
+                                                       <report>report-only</report>
+                                               </reports>
+                                               <configuration>
+                                                       <outputName>surefire-report</outputName>
+                                                       <reportsDirectories>
+                                                               <reportsDirectory>target/surefire-reports</reportsDirectory>
+                                                       </reportsDirectories>
+                                               </configuration>
+                                       </reportSet>
+                               </reportSets>
+                       </plugin>
+               </plugins>
+       </reporting>
+       <properties>
+               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <spring.version>2.5.6</spring.version>
+       </properties>
+       <repositories>
+               <!--
+               <repository>
+                       <id>central-myproject-repo</id>
+                       <name>Internal repository</name>
+                       <url>http://noserver/artifactory/my-repo</url>
+                       <snapshots>
+                               <enabled>false</enabled>
+                       </snapshots>
+               </repository>
+               <repository>
+                       <id>snapshots-releases</id>
+                       <name>snapshots-releases</name>
+                       <url>http://noserver/artifactory/custom-annotations-libs-snapshots-local</url>
+                       <snapshots>
+                               <enabled>true</enabled>
+                       </snapshots>
+               </repository>
+               -->
+       </repositories>
+       <pluginRepositories>
+               <!--
+               <pluginRepository>
+                       <id>central-myproject-plugins-repo</id>
+                       <name>Plugins internal repository</name>
+                       <url>http://noserver/artifactory/plugins-repo</url>
+                       <snapshots>
+                               <enabled>true</enabled>
+                       </snapshots>
+                       <releases>
+                               <enabled>true</enabled>
+                       </releases>
+               </pluginRepository>
+               -->
+       </pluginRepositories>
+</project>