diff options
Diffstat (limited to 'src/main/java/net/sf/antcontrib/antserver/server')
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); + } + } +} |