summaryrefslogtreecommitdiffstats
path: root/src/main/java/net/sf/antcontrib/antserver/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net/sf/antcontrib/antserver/server')
-rw-r--r--src/main/java/net/sf/antcontrib/antserver/server/ConnectionBuildListener.java198
-rw-r--r--src/main/java/net/sf/antcontrib/antserver/server/ConnectionHandler.java231
-rw-r--r--src/main/java/net/sf/antcontrib/antserver/server/Server.java126
-rw-r--r--src/main/java/net/sf/antcontrib/antserver/server/ServerTask.java68
4 files changed, 623 insertions, 0 deletions
diff --git a/src/main/java/net/sf/antcontrib/antserver/server/ConnectionBuildListener.java b/src/main/java/net/sf/antcontrib/antserver/server/ConnectionBuildListener.java
new file mode 100644
index 0000000..39cf1e5
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/antserver/server/ConnectionBuildListener.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package net.sf.antcontrib.antserver.server;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Stack;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.tools.ant.BuildEvent;
+import org.apache.tools.ant.BuildListener;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/****************************************************************************
+ * Place class description here.
+ *
+ * @author <a href='mailto:[email protected]'>Matthew Inger</a>
+ * @author <additional author>
+ *
+ * @since
+ *
+ ****************************************************************************/
+
+
+public class ConnectionBuildListener
+ implements BuildListener
+{
+ private Document results;
+ private Stack elementStack;
+ private ThreadGroup group;
+
+ public ConnectionBuildListener()
+ throws ParserConfigurationException
+ {
+ group = Thread.currentThread().getThreadGroup();
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ results = builder.newDocument();
+ elementStack = new Stack();
+
+ Element rootElement = results.createElement("results");
+ elementStack.push(rootElement);
+ results.appendChild(rootElement);
+ }
+
+ public Document getDocument()
+ {
+ return results;
+ }
+
+ public void buildStarted(BuildEvent event)
+ {
+ }
+
+
+ public void buildFinished(BuildEvent event)
+ {
+ }
+
+
+ public void targetStarted(BuildEvent event)
+ {
+ if (Thread.currentThread().getThreadGroup() != group)
+ return;
+
+ Element parent = (Element)elementStack.peek();
+
+ Element myElement = results.createElement("target");
+ myElement.setAttribute("name", event.getTarget().getName());
+ parent.appendChild(myElement);
+
+ elementStack.push(myElement);
+ }
+
+
+ public void targetFinished(BuildEvent event)
+ {
+ if (Thread.currentThread().getThreadGroup() != group)
+ return;
+
+ Element myElement = (Element)elementStack.peek();
+
+ String message = event.getMessage();
+ if (message != null)
+ myElement.setAttribute("message", message);
+
+ Throwable t = event.getException();
+ if (t != null)
+ {
+ myElement.setAttribute("status", "failure");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ t.printStackTrace(ps);
+ ps.flush();
+ String errorMessage = t.getMessage();
+ String stackTrace = baos.toString();
+
+ Element error = results.createElement("error");
+ Element errorMsgElement = results.createElement("message");
+ errorMsgElement.appendChild(results.createTextNode(errorMessage));
+ Element stackElement = results.createElement("stack");
+ stackElement.appendChild(results.createCDATASection(stackTrace));
+ error.appendChild(errorMsgElement);
+ error.appendChild(stackElement);
+ myElement.appendChild(error);
+ }
+ else
+ {
+ myElement.setAttribute("status", "success");
+ }
+
+ elementStack.pop();
+ }
+
+
+ public void taskStarted(BuildEvent event)
+ {
+
+ if (Thread.currentThread().getThreadGroup() != group)
+ return;
+
+ Element parent = (Element)elementStack.peek();
+
+ Element myElement = results.createElement("task");
+ myElement.setAttribute("name", event.getTask().getTaskName());
+ parent.appendChild(myElement);
+
+ elementStack.push(myElement);
+ }
+
+
+ public void taskFinished(BuildEvent event)
+ {
+ if (Thread.currentThread().getThreadGroup() != group)
+ return;
+
+ Element myElement = (Element)elementStack.peek();
+
+ Throwable t = event.getException();
+ if (t != null)
+ {
+ myElement.setAttribute("status", "failure");
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrintStream ps = new PrintStream(baos);
+ t.printStackTrace(ps);
+ ps.flush();
+ String errorMessage = t.getMessage();
+ String stackTrace = baos.toString();
+
+ Element error = results.createElement("error");
+ Element errorMsgElement = results.createElement("message");
+ errorMsgElement.appendChild(results.createTextNode(errorMessage));
+ Element stackElement = results.createElement("stack");
+ stackElement.appendChild(results.createCDATASection(stackTrace));
+ error.appendChild(errorMsgElement);
+ error.appendChild(stackElement);
+ myElement.appendChild(error);
+ }
+ else
+ {
+ myElement.setAttribute("status", "success");
+ }
+
+ elementStack.pop();
+ }
+
+
+ public void messageLogged(BuildEvent event)
+ {
+ /*
+ if (Thread.currentThread().getThreadGroup() != group)
+ return;
+
+ Element parentElement = (Element)elementStack.peek();
+
+ Element messageElement = results.createElement("message");
+ messageElement.setAttribute("level", String.valueOf(event.getPriority()));
+ messageElement.appendChild(results.createCDATASection(event.getMessage()));
+ parentElement.appendChild(messageElement);
+ */
+ }
+}
diff --git a/src/main/java/net/sf/antcontrib/antserver/server/ConnectionHandler.java b/src/main/java/net/sf/antcontrib/antserver/server/ConnectionHandler.java
new file mode 100644
index 0000000..23169e0
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/antserver/server/ConnectionHandler.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package net.sf.antcontrib.antserver.server;
+
+import java.io.*;
+import java.net.Socket;
+
+import org.apache.tools.ant.Project;
+import org.apache.xml.serialize.OutputFormat;
+import org.apache.xml.serialize.XMLSerializer;
+
+import net.sf.antcontrib.antserver.Command;
+import net.sf.antcontrib.antserver.Response;
+import net.sf.antcontrib.antserver.Util;
+import net.sf.antcontrib.antserver.commands.DisconnectCommand;
+import net.sf.antcontrib.antserver.commands.ShutdownCommand;
+
+/****************************************************************************
+ * Place class description here.
+ *
+ * @author <a href='mailto:[email protected]'>Matthew Inger</a>
+ * @author <additional author>
+ *
+ * @since
+ *
+ ****************************************************************************/
+
+
+public class ConnectionHandler
+ implements Runnable
+{
+ private static long nextGroupId = 0;
+ private ServerTask task;
+ private Socket socket;
+ private Thread thread;
+ private Throwable thrown;
+
+ public ConnectionHandler(ServerTask task, Socket socket)
+ {
+ super();
+ this.socket = socket;
+ this.task = task;
+ }
+
+ public void start()
+ {
+ long gid = nextGroupId;
+ if (nextGroupId == Long.MAX_VALUE)
+ nextGroupId = 0;
+ else
+ nextGroupId++;
+
+ ThreadGroup group = new ThreadGroup("server-tg-" + gid);
+ thread = new Thread(group, this);
+ thread.start();
+ }
+
+ public Throwable getThrown()
+ {
+ return thrown;
+ }
+
+ public void run()
+ {
+ InputStream is = null;
+ OutputStream os = null;
+
+
+ try
+ {
+ ConnectionBuildListener cbl = null;
+
+ is = socket.getInputStream();
+ os = socket.getOutputStream();
+
+ ObjectInputStream ois = new ObjectInputStream(is);
+ ObjectOutputStream oos = new ObjectOutputStream(os);
+
+ // Write the initial response object so that the
+ // object stream is initialized
+ oos.writeObject(new Response());
+
+ boolean disconnect = false;
+ Command inputCommand = null;
+ Response response = null;
+
+ while (! disconnect)
+ {
+ task.getProject().log("Reading command object.",
+ Project.MSG_DEBUG);
+
+ inputCommand = (Command) ois.readObject();
+
+ task.getProject().log("Executing command object: " + inputCommand,
+ Project.MSG_DEBUG);
+
+ response = new Response();
+
+ try
+ {
+ cbl = new ConnectionBuildListener();
+ task.getProject().addBuildListener(cbl);
+
+ inputCommand.execute(task.getProject(),
+ inputCommand.getContentLength(),
+ is);
+
+ response.setSucceeded(true);
+ }
+ catch (Throwable t)
+ {
+ response.setSucceeded(false);
+ response.setThrowable(t);
+ }
+ finally
+ {
+ if (cbl != null)
+ task.getProject().removeBuildListener(cbl);
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ XMLSerializer serial = new XMLSerializer();
+ OutputFormat fmt = new OutputFormat();
+ fmt.setOmitDocumentType(true);
+ fmt.setOmitXMLDeclaration(false);
+ serial.setOutputFormat(fmt);
+ serial.setOutputByteStream(baos);
+ serial.serialize(cbl.getDocument());
+ response.setResultsXml(baos.toString());
+
+ task.getProject().log("Executed command object: " + inputCommand,
+ Project.MSG_DEBUG);
+
+ task.getProject().log("Sending response: " + response,
+ Project.MSG_DEBUG);
+
+ response.setContentLength(inputCommand.getContentLength());
+
+ oos.writeObject(response);
+
+ if (inputCommand.getResponseContentLength() != 0)
+ {
+ Util.transferBytes(inputCommand.getReponseContentStream(),
+ inputCommand.getResponseContentLength(),
+ os,
+ true);
+ }
+
+ if (inputCommand instanceof DisconnectCommand)
+ {
+ disconnect = true;
+ task.getProject().log("Got disconnect command",
+ Project.MSG_DEBUG);
+ }
+ else if (inputCommand instanceof ShutdownCommand)
+ {
+ disconnect = true;
+ task.getProject().log("Got shutdown command",
+ Project.MSG_DEBUG);
+ task.shutdown();
+ }
+
+ }
+
+ }
+ catch (ClassNotFoundException e)
+ {
+ thrown = e;
+ }
+ catch (IOException e)
+ {
+ thrown = e;
+ }
+ catch (Throwable t)
+ {
+ thrown = t;
+ }
+ finally
+ {
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+
+ }
+ }
+
+ if (os != null)
+ {
+ try
+ {
+ os.close();
+ }
+ catch (IOException e)
+ {
+
+ }
+ }
+
+ if (socket != null)
+ {
+ try
+ {
+ socket.close();
+ }
+ catch (IOException e)
+ {
+
+ }
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/net/sf/antcontrib/antserver/server/Server.java b/src/main/java/net/sf/antcontrib/antserver/server/Server.java
new file mode 100644
index 0000000..b0e8c56
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/antserver/server/Server.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package net.sf.antcontrib.antserver.server;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/****************************************************************************
+ * Place class description here.
+ *
+ * @author <a href='mailto:[email protected]'>Matthew Inger</a>
+ * @author <additional author>
+ *
+ * @since
+ *
+ ****************************************************************************/
+
+
+public class Server
+ implements Runnable
+{
+ private ServerTask task;
+ private int port = 17000;
+ private boolean running = false;
+ private Thread thread = null;
+
+ public Server(ServerTask task, int port)
+ {
+ super();
+ this.task = task;
+ this.port = port;
+ }
+
+ public void start()
+ throws InterruptedException
+ {
+ thread = new Thread(this);
+ thread.start();
+ thread.join();
+ }
+
+ public void stop()
+ {
+ running = false;
+ }
+
+ public void run()
+ {
+ ServerSocket server = null;
+ running = true;
+ try
+ {
+ task.getProject().log("Starting server on port: " + port,
+ Project.MSG_DEBUG);
+ try
+ {
+ server = new ServerSocket(port);
+ server.setSoTimeout(500);
+ }
+ catch (IOException e)
+ {
+ throw new BuildException(e);
+ }
+
+
+ while (running)
+ {
+ try
+ {
+ Socket clientSocket = server.accept();
+ task.getProject().log("Got a client connection. Starting Handler.",
+ Project.MSG_DEBUG);
+ ConnectionHandler handler = new ConnectionHandler(task,
+ clientSocket);
+ handler.start();
+ }
+ catch (InterruptedIOException e)
+ {
+ ; // gulp, no socket connection
+ }
+ catch (IOException e)
+ {
+ task.getProject().log(e.getMessage(),
+ Project.MSG_ERR);
+ }
+ }
+ }
+ finally
+ {
+ if (server != null)
+ {
+ try
+ {
+ server.close();
+ server = null;
+ }
+ catch (IOException e)
+ {
+ ; // gulp
+ }
+ }
+ }
+ running = false;
+
+
+ }
+
+}
diff --git a/src/main/java/net/sf/antcontrib/antserver/server/ServerTask.java b/src/main/java/net/sf/antcontrib/antserver/server/ServerTask.java
new file mode 100644
index 0000000..74006af
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/antserver/server/ServerTask.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ package net.sf.antcontrib.antserver.server;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+
+/****************************************************************************
+ * Place class description here.
+ *
+ * @author <a href='mailto:[email protected]'>Matthew Inger</a>
+ * @author <additional author>
+ *
+ * @since
+ *
+ ****************************************************************************/
+
+
+public class ServerTask
+ extends Task
+{
+ private Server server;
+ private int port = 17000;
+
+ public ServerTask()
+ {
+ super();
+ }
+
+
+ public void setPort(int port)
+ {
+ this.port = port;
+ }
+
+
+ public void shutdown()
+ {
+ server.stop();
+ }
+
+ public void execute()
+ {
+ try
+ {
+ server = new Server(this, port);
+ server.start();
+ }
+ catch (InterruptedException e)
+ {
+ throw new BuildException(e);
+ }
+ }
+}