/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.command.internal.handlers; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Dictionary; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import de.rcenvironment.core.command.common.CommandException; import de.rcenvironment.core.command.spi.CommandContext; /** * A utility class that attempts to execute OSGi commands as if they were entered into the Equinox command console. * * To achieve this, all registered OSGi {@link CommandProvider} services are examined for matching command handlers methods (which are * named, by OSGi convention, as the command name prefixed with an underscore character). If a matching handler is found, it is invoked, and * the generated output is forwarded to the caller. * * @author Robert Mischke */ public class EquinoxConsoleCommandInvoker { private static final String MSG_ERROR_INVOKING_OSGI_COMMAND = "Error invoking OSGi command"; private final Log log = LogFactory.getLog(getClass()); /** * Attempts to execute the OSGi console command defined by the remaining tokens in the given {@link CommandContext}. See class * description for the general approach. * * @param context the {@link CommandContext} providing command tokens and receiving output * @throws CommandException if an error occurs during command execution */ public void execute(final CommandContext context) throws CommandException { final CommandInterpreter commandInterpreter = createCommandInterpreter(context); String osgiCommand = context.consumeNextToken(); if (osgiCommand == null || osgiCommand.isEmpty()) { throw CommandException.syntaxError("Missing OSGi command", context); } final BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext(); ServiceReference<?>[] refs; try { refs = bundleContext.getAllServiceReferences(CommandProvider.class.getName(), null); } catch (InvalidSyntaxException e) { log.error("Error getting service references", e); context.println("Internal error"); return; } final String commandMethodName = "_" + osgiCommand; boolean matched = false; for (ServiceReference<?> ref : refs) { final CommandProvider service = (CommandProvider) bundleContext.getService(ref); final Method[] methods = service.getClass().getMethods(); for (Method method : methods) { if (method.getName().equals(commandMethodName)) { invokeServiceMethod(service, method, commandInterpreter); matched = true; } } bundleContext.ungetService(ref); } if (!matched) { context.println("No matching OSGi command found. " + "(Note that built-in commands like \"info\" or \"help\" may not be accessible.)"); } } private void invokeServiceMethod(final CommandProvider service, Method method, final CommandInterpreter commandInterpreter) { try { method.invoke(service, commandInterpreter); } catch (RuntimeException e) { // TODO improve handling: generate console feedback as well? log.error(MSG_ERROR_INVOKING_OSGI_COMMAND, e); } catch (IllegalAccessException e) { log.error(MSG_ERROR_INVOKING_OSGI_COMMAND, e); } catch (InvocationTargetException e) { log.error(MSG_ERROR_INVOKING_OSGI_COMMAND, e); } } private static CommandInterpreter createCommandInterpreter(final CommandContext context) { return new CommandInterpreter() { private StringBuilder lineBuffer; @Override public void print(Object arg0) { if (lineBuffer == null) { lineBuffer = new StringBuilder(); } lineBuffer.append(arg0.toString()); } @Override public void println(Object arg0) { if (lineBuffer != null) { lineBuffer.append(arg0.toString()); context.println(lineBuffer.toString()); lineBuffer = null; } else { context.println(arg0); } } @Override public void println() { println(""); } @Override public void printStackTrace(Throwable arg0) { LogFactory.getLog(getClass()).warn("Unhandled printStackTrace output: " + arg0); } @Override @SuppressWarnings("rawtypes") public void printDictionary(Dictionary arg0, String arg1) { LogFactory.getLog(getClass()).warn("Unhandled printDictionary output: " + arg1); } @Override public void printBundleResource(Bundle arg0, String arg1) { LogFactory.getLog(getClass()).warn("Unhandled printBundleResource output: " + arg1); } @Override public String nextArgument() { return context.consumeNextToken(); } @Override public Object execute(String arg0) { return null; } }; } }