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