package com.asgow.ciel.simple; import java.net.URL; import java.net.MalformedURLException; import java.io.IOException; import java.net.URLClassLoader; import java.io.Reader; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.List; import java.util.ArrayList; import java.util.StringTokenizer; import java.util.NoSuchElementException; import java.util.ListIterator; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.UnsupportedEncodingException; public class JarTaskLoader { public static ClassLoader CLASSLOADER; public static void main(String[] args) { if(args[0].equals("--version")) { System.out.println("Ciel Java bindings v0.1\n"); return; } if(args.length < 2) { System.err.println("Usage: java JarTaskLoader fully.qualified.TaskClass file:///path/to/jar [further jars...]"); System.exit(1); } /* Step one: try to instantiate the class we've been asked for */ URL[] urls = new URL[args.length - 1]; try { for(int i = 1; i < args.length; i++) { urls[i-1] = new URL(args[i]); } } catch(MalformedURLException e) { System.err.println("Malformed URL: " + e.toString()); } URLClassLoader urlcl = new URLClassLoader(urls); JarTaskLoader.CLASSLOADER = urlcl; Class targetClass = null; Object targetInstance = null; Task targetTask = null; try { targetClass = urlcl.loadClass(args[0]); } catch(ClassNotFoundException e) { System.err.println("Class " + args[0] + " not found in given JARs"); System.exit(1); } catch(Exception e) { System.err.println("Error loading class '" + args[0] + "': " + e.toString()); System.exit(1); } try { targetInstance = targetClass.newInstance(); } catch(Exception e) { System.err.println("Error instantiating " + args[0] + ": " + e.toString()); System.exit(1); } try { targetTask = (Task)targetInstance; } catch(ClassCastException e) { System.err.println("Error: class " + args[0] + " does not implement the Task interface"); System.exit(1); } /* Step two: pull a list of input files, output files, and arguments from stdin */ Reader r = null; try { r = new BufferedReader(new InputStreamReader(System.in, "UTF-8")); } catch(UnsupportedEncodingException e) { System.err.println("Error: JVM does not support UTF-8 encoding"); System.exit(1); } StringBuilder sb = new StringBuilder(); List<String> inputStrings = new ArrayList<String>(); int nextChar; try { while((nextChar = r.read()) != -1) { if(nextChar == 0) { inputStrings.add(sb.toString()); sb.setLength(0); } else { sb.append((char)nextChar); } } } catch(IOException e) { System.err.println("IOException reading from stdin: " + e.toString()); System.exit(1); } if(inputStrings.size() == 0) { System.err.println("Error: stdin closed before we had received a single null char"); System.exit(1); } StringTokenizer toks = new StringTokenizer(inputStrings.get(0), ","); if(toks.countTokens() != 3) { System.err.println("First string argument must have format number,number,number (got " + inputStrings.get(0) + ")"); System.out.write('Q'); System.exit(1); } int nInputFiles = 0, nOutputFiles = 0, nArgs = 0; try { nInputFiles = Integer.parseInt(toks.nextToken()); nOutputFiles = Integer.parseInt(toks.nextToken()); nArgs = Integer.parseInt(toks.nextToken()); } catch(NoSuchElementException e) { System.err.println("Failed to tokenize the string " + inputStrings.get(0)); System.out.write('Q'); System.exit(1); } catch(NumberFormatException e) { System.err.println("Failed to parse three integers from " + inputStrings.get(0)); System.out.write('Q'); System.exit(1); } if((nInputFiles + nOutputFiles + nArgs + 1) != inputStrings.size()) { System.err.printf("Expected %d input files, %d output files, %d arguments, plus the 1 string-of-counts, but got a total of %d strings:\n", nInputFiles, nOutputFiles, nArgs, (nInputFiles + nOutputFiles + nArgs + 1)); ListIterator<String> it = inputStrings.listIterator(); while(it.hasNext()) { System.err.println(it.next()); } System.out.write('Q'); System.exit(1); } FileInputStream[] targetInputs = new FileInputStream[nInputFiles]; FileOutputStream[] targetOutputs = new FileOutputStream[nOutputFiles]; ListIterator<String> it = inputStrings.subList(nInputFiles + nOutputFiles + 1, nInputFiles + nOutputFiles + nArgs + 1).listIterator(); String[] targetArgs = new String[nArgs]; int i = 0; while(it.hasNext()) { targetArgs[i++] = it.next(); } it = inputStrings.subList(1, nInputFiles + 1).listIterator(); i = 0; while(it.hasNext()) { try { targetInputs[i++] = new FileInputStream(it.next()); } catch(Exception e) { System.err.println("Failed to open a file for input: " + e.toString()); System.out.write('Q'); System.exit(1); } } it = inputStrings.subList(nInputFiles + 1, nInputFiles + nOutputFiles + 1).listIterator(); i = 0; while(it.hasNext()) { try { targetOutputs[i++] = new FileOutputStream(it.next()); } catch(Exception e) { System.err.println("Failed to open a file for output: " + e.toString()); System.out.write('Q'); System.exit(1); } } System.out.write('S'); System.out.flush(); try { targetTask.invoke(targetInputs, targetOutputs, targetArgs); } catch(Exception e) { System.err.println("Invoked task died with an exception: " + e.toString()); e.printStackTrace(System.err); System.exit(2); } } }