/******************************************************************************* * Copyright (c) 2008, 2010 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: * VMware Inc. - initial contribution *******************************************************************************/ package org.eclipse.virgo.shell.internal; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import org.eclipse.virgo.shell.Converter; import org.eclipse.virgo.shell.internal.converters.ConverterRegistry; import org.eclipse.virgo.shell.internal.parsing.ParsedCommand; import org.springframework.util.ReflectionUtils; /** * A <code>CommandInvoker</code> implementation that finds the command to invoke from a {@link CommandRegistry}. * <p /> * * <strong>Concurrent Semantics</strong><br /> * * Thread-safe. * */ final class CommandRegistryCommandInvoker implements CommandInvoker { private final CommandRegistry commandRegistry; private final ConverterRegistry converterRegistry; /** * @param commandRegistry * @param converterRegistry */ CommandRegistryCommandInvoker(CommandRegistry commandRegistry, ConverterRegistry converterRegistry) { this.commandRegistry = commandRegistry; this.converterRegistry = converterRegistry; } public List<String> invokeCommand(ParsedCommand command) throws CommandNotFoundException, ParametersMismatchException { List<CommandDescriptor> commands = commandsOfCommandName(this.commandRegistry, command.getCommand()); if (commands.isEmpty()) { throw new CommandNotFoundException(); } String[] arguments = command.getArguments(); String subcommandName = extractSubcommand(arguments); String[] subcommandArguments = extractSubcommandArguments(arguments); ParametersMismatchException lastException = null; for (CommandDescriptor commandDescriptor : commands) { List<String> objResult = null; String commandSubcommandName = commandDescriptor.getSubCommandName(); String commandString = commandDescriptor.getCommandName(); try { if (commandSubcommandName != null && !commandSubcommandName.equals("")) { if (isSubcommandMatch(commandSubcommandName, subcommandName)) { commandString += " " + subcommandName; objResult = attemptExecution(commandDescriptor, subcommandArguments); return objResult; } } else { objResult = attemptExecution(commandDescriptor, arguments); return objResult; } } catch (ParametersMismatchException e) { lastException = new ParametersMismatchException("Command " + commandString + ": " + e.getMessage()); } } if (lastException != null) { throw lastException; } throw new ParametersMismatchException("Command '" + command.getCommand() + "' expects a subcommand; try help vsh:" + command.getCommand()); } private static boolean isSubcommandMatch(String commandSubcommandName, String subcommandName) { if (subcommandName == null) { return false; } if (commandSubcommandName != null) { if (commandSubcommandName.equals(subcommandName)) { return true; } } return false; } private static String[] extractSubcommandArguments(String[] arguments) { if (arguments.length > 0) { String[] result = new String[arguments.length - 1]; System.arraycopy(arguments, 1, result, 0, result.length); return result; } return null; } private static String extractSubcommand(String[] arguments) { if (arguments.length > 0) { return arguments[0]; } return null; } @SuppressWarnings("unchecked") private List<String> attemptExecution(CommandDescriptor commandDescriptor, String[] arguments) throws ParametersMismatchException { Method method = commandDescriptor.getMethod(); Object[] convertedArguments = convertArguments(method, arguments); ReflectionUtils.makeAccessible(method); return (List<String>) ReflectionUtils.invokeMethod(method, commandDescriptor.getTarget(), convertedArguments); } private static List<CommandDescriptor> commandsOfCommandName(final CommandRegistry commandRegistry, final String commandName) { List<CommandDescriptor> commands = new ArrayList<CommandDescriptor>(); for (CommandDescriptor commandDescriptor : commandRegistry.getCommandDescriptors()) { if (commandDescriptor.getCommandName().equals(commandName)) { commands.add(commandDescriptor); } } return commands; } private Object[] convertArguments(final Method method, final String[] arguments) throws ParametersMismatchException { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length != arguments.length) { throw new ParametersMismatchException("Incorrect number of parameters"); } Object[] parameters = new Object[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { Object convertedParameter = convertArgument(arguments[i], parameterTypes[i]); if (convertedParameter != null) { parameters[i] = convertedParameter; } else { throw new ParametersMismatchException("Cannot convert parameter " + i + "."); } } return parameters; } private Object convertArgument(final String argument, Class<?> type) { Converter converter = this.converterRegistry.getConverter(type); if (converter == null) { return null; } try { return converter.convert(type, argument); } catch (Exception e) { return null; } } }