diff --git a/.classpath b/.classpath index 9df503b..519f65c 100644 --- a/.classpath +++ b/.classpath @@ -2,7 +2,7 @@ - + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 416f4fb..8000cd6 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,11 +1,11 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.compliance=1.6 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.5 +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/src/com/flaremicro/crossjeeves/AgentInfo.java b/src/com/flaremicro/crossjeeves/AgentInfo.java index e91eb84..4f4a0fa 100644 --- a/src/com/flaremicro/crossjeeves/AgentInfo.java +++ b/src/com/flaremicro/crossjeeves/AgentInfo.java @@ -11,4 +11,9 @@ public class AgentInfo { this.addr = addr; this.port = port; } + + public String toString() + { + return addr.toString() + " " + port; + } } diff --git a/src/com/flaremicro/crossjeeves/CrossJeevesClient.java b/src/com/flaremicro/crossjeeves/CrossJeevesClient.java index 6a8df8b..56b372c 100644 --- a/src/com/flaremicro/crossjeeves/CrossJeevesClient.java +++ b/src/com/flaremicro/crossjeeves/CrossJeevesClient.java @@ -18,14 +18,16 @@ public class CrossJeevesClient { } public void beginJob() { + System.out.println("Trying to connect to agent"); for(int i = 0; i < MAX_ATTEMPTS; i++) { for(AgentInfo agent : agentList) { + System.out.println("Trying agent " + agent.toString()); int exitCode = ClientHandler.connect(agent.addr, agent.port, script); if(ErrorCodes.getErrorCode(exitCode) == null || ErrorCodes.getErrorCode(exitCode).isTerminal) { - System.out.println("Recieved terminal exit code " + exitCode); + System.err.println("Recieved terminal exit code " + exitCode); System.exit(exitCode); } else if(exitCode == ErrorCodes.OK.id) @@ -34,7 +36,19 @@ public class CrossJeevesClient { System.exit(0); } } + try + { + Thread.sleep(1000L); + System.out.println("Failed every agent, retrying..."); + } + catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } } + System.err.println("Failed every attempt!"); + System.exit(ErrorCodes.CONNECT_FAILED.id); } } diff --git a/src/com/flaremicro/crossjeeves/CrossJeevesHost.java b/src/com/flaremicro/crossjeeves/CrossJeevesHost.java index 75b5c78..1b9e23c 100644 --- a/src/com/flaremicro/crossjeeves/CrossJeevesHost.java +++ b/src/com/flaremicro/crossjeeves/CrossJeevesHost.java @@ -49,6 +49,7 @@ public class CrossJeevesHost { //TODO properties! ServerHandler handler = new ServerHandler(sock, this, new Properties()); connections.add(handler); + handler.init(); } catch (IOException ex) { diff --git a/src/com/flaremicro/crossjeeves/CrossJeevesMain.java b/src/com/flaremicro/crossjeeves/CrossJeevesMain.java index 10aea47..4173aae 100644 --- a/src/com/flaremicro/crossjeeves/CrossJeevesMain.java +++ b/src/com/flaremicro/crossjeeves/CrossJeevesMain.java @@ -52,10 +52,10 @@ public class CrossJeevesMain { System.out.println("IP must be specified"); System.exit(1); } - String ipStr = args[0]; + String ipStr = agentArgs[0]; String portStr = "10801"; - if(args.length >= 2) - portStr = args[1]; + if(agentArgs.length >= 2) + portStr = agentArgs[1]; try { int port = Integer.parseInt(portStr); diff --git a/src/com/flaremicro/crossjeeves/ScriptProcessor.java b/src/com/flaremicro/crossjeeves/ScriptProcessor.java index 23f90fe..6723d39 100644 --- a/src/com/flaremicro/crossjeeves/ScriptProcessor.java +++ b/src/com/flaremicro/crossjeeves/ScriptProcessor.java @@ -22,8 +22,11 @@ import org.xml.sax.InputSource; import com.flaremicro.crossjeeves.net.ErrorCodes; import com.flaremicro.crossjeeves.net.NetworkHandler; +import com.flaremicro.crossjeeves.net.StreamForwarder; import com.flaremicro.crossjeeves.net.packet.Packet; import com.flaremicro.crossjeeves.net.packet.Packet3Clone; +import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry; +import com.flaremicro.util.Util; import com.flaremicro.util.ZipUtils; public class ScriptProcessor { @@ -34,6 +37,7 @@ public class ScriptProcessor { private Random random = new Random(); private Thread executionThread = null; private File workspace = null; + private File workingDirectory = null; private boolean terminated = false; public ScriptProcessor(NetworkHandler netHandler, File workspace, Properties properties) { @@ -65,6 +69,7 @@ public class ScriptProcessor { } public void processScript(String script) throws ScriptProcessingException { + workingDirectory = workspace; if(terminated) throw new ScriptProcessingException("Processor has been terminated"); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -76,53 +81,7 @@ public class ScriptProcessor { NodeList nodeList = doc.getDocumentElement().getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) - { - if(terminated) - throw new ScriptProcessingException("Processor has been terminated"); - Node node = nodeList.item(i); - Element e = getElement(node); - if (e == null) - continue; - - String name = e.getTagName().trim(); - if (name == null || name.length() <= 0) - { - throw new ScriptProcessingException("Got invalid null or empty element"); - } - if (name.equalsIgnoreCase("environment")) - { - environmentProcessor(e); - } - else if (name.equalsIgnoreCase("clone")) - { - cloneProcessor(e); - } - else if (name.equalsIgnoreCase("bat")) - { - batchProcessor(e); - } - else if (name.equalsIgnoreCase("py")) - { - pythonProcessor(e); - } - else if (name.equalsIgnoreCase("sh")) - { - shellProcessor(e); - } - else if (name.equalsIgnoreCase("ps")) - { - powershellProcessor(e); - } - else if (name.equalsIgnoreCase("artifacts")) - { - artifactProcessor(e); - } - else - { - throw new ScriptProcessingException("Got invalid element " + name + ": " + e.toString()); - } - } + processScriptNodes(nodeList); } catch (ScriptProcessingException ex) { @@ -134,6 +93,69 @@ public class ScriptProcessor { } } + private void processScriptNodes(NodeList nodeList) throws ScriptProcessingException { + for (int i = 0; i < nodeList.getLength(); i++) + { + if(terminated) + throw new ScriptProcessingException("Processor has been terminated"); + Node node = nodeList.item(i); + Element e = getElement(node); + if (e == null) + continue; + + String name = e.getTagName().trim(); + if (name == null || name.length() <= 0) + { + throw new ScriptProcessingException("Got invalid null or empty element"); + } + if (name.equalsIgnoreCase("environment")) + { + environmentProcessor(e); + } + else if (name.equalsIgnoreCase("clone")) + { + cloneProcessor(e); + } + else if (name.equalsIgnoreCase("bat")) + { + batchProcessor(e); + } + else if (name.equalsIgnoreCase("py")) + { + pythonProcessor(e); + } + else if (name.equalsIgnoreCase("sh")) + { + shellProcessor(e); + } + else if (name.equalsIgnoreCase("ps")) + { + powershellProcessor(e); + } + + else if (name.equalsIgnoreCase("dir")) + { + dirProcessor(e); + } + else if (name.equalsIgnoreCase("artifacts")) + { + artifactProcessor(e); + } + else + { + throw new ScriptProcessingException("Got invalid element " + name + ": " + e.toString()); + } + } + } + + private void dirProcessor(Element e) throws ScriptProcessingException { + NodeList nodeList = e.getChildNodes(); + File lastWorkingDirectory = this.workingDirectory; + this.workingDirectory = new File(workingDirectory, this.requireAttribute(e, "path")); + this.processScriptNodes(nodeList); + this.workingDirectory = lastWorkingDirectory; + } + public void environmentProcessor(Element e) throws ScriptProcessingException { NodeList nodeList = e.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) @@ -167,7 +189,7 @@ public class ScriptProcessor { File file = netHandler.waitForFile(id); if (file == null) throw new ScriptProcessingException("File failed to transfer"); - if(!ZipUtils.unzipDirectory(file, workspace)); + if(!ZipUtils.unzipDirectory(file, workspace)) throw new ScriptProcessingException("File failed to decompress"); } @@ -204,8 +226,10 @@ public class ScriptProcessor { public int beginProcess(String... args) throws ScriptProcessingException { ProcessBuilder processBuilder = new ProcessBuilder(args); + processBuilder.directory(workspace); Map environment = processBuilder.environment(); + for (Entry set : currentEnvironment.entrySet()) { environment.put(set.getKey(), set.getValue()); @@ -216,13 +240,31 @@ public class ScriptProcessor { try { runningProcess = processBuilder.start(); - return runningProcess.exitValue(); + + StreamForwarder stdOutForwarder = new StreamForwarder(netHandler, runningProcess.getInputStream(), Packet7LogEntry.STD_OUT); + StreamForwarder stdErrForwarder = new StreamForwarder(netHandler, runningProcess.getErrorStream(), Packet7LogEntry.STD_ERR); + + stdOutForwarder.startAsync(); + stdErrForwarder.startAsync(); + + int exit = runningProcess.waitFor(); + + stdOutForwarder.end(); + stdErrForwarder.end(); + + return exit; } catch (IOException ex) { runningProcess = null; throw new ScriptProcessingException("Unable to run batch script: " + ex.getMessage(), ex); } + catch (InterruptedException ex) + { + runningProcess.destroy(); + runningProcess = null; + throw new ScriptProcessingException("Batch script interrupted: " + ex.getMessage(), ex); + } } private void batchProcessor(Element e) throws ScriptProcessingException { @@ -267,10 +309,11 @@ public class ScriptProcessor { try { processScript(script); + netHandler.disconnect(ErrorCodes.OK.id, "Script completed successfully!"); } catch (ScriptProcessingException e) { - netHandler.disconnect(ErrorCodes.SCRIPT_ERROR.id, e.toString()); + netHandler.disconnect(ErrorCodes.SCRIPT_ERROR.id, Util.getStackTrace(e)); e.printStackTrace(); } finally diff --git a/src/com/flaremicro/crossjeeves/net/ClientHandler.java b/src/com/flaremicro/crossjeeves/net/ClientHandler.java index b1f530e..3b9fa83 100644 --- a/src/com/flaremicro/crossjeeves/net/ClientHandler.java +++ b/src/com/flaremicro/crossjeeves/net/ClientHandler.java @@ -18,6 +18,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone; import com.flaremicro.crossjeeves.net.packet.Packet4FileData; import com.flaremicro.crossjeeves.net.packet.Packet5Artifact; import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect; +import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry; import com.flaremicro.util.Util; import com.flaremicro.util.ZipUtils; @@ -30,6 +31,7 @@ public class ClientHandler extends NetworkHandler { } private void init() { + System.out.println("CrossJeeves connected! Sending Identify packet..."); enqueue(new Packet0Identify(0)); this.beginWriteThread(); this.beginReading(); @@ -48,6 +50,7 @@ public class ClientHandler extends NetworkHandler { } else { + System.out.println("Got good identify packet response! Sending script..."); enqueue(new Packet2Script(script)); } } @@ -147,4 +150,12 @@ public class ClientHandler extends NetworkHandler { } } + @Override + public void handlePacket(Packet7LogEntry packet) { + if(packet.getStdOutput() == Packet7LogEntry.STD_ERR) + System.err.println(packet.getLogEntry()); + else + System.out.println(packet.getLogEntry()); + } + } diff --git a/src/com/flaremicro/crossjeeves/net/ErrorCodes.java b/src/com/flaremicro/crossjeeves/net/ErrorCodes.java index 3481736..33f6ba6 100644 --- a/src/com/flaremicro/crossjeeves/net/ErrorCodes.java +++ b/src/com/flaremicro/crossjeeves/net/ErrorCodes.java @@ -4,11 +4,14 @@ package com.flaremicro.crossjeeves.net; * Consider replacing with enum in the near future. */ public class ErrorCodes { + + private static final ErrorCodes codes[] = new ErrorCodes[13]; + public static final ErrorCodes OK = new ErrorCodes(0, false); public static final ErrorCodes READ_FAILED = new ErrorCodes(1, false); public static final ErrorCodes WRITE_FAILED = new ErrorCodes(2, false); public static final ErrorCodes THREAD_INTERRUPTED = new ErrorCodes(3, false); - public static final ErrorCodes SCRIPT_ERROR = new ErrorCodes(4, false); + public static final ErrorCodes SCRIPT_ERROR = new ErrorCodes(4, true); public static final ErrorCodes FILE_DOWNLOAD_FAILURE = new ErrorCodes(5, false); public static final ErrorCodes FILE_UPLOAD_FAILURE = new ErrorCodes(6, false); public static final ErrorCodes INVALID_PACKET_RECIEVED = new ErrorCodes(7, false); @@ -17,9 +20,7 @@ public class ErrorCodes { public static final ErrorCodes SERVER_BUSY = new ErrorCodes(10, false); public static final ErrorCodes AGENT_TERMINATED = new ErrorCodes(11, false); public static final ErrorCodes CONNECT_FAILED = new ErrorCodes(12, false); - - private static final ErrorCodes codes[] = new ErrorCodes[12]; - + public final int id; public final boolean isTerminal; public ErrorCodes(int id, boolean isTerminal) diff --git a/src/com/flaremicro/crossjeeves/net/NetworkHandler.java b/src/com/flaremicro/crossjeeves/net/NetworkHandler.java index 749f1a0..dd243ac 100644 --- a/src/com/flaremicro/crossjeeves/net/NetworkHandler.java +++ b/src/com/flaremicro/crossjeeves/net/NetworkHandler.java @@ -22,6 +22,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone; import com.flaremicro.crossjeeves.net.packet.Packet4FileData; import com.flaremicro.crossjeeves.net.packet.Packet5Artifact; import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect; +import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry; import com.flaremicro.util.Util; import static com.flaremicro.crossjeeves.net.ErrorCodes.*; @@ -31,6 +32,7 @@ public abstract class NetworkHandler { private Socket socket; private DataInputStream in; private DataOutputStream out; + private Thread writeThread; private Thread readThread; private int exitCode = 0; private HashMap downloadQueue = new HashMap(); @@ -49,7 +51,11 @@ public abstract class NetworkHandler { { while (true) { - downloadComplete.wait(); + synchronized (downloadComplete) + { + if (!downloadComplete.containsKey(fileId)) + downloadComplete.wait(); + } File file = downloadComplete.get(fileId); if (file != null) return file; @@ -67,7 +73,14 @@ public abstract class NetworkHandler { } public void enqueue(Packet packet) { - outbox.add(packet); + try + { + outbox.put(packet); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } } public void process(Packet packet) { @@ -75,14 +88,18 @@ public abstract class NetworkHandler { } public void disconnect(int code, String message) { - System.out.println("Disconnect code " + code + ": " + message); - doDisconnect(code); + if (isConnected()) + { + System.out.println("Disconnect code " + code + ": " + message); + doDisconnect(code); + } } protected void doDisconnect(int exitCode) { this.exitCode = exitCode; connected = false; - readThread.interrupt(); + if (writeThread != null) + writeThread.interrupt(); Util.cleanClose(in); Util.cleanClose(out); Util.cleanClose(socket); @@ -98,7 +115,7 @@ public abstract class NetworkHandler { try { int opcode = in.readByte(); - Packet packet = Packet.opToPacket.get(opcode); + Packet packet = Packet.opToPacket.get((byte) opcode); if (packet != null) { packet = packet.cloneTypeOnly(); @@ -108,42 +125,64 @@ public abstract class NetworkHandler { } catch (IOException e) { - e.printStackTrace(); - disconnect(READ_FAILED.id, e.toString()); + if (connected) + { + e.printStackTrace(); + disconnect(READ_FAILED.id, e.toString()); + } } } } + protected void beginReadThread() { + if (readThread == null) + { + readThread = new Thread(new Runnable() { + public void run() { + beginReading(); + } + }); + readThread.start(); + } + } + protected void beginWriteThread() { - readThread = new Thread(new Runnable() { - public void run() { - while (connected) - { - try + if (writeThread == null) + { + writeThread = new Thread(new Runnable() { + public void run() { + while (connected) { - Packet packet = outbox.take(); - if (packet != null) + try { - try + Packet packet = outbox.take(); + if (packet != null) { - packet.sendPacket(out); + try + { + packet.sendPacket(out); + } + catch (IOException e) + { + disconnect(WRITE_FAILED.id, e.toString()); + e.printStackTrace(); + } } - catch (IOException e) + } + catch (InterruptedException e) + { + if (connected) { - disconnect(WRITE_FAILED.id, e.toString()); + disconnect(THREAD_INTERRUPTED.id, e.toString()); e.printStackTrace(); } } } - catch (InterruptedException e) - { - disconnect(THREAD_INTERRUPTED.id, e.toString()); - e.printStackTrace(); - } + writeThread = null; } - } - }); - readThread.start(); + }); + writeThread.start(); + } } public abstract void handlePacket(Packet packet); @@ -161,6 +200,8 @@ public abstract class NetworkHandler { public abstract void handlePacket(Packet5Artifact packet); public abstract void handlePacket(Packet6Disconnect packet); + + public abstract void handlePacket(Packet7LogEntry packet); public abstract void handlePacket(Packet127KeepAlive packet); @@ -203,7 +244,10 @@ public abstract class NetworkHandler { { Util.cleanClose(fileTransferInfo); this.downloadComplete.put(fileId, fileTransferInfo.file); - this.downloadComplete.notifyAll(); + synchronized (this.downloadComplete) + { + this.downloadComplete.notifyAll(); + } } else { diff --git a/src/com/flaremicro/crossjeeves/net/ServerHandler.java b/src/com/flaremicro/crossjeeves/net/ServerHandler.java index 1939cf5..be159b8 100644 --- a/src/com/flaremicro/crossjeeves/net/ServerHandler.java +++ b/src/com/flaremicro/crossjeeves/net/ServerHandler.java @@ -19,6 +19,7 @@ import com.flaremicro.crossjeeves.net.packet.Packet3Clone; import com.flaremicro.crossjeeves.net.packet.Packet5Artifact; import com.flaremicro.crossjeeves.net.packet.Packet4FileData; import com.flaremicro.crossjeeves.net.packet.Packet6Disconnect; +import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry; public class ServerHandler extends NetworkHandler { private CrossJeevesHost host; @@ -31,6 +32,20 @@ public class ServerHandler extends NetworkHandler { this.scriptProcessor = new ScriptProcessor(this, workspace, properties); } + public void disconnect(int code, String message) { + enqueue(new Packet6Disconnect(code, message)); + try + { + Thread.sleep(1000L); + } + catch (InterruptedException e) + { + if(isConnected()) + e.printStackTrace(); + } + super.disconnect(code, message); + } + @Override protected void doDisconnect(int exitCode) { @@ -46,6 +61,7 @@ public class ServerHandler extends NetworkHandler { @Override public void handlePacket(Packet0Identify packet) { + System.out.println("Got valid identify packet with flags " + packet.getFlags() + " and version " + packet.getProtocolVersion()); enqueue(new Packet0Identify(0)); } @@ -61,7 +77,14 @@ public class ServerHandler extends NetworkHandler { @Override public void handlePacket(Packet3Clone packet) { - disconnect(INVALID_PACKET_RECIEVED.id, "Recieved invalid packet " + packet.getId() + " (Clone)"); + try + { + this.beginFile(packet.getFileID(), packet.getFileSize()); + } + catch (IOException e) + { + disconnect(FILE_DOWNLOAD_FAILURE.id, "Failed to start download of transferred file"); + } } @Override @@ -92,4 +115,15 @@ public class ServerHandler extends NetworkHandler { doDisconnect(packet.getCode()); } + public void init() { + this.beginWriteThread(); + this.beginReadThread(); + } + + @Override + public void handlePacket(Packet7LogEntry packet) { + // TODO Auto-generated method stub + + } + } diff --git a/src/com/flaremicro/crossjeeves/net/StreamForwarder.java b/src/com/flaremicro/crossjeeves/net/StreamForwarder.java new file mode 100644 index 0000000..f6da059 --- /dev/null +++ b/src/com/flaremicro/crossjeeves/net/StreamForwarder.java @@ -0,0 +1,98 @@ +package com.flaremicro.crossjeeves.net; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.flaremicro.crossjeeves.net.packet.Packet7LogEntry; +import com.flaremicro.util.Util; + +/* TODO + * Forward output from entire process, rather than just from started processes? + */ +public class StreamForwarder { + private InnerThread innerThread; + + public StreamForwarder(NetworkHandler handler, InputStream processInput, byte stdType) { + innerThread = new InnerThread(handler, processInput, stdType); + } + + public void startAsync() { + innerThread.start(); + } + + public void end() { + innerThread.stop(); + } + + private class InnerThread implements Runnable { + private Thread parent = null; + private final NetworkHandler handler; + private final InputStream processInput; + private final byte stdType; + private boolean isRunning = false; + + public InnerThread(NetworkHandler handler, InputStream processInput, byte stdType) { + this.handler = handler; + this.processInput = processInput; + this.stdType = stdType; + } + + public void stop() { + isRunning = false; + } + + public void start() { + if (!isRunning && parent != null) + { + isRunning = true; + parent = new Thread(this); + parent.start(); + } + } + + public void print(String s) + { + if(stdType == Packet7LogEntry.STD_ERR) + System.err.println(s); + else + System.out.println(s); + } + + @Override + public void run() { + BufferedReader reader = null; + try + { + reader = new BufferedReader(new InputStreamReader(processInput)); + String line; + while (isRunning && (line = reader.readLine()) != null) + { + handler.enqueue(new Packet7LogEntry(stdType, line)); + print(line); + } + if (processInput.available() > 0) + { + byte[] remaining = new byte[processInput.available()]; + processInput.read(remaining); + line = new String(remaining); + print(line); + handler.enqueue(new Packet7LogEntry(stdType, line)); + } + parent = null; + } + catch (IOException ex) + { + ex.printStackTrace(); + handler.enqueue(new Packet7LogEntry(stdType, "Error occured:" + ex.toString() + ", logging ended.")); + print("Error occured, logging ended."); + } + finally + { + Util.cleanClose(reader); + } + } + } + +} diff --git a/src/com/flaremicro/util/Util.java b/src/com/flaremicro/util/Util.java index 4913735..5e7c4c0 100644 --- a/src/com/flaremicro/util/Util.java +++ b/src/com/flaremicro/util/Util.java @@ -1,35 +1,37 @@ package com.flaremicro.util; +import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; +import java.io.PrintWriter; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.zip.ZipFile; public class Util { - public static Map parseArgs(String[] args, boolean toLowercaseKey, boolean exceptOnDuplicateKey) - { + public static Map parseArgs(String[] args, boolean toLowercaseKey, boolean exceptOnDuplicateKey) { Map map = new HashMap(); - for(String arg : args) + for (String arg : args) { + System.out.println(arg); String key, value; - if(arg.contains("=")) + if (arg.contains("=")) { - String[] param = arg.split("=", 1); + String[] param = arg.split("=", 2); key = param[0]; value = param[1]; } else { key = arg; - value = "isset"; + value = ""; } - if(!map.containsKey(value)) + if (!map.containsKey(value)) { map.put(key, value); } - else if(exceptOnDuplicateKey) + else if (exceptOnDuplicateKey) { throw new RuntimeException("Duplicate parameter"); } @@ -38,7 +40,7 @@ public class Util { } public static void cleanClose(Closeable closeable) { - if(closeable != null) + if (closeable != null) { try { @@ -52,7 +54,7 @@ public class Util { } public static void cleanClose(ZipFile zipFile) { - if(zipFile != null) + if (zipFile != null) { try { @@ -64,9 +66,9 @@ public class Util { } } } - + public static void cleanClose(Socket socket) { - if(socket != null) + if (socket != null) { try { @@ -78,4 +80,26 @@ public class Util { } } } + + /** + * Get the stacktrace of a {@link Throwable}. + * The stacktrace will be returned in the form of a string. + */ + public static String getStackTrace(Throwable ex) { + if (ex == null) + return ""; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter printWriter = new PrintWriter(baos, true); + ex.printStackTrace(printWriter); + String stackTrace = baos.toString(); + try + { + printWriter.close(); + baos.close(); + } + catch (IOException dontCare) + { + } + return stackTrace; + } } diff --git a/txt.txt b/txt.txt new file mode 100644 index 0000000..d79724a --- /dev/null +++ b/txt.txt @@ -0,0 +1 @@ +there should be some output diff --git a/workspace/-1884831558229147979/Test.txt b/workspace/-1884831558229147979/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-1884831558229147979/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-1884831558229147979/abba/Test.txt b/workspace/-1884831558229147979/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-1884831558229147979/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3407491290024025032/Test.txt b/workspace/-3407491290024025032/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3407491290024025032/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3407491290024025032/abba/Test.txt b/workspace/-3407491290024025032/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3407491290024025032/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3683641246049409820/Test.txt b/workspace/-3683641246049409820/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3683641246049409820/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3683641246049409820/abba/Test.txt b/workspace/-3683641246049409820/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3683641246049409820/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3695164149849747891/Test.txt b/workspace/-3695164149849747891/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3695164149849747891/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-3695164149849747891/abba/Test.txt b/workspace/-3695164149849747891/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-3695164149849747891/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-4423281390745774832/Test.txt b/workspace/-4423281390745774832/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-4423281390745774832/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-4423281390745774832/abba/Test.txt b/workspace/-4423281390745774832/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-4423281390745774832/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-4632459217752892791/Test.txt b/workspace/-4632459217752892791/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-4632459217752892791/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/-4632459217752892791/abba/Test.txt b/workspace/-4632459217752892791/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/-4632459217752892791/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/5444029390664951049/Test.txt b/workspace/5444029390664951049/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/5444029390664951049/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/5444029390664951049/abba/Test.txt b/workspace/5444029390664951049/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/5444029390664951049/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/5872898990672949951/Test.txt b/workspace/5872898990672949951/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/5872898990672949951/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/5872898990672949951/abba/Test.txt b/workspace/5872898990672949951/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/5872898990672949951/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/7258372885358876304/Test.txt b/workspace/7258372885358876304/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/7258372885358876304/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/7258372885358876304/abba/Test.txt b/workspace/7258372885358876304/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/7258372885358876304/abba/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/8784412856913438729/Test.txt b/workspace/8784412856913438729/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/8784412856913438729/Test.txt @@ -0,0 +1 @@ + diff --git a/workspace/8784412856913438729/abba/Test.txt b/workspace/8784412856913438729/abba/Test.txt new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/workspace/8784412856913438729/abba/Test.txt @@ -0,0 +1 @@ +