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.SyntaxException;
029import org.crsh.console.KeyHandler;
030import org.crsh.shell.impl.command.InvocationContextImpl;
031import org.crsh.shell.impl.command.spi.CommandCreationException;
032
033import java.io.IOException;
034import java.lang.reflect.UndeclaredThrowableException;
035
036/**
037* @author Julien Viet
038*/
039class ProducerCommandImpl<T extends BaseCommand, P> extends CommandImpl<T, Void, P> {
040
041  private final CommandInvoker<Instance<T>, ?> invoker;
042  private final Class<P> producedType;
043
044  public ProducerCommandImpl(ShellCommandImpl<T> shellCommand, CommandInvoker<Instance<T>, ?> invoker, Class<P> producedType) {
045    super(shellCommand);
046
047    //
048    this.invoker = invoker;
049    this.producedType = producedType;
050  }
051
052  @Override
053  public InvocationMatch<?> getMatch() {
054    return invoker.getMatch();
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 CommandCreationException {
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) throws IOException {
107        // Drop everything
108      }
109
110      public void flush() throws IOException {
111      }
112
113      public void close() throws IOException, UndeclaredThrowableException {
114
115        //
116        Object 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        //
127        if (ret != null && producedType.isInstance(ret)) {
128          P produced = producedType.cast(ret);
129          invocationContext.provide(produced);
130        }
131
132        //
133        invocationContext.flush();
134        invocationContext.close();
135        command.unmatched = null;
136        invocationContext = null;
137      }
138    };
139  }
140}