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     */
019    package org.crsh.lang.impl.java;
020    
021    import org.crsh.cli.impl.invocation.CommandInvoker;
022    import org.crsh.cli.impl.invocation.InvocationException;
023    import org.crsh.cli.impl.lang.Instance;
024    import org.crsh.command.BaseCommand;
025    import org.crsh.command.CommandContext;
026    import org.crsh.command.InvocationContext;
027    import org.crsh.keyboard.KeyHandler;
028    import org.crsh.shell.ErrorKind;
029    import org.crsh.shell.impl.command.InvocationContextImpl;
030    import org.crsh.shell.impl.command.spi.CommandException;
031    
032    import java.io.IOException;
033    
034    /**
035    * @author Julien Viet
036    */
037    class 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    }