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.impl.script;
021    
022    import org.crsh.shell.ErrorKind;
023    import org.crsh.shell.impl.command.ShellSession;
024    import org.crsh.shell.impl.command.spi.Command;
025    import org.crsh.shell.impl.command.spi.CommandException;
026    import org.crsh.shell.impl.command.spi.CommandInvoker;
027    import org.crsh.shell.impl.command.pipeline.PipeLine;
028    
029    import java.util.LinkedList;
030    import java.util.regex.Pattern;
031    
032    /**
033     * A factory for a pipeline.
034     */
035    public 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    }