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    
020    package org.crsh.lang.script;
021    
022    import org.crsh.shell.impl.command.spi.CommandCreationException;
023    import org.crsh.shell.impl.command.spi.CommandInvoker;
024    import org.crsh.shell.impl.command.spi.ShellCommand;
025    import org.crsh.command.SyntaxException;
026    import org.crsh.repl.ReplSession;
027    import org.crsh.shell.impl.command.pipeline.PipeLine;
028    import org.crsh.shell.ErrorType;
029    import org.crsh.text.Chunk;
030    
031    import java.util.LinkedList;
032    import java.util.regex.Pattern;
033    
034    /**
035     * A factory for a pipeline.
036     */
037    public 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    }