All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.crsh.command.BaseShellCommand Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 eXo Platform SAS.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.crsh.command;

import org.crsh.cli.descriptor.CommandDescriptor;
import org.crsh.cli.impl.Delimiter;
import org.crsh.cli.impl.completion.CompletionException;
import org.crsh.cli.impl.completion.CompletionMatch;
import org.crsh.cli.impl.completion.CompletionMatcher;
import org.crsh.cli.impl.descriptor.HelpDescriptor;
import org.crsh.cli.impl.invocation.InvocationException;
import org.crsh.cli.impl.invocation.InvocationMatch;
import org.crsh.cli.impl.invocation.InvocationMatcher;
import org.crsh.cli.impl.invocation.Resolver;
import org.crsh.cli.impl.lang.CommandFactory;
import org.crsh.cli.spi.Completer;
import org.crsh.cli.spi.Completion;
import org.crsh.shell.ErrorType;
import org.crsh.util.TypeResolver;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Type;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

/** @author Julien Viet */
public class BaseShellCommand implements ShellCommand {

  /** . */
  private final Class clazz;

  /** . */
  private final CommandDescriptor descriptor;

  public BaseShellCommand(Class clazz) {

    //
    CommandFactory factory = new CommandFactory(getClass().getClassLoader());

    //
    this.clazz = clazz;
    this.descriptor = HelpDescriptor.create(factory.create(clazz));
  }

  public CommandDescriptor getDescriptor() {
    return descriptor;
  }

  public final CompletionMatch complete(RuntimeContext context, String line) throws CommandCreationException {

    // WTF
    CompletionMatcher analyzer = descriptor.completer("main");

    //
    CC command = createCommand();

    //
    Completer completer = command instanceof Completer ? (Completer)command : null;

    //
    command.context = context;
    try {
      return analyzer.match(completer, line);
    }
    catch (CompletionException e) {
      command.log.log(Level.SEVERE, "Error during completion of line " + line, e);
      return new CompletionMatch(Delimiter.EMPTY, Completion.create());
    }
    finally {
      command.context = null;
    }
  }

  public final String describe(String line, DescriptionFormat mode) {

    // WTF
    InvocationMatcher analyzer = descriptor.matcher("main");

    //
    InvocationMatch match;
    try {
      match = analyzer.parse(line);
    }
    catch (org.crsh.cli.SyntaxException e) {
      throw new SyntaxException(e.getMessage());
    }

    //
    try {
      switch (mode) {
        case DESCRIBE:
          return match.getDescriptor().getUsage();
        case MAN:
          StringWriter sw = new StringWriter();
          PrintWriter pw = new PrintWriter(sw);
          match.getDescriptor().printMan(pw);
          return sw.toString();
        case USAGE:
          StringWriter sw2 = new StringWriter();
          PrintWriter pw2 = new PrintWriter(sw2);
          match.getDescriptor().printUsage(pw2);
          return sw2.toString();
      }
    }
    catch (IOException e) {
      throw new AssertionError(e);
    }

    //
    return null;
  }

  public CommandInvoker resolveInvoker(Map options, String subordinate, Map subordinateOptions, List arguments) throws CommandCreationException {
    InvocationMatcher matcher = descriptor.matcher("main");

    //
    if (options != null && options.size() > 0) {
      for (Map.Entry option : options.entrySet()) {
        matcher = matcher.option(option.getKey(), Collections.singletonList(option.getValue()));
      }
    }

    //
    if (subordinate != null && subordinate.length() > 0) {
      matcher = matcher.subordinate(subordinate);

      // Minor : remove that and use same signature
      if (subordinateOptions != null && subordinateOptions.size() > 0) {
        for (Map.Entry option : subordinateOptions.entrySet()) {
          matcher = matcher.option(option.getKey(), Collections.singletonList(option.getValue()));
        }
      }
    }

    //
    InvocationMatch match = matcher.arguments(arguments != null ? arguments : Collections.emptyList());

    //
    return resolveInvoker(match);
  }

  public CommandInvoker resolveInvoker(String line) throws CommandCreationException {
    InvocationMatcher analyzer = descriptor.matcher("main");
    InvocationMatch match;
    try {
      match = analyzer.parse(line);
    }
    catch (org.crsh.cli.SyntaxException e) {
      throw new SyntaxException(e.getMessage());
    }
    return resolveInvoker(match);
  }

  public final CommandInvoker resolveInvoker(final InvocationMatch match) throws CommandCreationException {
    return resolveInvoker2(match);
  }

  private CommandInvoker resolveInvoker2(final InvocationMatch match) throws CommandCreationException {

    // Invoker
    org.crsh.cli.impl.invocation.CommandInvoker invoker = match.getInvoker();

    // Necessary...
    final CC command = createCommand();

    /** The resolver. */
    Resolver resolver = new Resolver() {
      public  T resolve(Class type) {
        if (type.equals(InvocationContext.class)) {
          return type.cast(command.peekContext());
        } else {
          return null;
        }
      }
    };

    // Do we have a pipe command or not ?
    if (PipeCommand.class.isAssignableFrom(invoker.getReturnType())) {
      org.crsh.cli.impl.invocation.CommandInvoker invoker2 = invoker;
      return getPipeCommandInvoker(invoker2, command, resolver);
    } else {

      // A priori it could be any class
      Class producedType = Object.class;

      // Override produced type from InvocationContext

if any Class[] parameterTypes = invoker.getParameterTypes(); for (int i = 0;i < parameterTypes.length;i++) { Class parameterType = parameterTypes[i]; if (InvocationContext.class.isAssignableFrom(parameterType)) { Type contextGenericParameterType = invoker.getGenericParameterTypes()[i]; producedType = TypeResolver.resolveToClass(contextGenericParameterType, InvocationContext.class, 0); break; } } // return getInvoker(invoker, command, producedType, resolver); } } private CC createCommand() throws CommandCreationException { CC command; try { command = clazz.newInstance(); } catch (Exception e) { String name = clazz.getSimpleName(); throw new CommandCreationException(name, ErrorType.INTERNAL, "Could not create command " + name + " instance", e); } return command; } private > CommandInvoker getPipeCommandInvoker( final org.crsh.cli.impl.invocation.CommandInvoker invoker, final CC instance, final Resolver resolver) { return new CommandInvoker() { /** . */ final Type ret = invoker.getGenericReturnType(); /** . */ final Class consumedType = (Class)TypeResolver.resolveToClass(ret, PipeCommand.class, 0); /** . */ final Class

producedType = (Class

)TypeResolver.resolveToClass(ret, PipeCommand.class, 1); PipeCommand real; public Class

getProducedType() { return producedType; } public Class getConsumedType() { return consumedType; } public void open(CommandContext consumer) { // Java is fine with that but not intellij.... CommandContext

consumer2 = (CommandContext

)consumer; open2(consumer2); } public void open2(final CommandContext

consumer) { // final InvocationContextImpl

invocationContext = new InvocationContextImpl

(consumer); // Push context instance.pushContext(invocationContext); // Set the unmatched part instance.unmatched = invoker.getMatch().getRest(); // PC ret; try { ret = invoker.invoke(resolver, instance); } catch (org.crsh.cli.SyntaxException e) { throw new SyntaxException(e.getMessage()); } catch (InvocationException e) { throw instance.toScript(e.getCause()); } // It's a pipe command if (ret != null) { real = ret; real.open(invocationContext); } } public void provide(C element) throws IOException { if (real != null) { real.provide(element); } } public void flush() throws IOException { if (real != null) { real.flush(); } else { instance.peekContext().flush(); } } public void close() throws IOException { if (real != null) { try { real.close(); } finally { instance.popContext(); } } else { InvocationContext context = instance.popContext(); context.close(); } instance.unmatched = null; } }; } private

CommandInvoker getInvoker( final org.crsh.cli.impl.invocation.CommandInvoker invoker, final CC instance, final Class

_producedType, final Resolver resolver) { return new CommandInvoker() { public Class

getProducedType() { return _producedType; } public Class getConsumedType() { return Void.class; } public void open(CommandContext consumer) { // Java is fine with that but not intellij.... CommandContext

consumer2 = (CommandContext

)consumer; open2(consumer2); } public void open2(final CommandContext

consumer) { // final InvocationContextImpl

invocationContext = new InvocationContextImpl

(consumer); // Push context instance.pushContext(invocationContext); // Set the unmatched part instance.unmatched = invoker.getMatch().getRest(); } public void provide(Void element) throws IOException { // Drop everything } public void flush() throws IOException { // peekContext().flush(); } public void close() throws IOException, UndeclaredThrowableException { // Object ret; try { ret = invoker.invoke(resolver, instance); } catch (org.crsh.cli.SyntaxException e) { throw new SyntaxException(e.getMessage()); } catch (InvocationException e) { throw instance.toScript(e.getCause()); } // if (ret != null) { instance.peekContext().getWriter().print(ret); } // InvocationContext context = instance.popContext(); context.flush(); context.close(); instance.unmatched = null; } }; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy