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
020package org.crsh.lang.script;
021
022import org.crsh.shell.impl.command.spi.CommandCreationException;
023import org.crsh.shell.impl.command.spi.CommandInvoker;
024import org.crsh.shell.impl.command.spi.ShellCommand;
025import org.crsh.command.SyntaxException;
026import org.crsh.repl.ReplSession;
027import org.crsh.shell.impl.command.pipeline.PipeLine;
028import org.crsh.shell.ErrorType;
029import org.crsh.text.Chunk;
030
031import java.util.LinkedList;
032import java.util.regex.Pattern;
033
034/**
035 * A factory for a pipeline.
036 */
037public class PipeLineFactory {
038
039  /** . */
040  private static final Pattern p = Pattern.compile("^\\s*(\\S+)");
041
042  /** . */
043  final String line;
044
045  /** . */
046  final String name;
047
048  /** . */
049  final String rest;
050
051  /** . */
052  final PipeLineFactory next;
053
054  /**
055   * Create a pipeline factory for the specified line and next factory
056   *
057   * @param line the line
058   * @param next the next factory
059   * @throws SyntaxException when the line is not correct
060   */
061  public PipeLineFactory(String line, PipeLineFactory next) throws SyntaxException {
062    java.util.regex.Matcher m = p.matcher(line);
063    if (m.find()) {
064      this.name = m.group(1);
065      this.rest = line.substring(m.end());
066      this.line = line;
067      this.next = next;
068    } else {
069      StringBuilder sb = new StringBuilder("syntax error near unexpected token");
070      if (next != null) {
071        sb.append(' ');
072        for (PipeLineFactory factory = next;factory != null;factory = factory.next) {
073          sb.append('|').append(factory.line);
074        }
075      }
076      throw new SyntaxException(sb.toString());
077    }
078  }
079
080  public String getLine() {
081    return line;
082  }
083
084  public PipeLineFactory getNext() {
085    return next;
086  }
087
088  public CommandInvoker<Void, Chunk> create(ReplSession session) throws CommandCreationException {
089    LinkedList<CommandInvoker> pipes = new LinkedList<CommandInvoker>();
090    for (PipeLineFactory current = this;current != null;current = current.next) {
091      ShellCommand<?> command = session.getCommand(current.name);
092      if (command == null) {
093        throw new CommandCreationException(current.name, ErrorType.EVALUATION, "Unknown command");
094      }
095      CommandInvoker commandInvoker = command.resolveInvoker(current.rest);
096      if (commandInvoker == null) {
097        throw new CommandCreationException(current.name, ErrorType.EVALUATION, "Command " + current.rest + " cannot not be invoked");
098      }
099      pipes.add(commandInvoker);
100    }
101    return new PipeLine(pipes.toArray(new CommandInvoker[pipes.size()]));
102  }
103
104  public PipeLineFactory getLast() {
105    if (next != null) {
106      return next.getLast();
107    }
108    return this;
109  }
110}