David Ostrovsky
2014-03-11 b799d545f37f7123aaa1ee1d0ff3b61f1f3cc8c2
src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -16,18 +16,24 @@
import java.io.IOException;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Provider;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.kohsuke.args4j.Argument;
import com.gitblit.git.GitblitReceivePackFactory;
import com.gitblit.git.GitblitUploadPackFactory;
import com.gitblit.git.RepositoryResolver;
import com.gitblit.transport.ssh.AbstractGitCommand;
import com.gitblit.transport.ssh.CommandMetaData;
import com.gitblit.transport.ssh.SshKeyAuthenticator;
import com.gitblit.transport.ssh.SshSession;
import com.gitblit.utils.cli.SubcommandHandler;
import com.google.common.base.Charsets;
import com.google.common.base.Strings;
@@ -42,28 +48,34 @@
  @Argument(index = 1, multiValued = true, metaVar = "ARG")
  private List<String> args = new ArrayList<String>();
  private Set<Provider<Command>> commands;
  private Map<String, Provider<Command>> map;
  private Set<Class<? extends Command>> commands;
  private Map<String, Class<? extends Command>> map;
  private Map<String, Command> root;
  public DispatchCommand() {}
  public DispatchCommand(Map<String, Provider<Command>> map) {
    this.map = map;
  public DispatchCommand() {
     commands = new HashSet<Class<? extends Command>>();
  }
  public void setMap(Map<String, Provider<Command>> m) {
    map = m;
  public void registerDispatcher(String name, Command cmd) {
     if (root == null) {
        root = Maps.newHashMap();
     }
     root.put(name, cmd);
  }
  public DispatchCommand(Set<Provider<Command>> commands) {
    this.commands = commands;
  public void registerCommand(Class<? extends Command> cmd) {
     if (!cmd.isAnnotationPresent(CommandMetaData.class)) {
        throw new RuntimeException(MessageFormat.format("{0} must be annotated with {1}!",
              cmd.getName(), CommandMetaData.class.getName()));
     }
     commands.add(cmd);
  }
  private Map<String, Provider<Command>> getMap() {
  private Map<String, Class<? extends Command>> getMap() {
    if (map == null) {
      map = Maps.newHashMapWithExpectedSize(commands.size());
      for (Provider<Command> cmd : commands) {
        CommandMetaData meta = cmd.get().getClass().getAnnotation(CommandMetaData.class);
      for (Class<? extends Command> cmd : commands) {
        CommandMetaData meta = cmd.getAnnotation(CommandMetaData.class);
        map.put(meta.name(), cmd);
      }
    }
@@ -80,15 +92,7 @@
        throw new UnloggedFailure(1, msg.toString());
      }
      final Provider<Command> p = getMap().get(commandName);
      if (p == null) {
        String msg =
            (getName().isEmpty() ? "Gitblit" : getName()) + ": "
                + commandName + ": not found";
        throw new UnloggedFailure(1, msg);
      }
      final Command cmd = p.get();
      Command cmd = getCommand();
      if (cmd instanceof BaseCommand) {
        BaseCommand bc = (BaseCommand) cmd;
        if (getName().isEmpty()) {
@@ -97,11 +101,11 @@
          bc.setName(getName() + " " + commandName);
        }
        bc.setArguments(args.toArray(new String[args.size()]));
      } else if (!args.isEmpty()) {
        throw new UnloggedFailure(1, commandName + " does not take arguments");
      }
      provideStateTo(cmd);
      provideBaseStateTo(cmd);
      provideGitState(cmd);
      reset();
      //atomicCmd.set(cmd);
      cmd.start(env);
@@ -116,6 +120,28 @@
    }
  }
  private Command getCommand() throws UnloggedFailure {
   if (root != null && root.containsKey(commandName)) {
      return root.get(commandName);
   }
   final Class<? extends Command> c = getMap().get(commandName);
      if (c == null) {
        String msg =
            (getName().isEmpty() ? "Gitblit" : getName()) + ": "
                + commandName + ": not found";
        throw new UnloggedFailure(1, msg);
      }
      Command cmd = null;
      try {
         cmd = c.newInstance();
      } catch (Exception e) {
         throw new UnloggedFailure(1, MessageFormat.format("Failed to instantiate {0} command", commandName));
      }
   return cmd;
  }
  @Override
  protected String usage() {
    final StringBuilder usage = new StringBuilder();
    usage.append("Available commands");
@@ -127,15 +153,15 @@
    usage.append("\n");
    int maxLength = -1;
    Map<String, Provider<Command>> m = getMap();
    Map<String, Class<? extends Command>> m = getMap();
    for (String name : m.keySet()) {
      maxLength = Math.max(maxLength, name.length());
    }
    String format = "%-" + maxLength + "s   %s";
    for (String name : Sets.newTreeSet(m.keySet())) {
      final Provider<Command> p = m.get(name);
      final Class<? extends Command> c = m.get(name);
      usage.append("   ");
      CommandMetaData meta = p.get().getClass().getAnnotation(CommandMetaData.class);
      CommandMetaData meta = c.getAnnotation(CommandMetaData.class);
      if (meta != null) {
        usage.append(String.format(format, name,
            Strings.nullToEmpty(meta.description())));
@@ -153,4 +179,48 @@
    usage.append("\n");
    return usage.toString();
  }
  // This is needed because we are not using provider or
  // clazz.newInstance() for DispatchCommand
  private void reset() {
     args = new ArrayList<String>();
  }
  private void provideGitState(Command cmd) {
     if (cmd instanceof AbstractGitCommand) {
      AbstractGitCommand a = (AbstractGitCommand) cmd;
      a.setRepositoryResolver(repositoryResolver);
      a.setUploadPackFactory(gitblitUploadPackFactory);
      a.setReceivePackFactory(gitblitReceivePackFactory);
     } else if (cmd instanceof DispatchCommand) {
      DispatchCommand d = (DispatchCommand)cmd;
      d.setRepositoryResolver(repositoryResolver);
      d.setUploadPackFactory(gitblitUploadPackFactory);
      d.setReceivePackFactory(gitblitReceivePackFactory);
      d.setAuthenticator(authenticator);
     } else if (cmd instanceof SetAccountCommand) {
        SetAccountCommand setAccountCommand = (SetAccountCommand)cmd;
        setAccountCommand.setAuthenticator(authenticator);
     }
  }
  private RepositoryResolver<SshSession> repositoryResolver;
  public void setRepositoryResolver(RepositoryResolver<SshSession> repositoryResolver) {
     this.repositoryResolver = repositoryResolver;
  }
  private GitblitUploadPackFactory<SshSession> gitblitUploadPackFactory;
  public void setUploadPackFactory(GitblitUploadPackFactory<SshSession> gitblitUploadPackFactory) {
     this.gitblitUploadPackFactory = gitblitUploadPackFactory;
  }
  private GitblitReceivePackFactory<SshSession> gitblitReceivePackFactory;
  public void setReceivePackFactory(GitblitReceivePackFactory<SshSession> gitblitReceivePackFactory) {
     this.gitblitReceivePackFactory = gitblitReceivePackFactory;
  }
  private SshKeyAuthenticator authenticator;
  public void setAuthenticator(SshKeyAuthenticator authenticator) {
   this.authenticator = authenticator;
  }
}