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.java;
020    
021    import org.crsh.cli.impl.invocation.CommandInvoker;
022    import org.crsh.cli.impl.invocation.InvocationException;
023    import org.crsh.cli.impl.invocation.InvocationMatch;
024    import org.crsh.cli.impl.lang.Instance;
025    import org.crsh.command.BaseCommand;
026    import org.crsh.command.CommandContext;
027    import org.crsh.command.InvocationContext;
028    import org.crsh.command.Pipe;
029    import org.crsh.command.SyntaxException;
030    import org.crsh.console.KeyHandler;
031    import org.crsh.shell.impl.command.InvocationContextImpl;
032    import org.crsh.shell.impl.command.spi.CommandCreationException;
033    import org.crsh.util.Utils;
034    
035    import java.io.IOException;
036    import java.lang.reflect.Type;
037    
038    /**
039    * @author Julien Viet
040    */
041    class PipeCommandImpl<T extends BaseCommand, C, P, PC extends Pipe<C, P>> extends CommandImpl<T, C, P> {
042    
043      /** . */
044      final Type ret;
045    
046      /** . */
047      final Class<C> consumedType;
048    
049      /** . */
050      final Class<P> producedType;
051      private final CommandInvoker<Instance<T>, PC> invoker;
052    
053      public PipeCommandImpl(ShellCommandImpl<T> baseShellCommand, CommandInvoker<Instance<T>, PC> invoker) {
054        super(baseShellCommand);
055        this.invoker = invoker;
056        ret = invoker.getGenericReturnType();
057        consumedType = (Class<C>)Utils.resolveToClass(ret, Pipe.class, 0);
058        producedType = (Class<P>)Utils.resolveToClass(ret, Pipe.class, 1);
059      }
060    
061      @Override
062      public InvocationMatch<?> getMatch() {
063        return invoker.getMatch();
064      }
065    
066      @Override
067      public Class<P> getProducedType() {
068        return producedType;
069      }
070    
071      @Override
072      public Class<C> getConsumedType() {
073        return consumedType;
074      }
075    
076      @Override
077      BaseInvoker getInvoker(T command) throws CommandCreationException {
078    
079        //
080        return new BaseInvoker(command) {
081    
082          Pipe<C, P> real;
083          InvocationContext<P> invocationContext;
084    
085          public Class<P> getProducedType() {
086            return producedType;
087          }
088    
089          public Class<C> getConsumedType() {
090            return consumedType;
091          }
092    
093          public void open(CommandContext<? super P> consumer) {
094            // Java is fine with that but not intellij....
095            CommandContext<P> consumer2 = (CommandContext<P>)consumer;
096            open2(consumer2);
097          }
098    
099          @Override
100          public KeyHandler getKeyHandler() {
101            return command instanceof KeyHandler ? (KeyHandler)command : null;
102          }
103    
104          public void open2(final CommandContext<P> consumer) {
105    
106            //
107            invocationContext = new InvocationContextImpl<P>(consumer);
108    
109            // Push context
110            command.pushContext(invocationContext);
111    
112            //  Set the unmatched part
113            command.unmatched = invoker.getMatch().getRest();
114    
115            //
116            PC ret;
117            try {
118              ret = invoker.invoke(this);
119            }
120            catch (org.crsh.cli.SyntaxException e) {
121              throw new SyntaxException(e.getMessage());
122            } catch (InvocationException e) {
123              throw command.toScript(e.getCause());
124            }
125    
126            // It's a pipe command
127            if (ret != null) {
128              real = ret;
129              real.open(invocationContext);
130            }
131          }
132    
133          public void provide(C element) throws IOException {
134            if (real != null) {
135              real.provide(element);
136            }
137          }
138    
139          public void flush() throws IOException {
140            if (real != null) {
141              real.flush();
142            } else {
143              invocationContext.flush();
144            }
145          }
146    
147          public void close() throws IOException {
148            try {
149              if (real != null) {
150                try {
151                  real.close();
152                }
153                finally {
154                  Utils.close(invocationContext);
155                }
156              } else {
157                Utils.close(invocationContext);
158              }
159            }
160            finally {
161              command.popContext();
162              command.unmatched = null;
163            }
164          }
165        };
166      }
167    }