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.shell.impl.command.pipeline;
020
021import org.crsh.command.CommandContext;
022import org.crsh.shell.impl.command.spi.CommandException;
023import org.crsh.stream.Consumer;
024import org.crsh.stream.Producer;
025import org.crsh.text.Screenable;
026import org.crsh.text.ScreenContext;
027import org.crsh.shell.impl.command.spi.CommandInvoker;
028import org.crsh.text.CLS;
029import org.crsh.text.ScreenContextConsumer;
030import org.crsh.text.Style;
031
032import java.io.IOException;
033import java.lang.reflect.UndeclaredThrowableException;
034import java.util.Map;
035
036/** @author Julien Viet */
037class CommandInvokerAdapter<C, P, CONSUMER extends CommandContext<? super P>>
038    implements Consumer<Object>, Producer<P, CONSUMER>, CommandContext<Object> {
039
040  /** . */
041  final CommandInvoker<C, P> command;
042
043  /** . */
044  protected CONSUMER consumer;
045
046  /** . */
047  private final Class<C> consumedType;
048
049  /** . */
050  private final Class<P> producedType;
051
052  /** . */
053  private ScreenContextConsumer adapter;
054
055  /** . */
056  private ScreenContext screenContext;
057
058  /** . */
059  private final boolean charSequenceConsumer;
060
061  /** . */
062  private final boolean styleConsumer;
063
064  /** . */
065  private final boolean clsConsumer;
066
067  CommandInvokerAdapter(CommandInvoker<C, P> command, Class<C> consumedType, Class<P> producedType) {
068    this.consumedType = consumedType;
069    this.producedType = producedType;
070    this.consumer = null;
071    this.command = command;
072    this.screenContext = null;
073    this.charSequenceConsumer = consumedType.isAssignableFrom(CharSequence.class);
074    this.styleConsumer = consumedType.isAssignableFrom(Style.class);
075    this.clsConsumer = consumedType.isAssignableFrom(CLS.class);
076  }
077
078  public boolean takeAlternateBuffer() throws IOException {
079    return consumer.takeAlternateBuffer();
080  }
081
082  public boolean releaseAlternateBuffer() throws IOException {
083    return consumer.releaseAlternateBuffer();
084  }
085
086  public String getProperty(String propertyName) {
087    return consumer.getProperty(propertyName);
088  }
089
090  public String readLine(String msg, boolean echo) throws IOException, InterruptedException {
091    return consumer.readLine(msg, echo);
092  }
093
094  public Map<String, Object> getSession() {
095    return consumer.getSession();
096  }
097
098  public Map<String, Object> getAttributes() {
099    return consumer.getAttributes();
100  }
101
102  public int getWidth() {
103    return screenContext != null ? screenContext.getWidth() : consumer.getWidth();
104  }
105
106  public int getHeight() {
107    return screenContext != null ? screenContext.getHeight() : consumer.getHeight();
108  }
109
110  public void open(final CONSUMER consumer) throws Exception {
111
112    //
113    try {
114      command.open(consumer);
115    }
116    catch (CommandException e) {
117      Throwable cause = e.getCause();
118      if (cause instanceof Exception) {
119        throw (Exception)cause;
120      } else if (cause instanceof Error) {
121        throw (Error)cause;
122      } else {
123        throw new UndeclaredThrowableException(cause);
124      }
125    }
126
127    //
128    ScreenContext screenContext = command.getScreenContext();
129    ScreenContextConsumer adapter = screenContext != null ? new ScreenContextConsumer(screenContext) : null;
130
131    //
132    this.screenContext = screenContext;
133    this.adapter = adapter;
134    this.consumer = consumer;
135  }
136
137  @Override
138  public Class<Object> getConsumedType() {
139    return Object.class;
140  }
141
142  @Override
143  public Class<P> getProducedType() {
144    return producedType;
145  }
146
147  @Override
148  public void provide(Object element) throws Exception  {
149    if (adapter != null) {
150      adapter.provide(element);
151    }
152    if (consumedType.isInstance(element)) {
153      try {
154        command.provide(consumedType.cast(element));
155      }
156      catch (CommandException e) {
157        Throwable cause = e.getCause();
158        if (cause instanceof Exception) {
159          throw (Exception)cause;
160        } else if (cause instanceof Error) {
161          throw (Error)cause;
162        } else {
163          throw new UndeclaredThrowableException(cause);
164        }
165      }
166    }
167  }
168
169  @Override
170  public Appendable append(char c) throws IOException {
171    if (screenContext != null) {
172      screenContext.append(c);
173    }
174    if (charSequenceConsumer) {
175      try {
176        command.provide(consumedType.cast(Character.toString(c)));
177      }
178      catch (CommandException e) {
179        Throwable cause = e.getCause();
180        if (cause instanceof RuntimeException) {
181          throw (RuntimeException)cause;
182        } else if (cause instanceof Error) {
183          throw (Error)cause;
184        } else {
185          throw new UndeclaredThrowableException(cause);
186        }
187      }
188    }
189    return this;
190  }
191
192  @Override
193  public Appendable append(CharSequence s) throws IOException {
194    if (screenContext != null) {
195      screenContext.append(s);
196    }
197    if (charSequenceConsumer) {
198      try {
199        command.provide(consumedType.cast(s));
200      }
201      catch (CommandException e) {
202        Throwable cause = e.getCause();
203        if (cause instanceof RuntimeException) {
204          throw (RuntimeException)cause;
205        } else if (cause instanceof Error) {
206          throw (Error)cause;
207        } else {
208          throw new UndeclaredThrowableException(cause);
209        }
210      }
211    }
212    return this;
213  }
214
215  @Override
216  public Appendable append(CharSequence csq, int start, int end) throws IOException {
217    if (screenContext != null) {
218      screenContext.append(csq, start, end);
219    }
220    if (charSequenceConsumer) {
221      try {
222        command.provide(consumedType.cast(csq.subSequence(start, end)));
223      }
224      catch (CommandException e) {
225        Throwable cause = e.getCause();
226        if (cause instanceof RuntimeException) {
227          throw (RuntimeException)cause;
228        } else if (cause instanceof Error) {
229          throw (Error)cause;
230        } else {
231          throw new UndeclaredThrowableException(cause);
232        }
233      }
234    }
235    return this;
236  }
237
238  @Override
239  public Screenable append(Style style) throws IOException {
240    if (screenContext != null) {
241      screenContext.append(style);
242    }
243    if (styleConsumer) {
244      try {
245        command.provide(consumedType.cast(style));
246      }
247      catch (CommandException e) {
248        Throwable cause = e.getCause();
249        if (cause instanceof RuntimeException) {
250          throw (RuntimeException)cause;
251        } else if (cause instanceof Error) {
252          throw (Error)cause;
253        } else {
254          throw new UndeclaredThrowableException(cause);
255        }
256      }
257    }
258    return this;
259  }
260
261  @Override
262  public Screenable cls() throws IOException {
263    if (screenContext != null) {
264      screenContext.cls();
265    }
266    if (clsConsumer) {
267      try {
268        command.provide(consumedType.cast(CLS.INSTANCE));
269      }
270      catch (CommandException e) {
271        Throwable cause = e.getCause();
272        if (cause instanceof RuntimeException) {
273          throw (RuntimeException)cause;
274        } else if (cause instanceof Error) {
275          throw (Error)cause;
276        } else {
277          throw new UndeclaredThrowableException(cause);
278        }
279      }
280    }
281    return this;
282  }
283
284  public void flush() throws IOException {
285    if (adapter != null) {
286      adapter.flush();
287    }
288    command.flush();
289  }
290
291  public void close() throws Exception {
292    if (adapter != null) {
293      adapter.flush();
294    }
295    try {
296      command.close();
297    }
298    catch (CommandException e) {
299      Throwable cause = e.getCause();
300      if (cause instanceof Exception) {
301        throw (Exception)cause;
302      } else if (cause instanceof Error) {
303        throw (Error)cause;
304      } else {
305        throw new UndeclaredThrowableException(cause);
306      }
307    }
308  }
309}