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 }