/******************************************************************************* * Copyright (c) 2007, 2009 SpringSource, a divison of VMware, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * SpringSource, a divison of VMware, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.virgo.ide.management.remote; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.util.Arrays; import java.util.Dictionary; import java.util.Enumeration; import java.util.StringTokenizer; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.eclipse.osgi.framework.internal.core.ConsoleMsg; import org.eclipse.osgi.framework.internal.core.Util; import org.eclipse.osgi.util.NLS; import org.osgi.framework.Bundle; /** * @author Christian Dupuis */ public class ServerCommandInterpreter implements CommandInterpreter { private static final String WS_DELIM = " \t\n\r\f"; //$NON-NLS-1$ /** The command line in StringTokenizer form */ private StringTokenizer tok; /** The active CommandProviders */ private Object[] commandProviders; /** Strings used to format other strings */ private String tab = "\t"; //$NON-NLS-1$ private String newline = "\r\n"; //$NON-NLS-1$ private PrintWriter out; public ServerCommandInterpreter(String cmdLine, Object[] commandProviders, PrintWriter writer) { this.commandProviders = commandProviders; this.tok = new StringTokenizer(cmdLine); this.out = writer; } /** * Get the next argument in the input. * * E.g. if the commandline is hello world, the _hello method will get "world" as the first argument. * * @return A string containing the next argument on the command line */ public String nextArgument() { if (tok == null || !tok.hasMoreElements()) return null; String arg = tok.nextToken(); if (arg.startsWith("\"")) { //$NON-NLS-1$ if (arg.endsWith("\"")) { //$NON-NLS-1$ if (arg.length() >= 2) // strip the beginning and ending quotes return arg.substring(1, arg.length() - 1); } String remainingArg = tok.nextToken("\""); //$NON-NLS-1$ arg = arg.substring(1) + remainingArg; // skip to next whitespace separated token tok.nextToken(WS_DELIM); } else if (arg.startsWith("'")) { //$NON-NLS-1$ //$NON-NLS-2$ if (arg.endsWith("'")) { //$NON-NLS-1$ if (arg.length() >= 2) // strip the beginning and ending quotes return arg.substring(1, arg.length() - 1); } String remainingArg = tok.nextToken("'"); //$NON-NLS-1$ arg = arg.substring(1) + remainingArg; // skip to next whitespace separated token tok.nextToken(WS_DELIM); } return arg; } /** * Execute a command line as if it came from the end user. * * Searches the list of command providers using introspection until it finds one that contains a matching method. It * searches for a method with the name "_cmd" where cmd is the command to execute. For example, for a command of * "launch" execute searches for a method called "_launch". * * @param cmd The name of the command to execute. * @return The object returned by the method executed. */ public Object execute(String cmd) { Object retval = null; Class[] parameterTypes = new Class[] { CommandInterpreter.class }; Object[] parameters = new Object[] { this }; boolean executed = false; int size = commandProviders.length; for (int i = 0; !executed && (i < size); i++) { try { Object target = commandProviders[i]; Method method = target.getClass().getMethod("_" + cmd, parameterTypes); //$NON-NLS-1$ retval = method.invoke(target, parameters); executed = true; // stop after the command has been found } catch (NoSuchMethodException ite) { // keep going - maybe another command provider will be able to // execute this command } catch (InvocationTargetException ite) { executed = true; // don't want to keep trying - we found the // method but got an error printStackTrace(ite.getTargetException()); } catch (Exception ee) { executed = true; // don't want to keep trying - we got an error // we don't understand printStackTrace(ee); } } // if no command was found to execute, display help for all registered // command providers if (!executed) { for (int i = 0; i < size; i++) { try { CommandProvider commandProvider = (CommandProvider) commandProviders[i]; out.print(commandProvider.getHelp()); out.flush(); } catch (Exception ee) { printStackTrace(ee); } } // call help for the more command provided by this class out.print(getHelp()); out.flush(); } return retval; } /** * Prints a string to the output medium (appended with newline character). * <p> * This method does not increment the line counter for the 'more' prompt. * * @param o the string to be printed */ private void printline(Object o) { print(o + newline); } /** * Prints an object to the outputstream * * @param o the object to be printed */ public void print(Object o) { synchronized (out) { out.print(o); out.flush(); } } /** * Prints a empty line to the outputstream */ public void println() { println(""); //$NON-NLS-1$ } /** * Print a stack trace including nested exceptions. * * @param t The offending exception */ public void printStackTrace(Throwable t) { t.printStackTrace(out); Method[] methods = t.getClass().getMethods(); int size = methods.length; Class throwable = Throwable.class; for (int i = 0; i < size; i++) { Method method = methods[i]; if (Modifier.isPublic(method.getModifiers()) && method.getName().startsWith("get") && throwable.isAssignableFrom(method.getReturnType()) && (method.getParameterTypes().length == 0)) { //$NON-NLS-1$ try { Throwable nested = (Throwable) method.invoke(t, null); if ((nested != null) && (nested != t)) { out.println(ConsoleMsg.CONSOLE_NESTED_EXCEPTION); printStackTrace(nested); } } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } } } } /** * Prints an object to the output medium (appended with newline character). * <p> * If running on the target environment, the user is prompted with '--more' if more than the configured number of * lines have been printed without user prompt. This enables the user of the program to have control over scrolling. * <p> * For this to work properly you should not embed "\n" etc. into the string. * * @param o the object to be printed */ public void println(Object o) { if (o == null) { return; } synchronized (out) { printline(o); } } /** * Prints the given dictionary sorted by keys. * * @param dic the dictionary to print * @param title the header to print above the key/value pairs */ public void printDictionary(Dictionary dic, String title) { if (dic == null) return; int count = dic.size(); String[] keys = new String[count]; Enumeration keysEnum = dic.keys(); int i = 0; while (keysEnum.hasMoreElements()) { keys[i++] = (String) keysEnum.nextElement(); } Util.sortByString(keys); if (title != null) { println(title); } for (i = 0; i < count; i++) { println(" " + keys[i] + " = " + dic.get(keys[i])); //$NON-NLS-1$//$NON-NLS-2$ } println(); } /** * Prints the given bundle resource if it exists * * @param bundle the bundle containing the resource * @param resource the resource to print */ public void printBundleResource(Bundle bundle, String resource) { URL entry = null; entry = bundle.getEntry(resource); if (entry != null) { try { println(resource); InputStream in = entry.openStream(); byte[] buffer = new byte[1024]; int read = 0; try { while ((read = in.read(buffer)) != -1) print(new String(buffer, 0, read)); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } } catch (Exception e) { System.err.println(NLS.bind(ConsoleMsg.CONSOLE_ERROR_READING_RESOURCE, resource)); } } else { println(NLS.bind(ConsoleMsg.CONSOLE_RESOURCE_NOT_IN_BUNDLE, resource, bundle.toString())); } } /** * Answer a string (may be as many lines as you like) with help texts that explain the command. */ public String getHelp() { StringBuffer help = new StringBuffer(256); help.append(ConsoleMsg.CONSOLE_HELP_CONTROLLING_CONSOLE_HEADING); help.append(newline); help.append(tab); help.append("more - "); //$NON-NLS-1$ help.append(ConsoleMsg.CONSOLE_HELP_MORE); help.append(newline); return help.toString(); } }