001/*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019package org.crsh.lang.impl.java;
020
021import org.crsh.cli.impl.invocation.CommandInvoker;
022import org.crsh.cli.impl.invocation.InvocationException;
023import org.crsh.cli.impl.lang.Instance;
024import org.crsh.command.BaseCommand;
025import org.crsh.command.CommandContext;
026import org.crsh.command.InvocationContext;
027import org.crsh.keyboard.KeyHandler;
028import org.crsh.shell.ErrorKind;
029import org.crsh.shell.impl.command.InvocationContextImpl;
030import org.crsh.shell.impl.command.spi.CommandException;
031
032import java.io.IOException;
033
034/**
035* @author Julien Viet
036*/
037class ProducerCommandMatch<T extends BaseCommand, P> extends BaseCommandMatch<T, Void, P> {
038
039  /** . */
040  private final CommandInvoker<Instance<T>, ?> invoker;
041
042  /** . */
043  private final Class<P> producedType;
044
045  /** . */
046  private final String name;
047
048  public ProducerCommandMatch(ClassShellCommand<T> shellCommand, CommandInvoker<Instance<T>, ?> invoker, Class<P> producedType) {
049    super(shellCommand);
050
051    //
052    this.invoker = invoker;
053    this.producedType = producedType;
054    this.name = shellCommand.getDescriptor().getName();
055  }
056
057  @Override
058  public Class<P> getProducedType() {
059    return producedType;
060  }
061
062  @Override
063  public Class<Void> getConsumedType() {
064    return Void.class;
065  }
066
067  @Override
068  BaseInvoker getInvoker(T command) throws CommandException {
069
070    //
071    return new BaseInvoker(command) {
072
073      /** . */
074      private InvocationContext<P> invocationContext;
075
076      public Class<P> getProducedType() {
077        return producedType;
078      }
079
080      public Class<Void> getConsumedType() {
081        return Void.class;
082      }
083
084      public void open(CommandContext<? super P> consumer) {
085        // Java is fine with that but not intellij....
086        CommandContext<P> consumer2 = (CommandContext<P>)consumer;
087        open2(consumer2);
088      }
089
090      public void open2(final CommandContext<P> consumer) {
091        invocationContext = new InvocationContextImpl<P>(consumer);
092        command.pushContext(invocationContext);
093        command.unmatched = invoker.getMatch().getRest();
094      }
095
096
097      @Override
098      public KeyHandler getKeyHandler() {
099        if (command instanceof KeyHandler) {
100          return (KeyHandler)command;
101        } else {
102          return null;
103        }
104      }
105
106      public void provide(Void element) {
107        // Drop everything
108      }
109
110      public void flush() {
111      }
112
113      public void close() throws IOException, CommandException {
114        try {
115          Object ret;
116          try {
117            ret = invoker.invoke(this);
118          }
119          catch (org.crsh.cli.impl.SyntaxException e) {
120            throw new CommandException(ErrorKind.SYNTAX, "Syntax exception when executing command " + name, e);
121          } catch (InvocationException e) {
122            throw new CommandException(ErrorKind.EVALUATION, "Command " + name + " failed", e.getCause());
123          }
124
125          // Anything returned compatible is then produced
126          if (ret != null && producedType.isInstance(ret)) {
127            P produced = producedType.cast(ret);
128            try {
129              invocationContext.provide(produced);
130            }
131            catch (Exception e) {
132              throw new CommandException(ErrorKind.EVALUATION, "Command " + name + " failed", e);
133            }
134          }
135        } finally {
136          try {
137            invocationContext.flush();
138          }
139          finally {
140            try {
141              invocationContext.close();
142            }
143            catch (Exception e) {
144              throw new CommandException(ErrorKind.EVALUATION, "Command " + name + " failed", e);
145            } finally {
146              command.unmatched = null;
147              invocationContext = null;
148            }
149          }
150        }
151      }
152    };
153  }
154}