import javax.imageio.*; import java.awt.image.*; import java.awt.event.*; import java.awt.*; import java.security.spec.*; import java.security.*; import java.lang.management.*; import java.lang.ref.*; import java.lang.reflect.*; import java.net.*; import java.io.*; import javax.swing.table.*; import javax.swing.text.*; import javax.swing.event.*; import javax.swing.*; import java.util.concurrent.atomic.*; import java.util.concurrent.*; import java.util.regex.*; import java.util.List; import java.util.zip.*; import java.util.*; public class main { static String vmName = "This is a JavaX VM."; // Use any vM public static void main(String[] args) throws Exception { new Console(new String[0]); } static class DelayedUpdate { Runnable renderer; volatile long version; long lastUpdate; // AWT time int delay = 1000; DelayedUpdate(Runnable renderer) { this.renderer = renderer;} void trigger() { SwingUtilities.invokeLater(new Runnable() { public void run() { try { awt_quickUpdate(); } catch (Exception _e) { throw _e instanceof RuntimeException ? (RuntimeException) _e : new RuntimeException(_e); } } }); final long n = ++version; javax.swing.Timer timer = new javax.swing.Timer(delay, new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { awt_show(n); }}); timer.setRepeats(false); timer.start(); } void awt_quickUpdate() { if (lastUpdate < now()-delay) { render(); lastUpdate = now(); // This can be rough, no problem } } void awt_show(long n) { if (n == version) { render(); lastUpdate = now(); } } void render() { try { renderer.run(); } catch (Throwable e) { e.printStackTrace(); } } } // DelayedUpdate static class Console extends WindowAdapter implements WindowListener, ActionListener { PipedInputStream pin=new PipedInputStream(); PipedInputStream pin2=new PipedInputStream(); PipedInputStream pin3=new PipedInputStream(); Thread reader, reader2; boolean quit; JFrame frame; JTextArea textArea; JTextField tfInput; StringBuffer buf = new StringBuffer(); JButton buttonclear, buttonkill, buttonrestart, buttonduplicate, buttonstacktrace; String[] args; final DelayedUpdate du = new DelayedUpdate(new Runnable() { public void run() { try { textArea.append(buf.substring(textArea.getText().length())); } catch (Exception __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }}}); public Console(final String[] args) { try { this.args = args; // create all components and add them frame=new JFrame(args.length == 0 ? "Console Bot Console" : "Console Bot Console - " + join(" ", args)); /*Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize(); Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2)); int x=(int)(frameSize.width/2); int y=(int)(frameSize.height/2); frame.setBounds(x,y,frameSize.width,frameSize.height);*/ // put in right-bottom corner Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); int w = 550, h = 200; frame.setBounds(r.x+r.width-w, r.y+r.height-h, w, h); textArea=new JTextArea(); textArea.setEditable(false); buttonclear = new JButton("clear"); buttonkill = new JButton("kill"); buttonrestart = new JButton("restart"); buttonduplicate = new JButton("duplicate"); buttonstacktrace = new JButton("status"); buttonstacktrace.setToolTipText("Show threads & stack traces."); JPanel buttons = new JPanel(new GridLayout(1, 5)); buttons.add(buttonclear); buttons.add(buttonkill); buttons.add(buttonrestart); buttons.add(buttonduplicate); buttons.add(buttonstacktrace); tfInput = new JTextField(); tfInput.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent _evt) { String line = tfInput.getText(); sendToLocalBot(vmName, "send line * to system.in", line); tfInput.setText(""); }}); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JScrollPane(textArea), BorderLayout.CENTER); panel.add(tfInput, BorderLayout.SOUTH); frame.addWindowListener(new WindowAdapter() { public void windowActivated(WindowEvent e) { tfInput.requestFocus(); } }); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(panel, BorderLayout.CENTER); frame.getContentPane().add(buttons, BorderLayout.SOUTH); frame.setVisible(true); //frame.addWindowListener(this); // disabled for now buttonclear.addActionListener(this); buttonkill.addActionListener(this); buttonrestart.addActionListener(this); buttonduplicate.addActionListener(this); buttonstacktrace.addActionListener(this); quit=false; // signals the Threads that they should exit if (args.length != 0) { print("Starting title updater"); new Thread("Console Title Updater :)") { public void run() { if (args.length != 0) { int i = 0; while (i < args.length && !isSnippetID(args[i])) ++i; print("Getting title for " + args[i]); String title = getSnippetTitle(args[i]); print("Title: " + title); if (title != null && title.length() != 0) frame.setTitle(title + " [Output]"); } } }.start(); } System.setIn(pin3); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} public synchronized void windowClosed(WindowEvent evt) { /*quit=true; this.notifyAll(); // stop all threads try { reader.join(1000);pin.close(); } catch (Exception e){} try { reader2.join(1000);pin2.close(); } catch (Exception e){} System.exit(0);*/ } public synchronized void windowClosing(WindowEvent evt) { frame.setVisible(false); // default behaviour of JFrame frame.dispose(); } public synchronized void actionPerformed(ActionEvent evt) { /*if (evt.getSource() == buttonkill) { print("Console: Kill button pressed!"); // TODO: give threads time to finish, e.g. reportToChat? System.exit(0); } else if (evt.getSource() == buttonrestart) { print("Console: Restart button pressed."); nohupJavax(smartJoin(args)); System.exit(0); } else if (evt.getSource() == buttonduplicate) { print("Console: Duplicate button pressed."); nohupJavax(smartJoin(args)); } else if (evt.getSource() == buttonstacktrace) { listUserThreadsWithStackTraces(); } else { textArea.setText(""); buf = new StringBuffer(); }*/ } public void appendText(String s, boolean outNotErr) { //if (verbose) oldOut.println("Console appendText " + outNotErr + " " + quote(s)); buf.append(s); du.trigger(); } } // Console static String sendToLocalBot(String bot, String text, Object... args) { text = format3(text, args); DialogIO channel = findBot(bot); if (channel == null) fail(quote(bot) + " not found"); try { channel.readLine(); print(bot + "> " + text); channel.sendLine(text); String s = channel.readLine(); print(bot + "< " + s); return s; } catch (Throwable e) { e.printStackTrace(); return null; } finally { channel.close(); } } static String sendToLocalBot(int port, String text, Object... args) { text = format3(text, args); DialogIO channel = talkTo(port); try { channel.readLine(); print(port + "> " + text); channel.sendLine(text); String s = channel.readLine(); print(port + "< " + s); return s; } catch (Throwable e) { e.printStackTrace(); return null; } finally { if (channel != null) channel.close(); } } static String getSnippetTitle(String id) { try { return loadPage(new URL("http://tinybrain.de:8080/tb-int/getfield.php?id=" + parseSnippetID(id) + "&field=title")); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static long now_virtualTime; static long now() { return now_virtualTime != 0 ? now_virtualTime : System.currentTimeMillis(); } static StringBuffer print_log = new StringBuffer(); static void print() { print(""); } static void print(Object o) { String s = String.valueOf(o) + "\n"; print_log.append(s); System.out.print(s); } static void print(long l) { print(String.valueOf(l)); } public static boolean isSnippetID(String s) { try { parseSnippetID(s); return true; } catch (RuntimeException e) { return false; } } public static String join(String glue, Iterable strings) { StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String[] strings) { return join(glue, Arrays.asList(strings)); } public static String join(Iterable strings) { return join("", strings); } public static String join(String[] strings) { return join("", strings); } static int l(Object[] array) { return array == null ? 0 : array.length; } static int l(List list) { return list == null ? 0 : list.size(); } static int l(String s) { return s == null ? 0 : s.length(); } static String format3(String pat, Object... args) { if (args.length == 0) return pat; List tok = javaTokPlusPeriod(pat); int argidx = 0; for (int i = 1; i < tok.size(); i += 2) if (tok.get(i).equals("*")) tok.set(i, format3_formatArg(argidx < args.length ? args[argidx++] : "null")); return join(tok); } static String format3_formatArg(Object arg) { if (arg == null) return "null"; if (arg instanceof String) return quote((String) arg); return quote(structure(arg)); } static String quote(String s) { if (s == null) return "null"; return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\r", "\\r").replace("\n", "\\n") + "\""; } static String quote(long l) { return quote("" + l); } static Map findBot_cache = new TreeMap(); static int findBot_timeout = 5000; static DialogIO findBot(String searchPattern) { String subBot = null; int i = searchPattern.indexOf('/'); if (i >= 0 && (isJavaIdentifier(searchPattern.substring(0, i)) || isInteger(searchPattern.substring(0, i)))) { subBot = searchPattern.substring(i+1); searchPattern = searchPattern.substring(0, i); if (!isInteger(searchPattern)) searchPattern = "Multi-Port at " + searchPattern + "."; } // assume it's a port if it's an integer if (isInteger(searchPattern)) return talkToSubBot(subBot, talkTo(parseInt(searchPattern))); Integer port = findBot_cache.get(searchPattern); if (port != null) try { DialogIO io = talkTo("localhost", port); io.waitForLine(/*findBot_timeout*/); // TODO: implement String line = io.readLineNoBlock(); if (indexOfIgnoreCase(line, searchPattern) == 0) { call(io, "pushback", line); // put hello string back in return talkToSubBot(subBot, io); } } catch (Exception e) { e.printStackTrace(); } for (ProgramScan.Program p : quickBotScan()) if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) { // strict matching - start of hello string only, but case-insensitive findBot_cache.put(searchPattern, p.port); return talkToSubBot(subBot, talkTo("localhost", p.port)); } return null; } static abstract class DialogIO { abstract boolean isStillConnected(); abstract String readLineNoBlock(); abstract boolean waitForLine(); abstract void sendLine(String line); abstract boolean isLocalConnection(); abstract Socket getSocket(); abstract void close(); int getPort() { return getSocket().getPort(); } boolean helloRead; String readLine() { waitForLine(); helloRead = true; return readLineNoBlock(); } String ask(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); sendLine(s); return readLine(); } String askLoudly(String s, Object... args) { if (!helloRead) readLine(); if (args.length != 0) s = format3(s, args); print("> " + s); sendLine(s); String answer = readLine(); print("< " + answer); return answer; } } static abstract class DialogHandler { abstract void run(DialogIO io); } // DialogIO static DialogIO talkTo(int port) { return talkTo("localhost", port); } static DialogIO talkTo(String ip, int port) { try { final Socket s = new Socket(ip, port); print("Talking to " + ip + ":" + port); final Writer w = new OutputStreamWriter(s.getOutputStream(), "UTF-8"); final BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); return new DialogIO() { String line; boolean buff; boolean isLocalConnection() { return s.getInetAddress().isLoopbackAddress(); } boolean isStillConnected() { return !(buff || s.isClosed()); } String readLineNoBlock() { String l = line; line = null; return l; } boolean waitForLine() { try { if (line != null) return true; //print("Readline"); line = in.readLine(); //print("Readline done: " + line); if (line == null) buff = true; return line != null; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} void sendLine(String line) { try { w.write(line + "\n"); w.flush(); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} void close() { try { s.close(); } catch (IOException e) { // whatever } } Socket getSocket() { return s; } void pushback(String l) { if (line != null) fail(); line = l; } }; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} public static String loadPageSilently(String url) { try { return loadPageSilently(new URL(loadPage_preprocess(url))); } catch (IOException e) { throw new RuntimeException(e); } } public static String loadPageSilently(URL url) { try { IOException e = null; for (int tries = 0; tries < 5; tries++) try { URLConnection con = url.openConnection(); return loadPage(con, url); } catch (IOException _e) { e = _e; print("Retrying because of: " + e); } throw e; } catch (IOException e) { throw new RuntimeException(e); } } static String loadPage_preprocess(String url) { if (url.startsWith("tb/")) url = "tinybrain.de:8080/" + url; if (url.indexOf("://") < 0) url = "http://" + url; return url; } public static String loadPage(String url) { try { return loadPage(new URL(loadPage_preprocess(url))); } catch (IOException e) { throw new RuntimeException(e); } } public static String loadPage(URL url) { print("Loading: " + url.toExternalForm()); return loadPageSilently(url); } public static String loadPage(URLConnection con, URL url) throws IOException { String contentType = con.getContentType(); if (contentType == null) throw new IOException("Page could not be read: " + url); //Log.info("Content-Type: " + contentType); String charset = loadPage_guessCharset(contentType); Reader r = new InputStreamReader(con.getInputStream(), charset); StringBuilder buf = new StringBuilder(); while (true) { int ch = r.read(); if (ch < 0) break; //Log.info("Chars read: " + buf.length()); buf.append((char) ch); } return buf.toString(); } static String loadPage_guessCharset(String contentType) { Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*"); Matcher m = p.matcher(contentType); /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ return m.matches() ? m.group(1) : "ISO-8859-1"; } static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } public static long parseSnippetID(String snippetID) { long id = Long.parseLong(shortenSnippetID(snippetID)); if (id == 0) fail("0 is not a snippet ID"); return id; } static DialogIO talkToSubBot(final String subBot, final DialogIO io) { if (subBot == null) return io; return new DialogIO() { // delegate all but sendLine boolean isStillConnected() { return io.isStillConnected(); } String readLineNoBlock() { return io.readLineNoBlock(); } boolean waitForLine() { return io.waitForLine(); } boolean isLocalConnection() { return io.isLocalConnection(); } Socket getSocket() { return io.getSocket(); } void close() { io.close(); } void sendLine(String line) { io.sendLine(format3("please forward to bot *: *", subBot, line)); } }; } static Class include(String progID) { Class c = hotwire(progID); setOpt(c, "programID", getProgramID()); return c; } static class ProgramScan { static int threads = isWindows() ? 500 : 10; static int timeout = 5000; // hmm... static String ip = "127.0.0.1"; static int quickScanFrom = 10000, quickScanTo = 10999; static boolean verbose; static class Program { int port; String helloString; Program(int port, String helloString) { this.helloString = helloString; this.port = port;} } static List scan() { try { return scan(1, 65535); } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static List scan(int fromPort, int toPort) { return scan(fromPort, toPort, new int[0]); } static List scan(int fromPort, int toPort, int[] preferredPorts) { try { Set preferredPortsSet = new HashSet(asList(preferredPorts)); String name = toPort < 10000 ? "bot" : "program"; final ExecutorService es = Executors.newFixedThreadPool(threads); if (verbose) print(firstToUpper(name) + "-scanning " + ip + " with timeout " + timeout + " ms in " + threads + " threads."); startTiming(); List> futures = new ArrayList>(); for (int port : preferredPorts) futures.add(checkPort(es, ip, port, timeout)); for (int port = fromPort; port <= toPort; port++) if (!preferredPortsSet.contains(port)) futures.add(checkPort(es, ip, port, timeout)); es.shutdown(); List programs = new ArrayList(); for (final Future f : futures) { Program p = f.get(); if (p != null) programs.add(p); } stopTiming(); if (verbose) print("Found " + programs.size() + " " + name + "(s) on " + ip); return programs; } catch (Throwable __e) { throw __e instanceof RuntimeException ? (RuntimeException) __e : new RuntimeException(__e); }} static Future checkPort(final ExecutorService es, final String ip, final int port, final int timeout) { return es.submit(new Callable() { @Override public Program call() { try { Socket socket = new Socket(); socket.setSoTimeout(timeout); socket.connect(new InetSocketAddress(ip, port), timeout); if (verbose) print("Connected to " + ip + ":" + port); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream(), "UTF-8")); String hello = in.readLine(); socket.close(); return new Program(port, hello); } catch (Exception ex) { return null; } } }); } static List quickScan() { return scan(quickScanFrom, quickScanTo); } static List quickBotScan() { return quickBotScan(new int[0]); } static List quickBotScan(int[] preferredPorts) { return scan(4990, 5999, preferredPorts); } } // ProgramScan static List quickBotScan() { return ProgramScan.quickBotScan(); } static List quickBotScan(int[] preferredPorts) { return ProgramScan.quickBotScan(preferredPorts); } static List quickBotScan(String searchPattern) { List l = new ArrayList(); for (ProgramScan.Program p : ProgramScan.quickBotScan()) if (indexOfIgnoreCase(p.helloString, searchPattern) == 0) l.add(p); return l; } static boolean isJavaIdentifier(String s) { if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i < s.length(); i++) if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; return true; } static int parseInt(String s) { return Integer.parseInt(s); } // This is made for NL parsing. // It's javaTok extended with "..." token, "$n" and "#n" static List javaTokPlusPeriod(String s) { List tok = new ArrayList(); int l = s.length(); int i = 0; while (i < l) { int j = i; char c; String cc; // scan for whitespace while (j < l) { c = s.charAt(j); cc = s.substring(j, Math.min(j+2, l)); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (cc.equals("/*")) { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (cc.equals("//")) { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(s.substring(i, j)); i = j; if (i >= l) break; c = s.charAt(i); cc = s.substring(i, Math.min(i+2, l)); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener) { ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && (Character.isJavaIdentifierPart(s.charAt(j)) || s.charAt(j) == '\'')); // for things like "this one's" else if (Character.isDigit(c)) do ++j; while (j < l && Character.isDigit(s.charAt(j))); else if (cc.equals("[[")) { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else if (s.substring(j, Math.min(j+3, l)).equals("...")) j += 3; else if (c == '$' || c == '#') do ++j; while (j < l && Character.isDigit(s.charAt(j))); else ++j; tok.add(s.substring(i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static Object call(Object o, String method, Object... args) { try { if (o instanceof Class) { Method m = call_findStaticMethod((Class) o, method, args, false); m.setAccessible(true); return m.invoke(null, args); } else { Method m = call_findMethod(o, method, args, false); m.setAccessible(true); return m.invoke(o, args); } } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + _c.getName()); } static Method call_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && call_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName()); } private static boolean call_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static boolean isInteger(String s) { return Pattern.matches("\\-?\\d+", s); } static String structure(Object o) { return structure(o, 0); } // leave to false, unless unstructure() breaks static boolean structure_allowShortening = false; static String structure(Object o, int stringSizeLimit) { if (o == null) return "null"; String name = o.getClass().getName(); StringBuilder buf = new StringBuilder(); if (o instanceof Collection) { // TODO: store the type (e.g. HashSet/TreeSet) for (Object x : (Collection) o) { if (buf.length() != 0) buf.append(", "); buf.append(structure(x, stringSizeLimit)); } return "[" + buf + "]"; } if (o instanceof Map) { for (Object e : ((Map) o).entrySet()) { if (buf.length() != 0) buf.append(", "); buf.append(structure(((Map.Entry) e).getKey(), stringSizeLimit)); buf.append("="); buf.append(structure(((Map.Entry) e).getValue(), stringSizeLimit)); } return "{" + buf + "}"; } if (o.getClass().isArray()) { int n = Array.getLength(o); for (int i = 0; i < n; i++) { if (buf.length() != 0) buf.append(", "); buf.append(structure(Array.get(o, i), stringSizeLimit)); } return "array{" + buf + "}"; } if (o instanceof String) return quote(stringSizeLimit != 0 ? shorten((String) o, stringSizeLimit) : (String) o); if (o instanceof Class) return "class(" + quote(((Class) o).getName()) + ")"; if (o instanceof Throwable) return "exception(" + quote(((Throwable) o).getMessage()) + ")"; // Need more cases? This should cover all library classes... if (name.startsWith("java.") || name.startsWith("javax.")) return String.valueOf(o); String shortName = o.getClass().getName().replaceAll("^main\\$", ""); int numFields = 0; String fieldName = ""; if (shortName.equals("DynamicObject")) { shortName = (String) get(o, "className"); Map fieldValues = (Map) get(o, "fieldValues"); for (String _fieldName : fieldValues.keySet()) { fieldName = _fieldName; Object value = fieldValues.get(fieldName); if (value != null) { if (buf.length() != 0) buf.append(", "); buf.append(fieldName + "=" + structure(value, stringSizeLimit)); } ++numFields; } } else { // regular class // TODO: go to superclasses too Field[] fields = o.getClass().getDeclaredFields(); for (Field field : fields) { if ((field.getModifiers() & Modifier.STATIC) != 0) continue; Object value; try { field.setAccessible(true); value = field.get(o); } catch (Exception e) { value = "?"; } fieldName = field.getName(); // put special cases here... if (value != null) { if (buf.length() != 0) buf.append(", "); buf.append(fieldName + "=" + structure(value, stringSizeLimit)); } ++numFields; } } String b = buf.toString(); if (numFields == 1 && structure_allowShortening) b = b.replaceAll("^" + fieldName + "=", ""); // drop field name if only one String s = shortName; if (buf.length() != 0) s += "(" + b + ")"; return s; } // works on lists and strings and null static int indexOfIgnoreCase(Object a, Object b) { if (a == null) return -1; if (a instanceof String) { Matcher m = Pattern.compile((String) b, Pattern.CASE_INSENSITIVE + Pattern.LITERAL).matcher((String) a); if (m.find()) return m.start(); else return -1; } if (a instanceof List) { for (int i = 0; i < ((List) a).size(); i++) { Object o = ((List) a).get(i); if (o != null && ((String) o).equalsIgnoreCase((String) b)) return i; } return -1; } throw fail("Unknown type: " + a); } static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return snippetID; } static String programID; static String getProgramID() { return programID; } // extended over Class.isInstance() to handle primitive types static boolean isInstanceX(Class type, Object arg) { if (type == boolean.class) return arg instanceof Boolean; if (type == int.class) return arg instanceof Integer; if (type == long.class) return arg instanceof Long; if (type == float.class) return arg instanceof Float; if (type == short.class) return arg instanceof Short; if (type == char.class) return arg instanceof Character; if (type == byte.class) return arg instanceof Byte; return type.isInstance(arg); } static void setOpt(Object o, String field, Object value) { if (o instanceof Class) setOpt((Class) o, field, value); else try { Field f = setOpt_findField(o.getClass(), field); if (f == null) return; f.setAccessible(true); f.set(o, value); } catch (Exception e) { throw new RuntimeException(e); } } static void setOpt(Class c, String field, Object value) { try { Field f = setOpt_findStaticField(c, field); if (f == null) return; f.setAccessible(true); f.set(null, value); } catch (Exception e) { throw new RuntimeException(e); } } static Field setOpt_findField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field)) return f; return null; } static Field setOpt_findStaticField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) return f; return null; } // compile JavaX source, load classes & return main class // src can be a snippet ID or actual source code // TODO: record injection? static Class hotwire(String src) { try { Class j = getJavaX(); synchronized(j) { // hopefully this goes well... List libraries = new ArrayList(); File srcDir = (File) call(j, "transpileMain", src, libraries); if (srcDir == null) fail("transpileMain returned null (src=" + quote(src) + ")"); Object androidContext = get(j, "androidContext"); if (androidContext != null) return (Class) call(j, "loadx2android", srcDir, src); File classesDir = (File) call(j, "TempDirMaker_make"); String javacOutput = (String) call(j, "compileJava", srcDir, libraries, classesDir); System.out.println(javacOutput); URL[] urls = new URL[libraries.size()+1]; urls[0] = classesDir.toURI().toURL(); for (int i = 0; i < libraries.size(); i++) urls[i+1] = libraries.get(i).toURI().toURL(); // make class loader URLClassLoader classLoader = new URLClassLoader(urls); // load & return main class Class theClass = classLoader.loadClass("main"); call(j, "setVars", theClass, isSnippetID(src) ? src: null); if (isSnippetID(src)) callOpt(j, "addInstance", src, theClass); return theClass; } } catch (Exception e) { throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); } } static Object get(Object o, String field) { if (o instanceof Class) return get((Class) o, field); try { Field f = get_findField(o.getClass(), field); f.setAccessible(true); return f.get(o); } catch (Exception e) { throw new RuntimeException(e); } } static Object get(Class c, String field) { try { Field f = get_findStaticField(c, field); f.setAccessible(true); return f.get(null); } catch (Exception e) { throw new RuntimeException(e); } } static Field get_findStaticField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0) return f; throw new RuntimeException("Static field '" + field + "' not found in " + c.getName()); } static Field get_findField(Class c, String field) { for (Field f : c.getDeclaredFields()) if (f.getName().equals(field)) return f; throw new RuntimeException("Field '" + field + "' not found in " + c.getName()); } static String shorten(String s, int max) { return s.length() <= max ? s : s.substring(0, Math.min(s.length(), max)) + "..."; } static int max(int a, int b) { return Math.max(a, b); } static String programID() { return getProgramID(); } static Object callOpt(Object o, String method, Object... args) { try { if (o instanceof Class) { Method m = callOpt_findStaticMethod((Class) o, method, args, false); if (m == null) return null; m.setAccessible(true); return m.invoke(null, args); } else { Method m = callOpt_findMethod(o, method, args, false); if (m == null) return null; m.setAccessible(true); return m.invoke(o, args); } } catch (Exception e) { throw new RuntimeException(e); } } static Method callOpt_findStaticMethod(Class c, String method, Object[] args, boolean debug) { Class _c = c; while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (!m.getName().equals(method)) { if (debug) System.out.println("Method name mismatch: " + method); continue; } if ((m.getModifiers() & Modifier.STATIC) == 0 || !callOpt_checkArgs(m, args, debug)) continue; return m; } c = c.getSuperclass(); } return null; } static Method callOpt_findMethod(Object o, String method, Object[] args, boolean debug) { Class c = o.getClass(); while (c != null) { for (Method m : c.getDeclaredMethods()) { if (debug) System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");; if (m.getName().equals(method) && callOpt_checkArgs(m, args, debug)) return m; } c = c.getSuperclass(); } return null; } private static boolean callOpt_checkArgs(Method m, Object[] args, boolean debug) { Class[] types = m.getParameterTypes(); if (types.length != args.length) { if (debug) System.out.println("Bad parameter length: " + args.length + " vs " + types.length); return false; } for (int i = 0; i < types.length; i++) if (!(args[i] == null || isInstanceX(types[i], args[i]))) { if (debug) System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]); return false; } return true; } static Class __javax; static Class getJavaX() { return __javax; } static String firstToUpper(String s) { if (s.length() == 0) return s; return Character.toUpperCase(s.charAt(0)) + s.substring(1); } static BufferedReader readLine_reader; static String readLine() { return (String) call(getJavaX(), "readLine"); } static ArrayList asList(A[] a) { return new ArrayList(Arrays.asList(a)); } static ArrayList asList(int[] a) { ArrayList l = new ArrayList(); for (int i : a) l.add(i); return l; } static ArrayList asList(Set s) { return new ArrayList(s); } public static boolean isWindows() { return System.getProperty("os.name").contains("Windows"); } static long startTiming_startTime; static void startTiming() { startTiming_startTime = now(); } static void stopTiming() { long end = now(); print("Time: " + (end-startTiming_startTime) + " ms"); } }