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.java;
020
021import org.crsh.cli.impl.invocation.CommandInvoker;
022import org.crsh.cli.impl.invocation.InvocationException;
023import org.crsh.cli.impl.invocation.InvocationMatch;
024import org.crsh.cli.impl.lang.Instance;
025import org.crsh.command.BaseCommand;
026import org.crsh.command.CommandContext;
027import org.crsh.command.InvocationContext;
028import org.crsh.command.Pipe;
029import org.crsh.command.SyntaxException;
030import org.crsh.console.KeyHandler;
031import org.crsh.shell.impl.command.InvocationContextImpl;
032import org.crsh.shell.impl.command.spi.CommandCreationException;
033import org.crsh.util.Utils;
034
035import java.io.IOException;
036import java.lang.reflect.Type;
037
038/**
039* @author Julien Viet
040*/
041class 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}