001    /*
002     * Copyright (C) 2010 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.shell.impl;
021    
022    import org.crsh.command.CommandInvoker;
023    import org.crsh.command.ShellCommand;
024    import org.crsh.shell.ShellResponse;
025    import org.crsh.shell.ShellProcessContext;
026    
027    import java.util.ArrayList;
028    import java.util.regex.Pattern;
029    
030    /**
031     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
032     * @version $Revision$
033     */
034    abstract class AST {
035    
036      abstract Term lastTerm();
037    
038      static class Expr extends AST {
039    
040        /** . */
041        final Term term;
042    
043        /** . */
044        final Expr next;
045    
046        Expr(Term term) {
047          this.term = term;
048          this.next = null;
049        }
050    
051        Expr(Term term, Expr next) {
052          this.term = term;
053          this.next = next;
054        }
055    
056        final CRaSHProcess create(CRaSHSession crash, String request) throws CreateCommandException {
057          term.create(crash);
058          if (next != null) {
059            next.create(crash);
060          }
061          return new CRaSHProcess(crash, request) {
062            @Override
063            ShellResponse doInvoke(ShellProcessContext context) throws InterruptedException {
064              return Expr.this.execute(crash, context, null);
065            }
066          };
067        }
068    
069        private void create(CRaSHSession crash) throws CreateCommandException {
070          term.create(crash);
071          if (next != null) {
072            next.create(crash);
073          }
074        }
075    
076        protected ShellResponse execute(CRaSHSession crash, ShellProcessContext context, ArrayList consumed) throws InterruptedException {
077    
078          // What will be produced by this expression
079          ArrayList produced = new ArrayList();
080    
081          //
082          StringBuilder out = new StringBuilder();
083    
084          // Iterate over all terms
085          for (Term current = term;current != null;current = current.next) {
086    
087            // Build command context
088            InvocationContextImpl ctx;
089            if (current.invoker.getConsumedType() == Void.class) {
090              ctx = new InvocationContextImpl(context, null, crash.attributes);
091            } else {
092              // For now we assume we have compatible consumed/produced types
093              ctx = new InvocationContextImpl(context, consumed, crash.attributes);
094            }
095    
096            //
097            try {
098              current.invoker.invoke(ctx);
099            } catch (InterruptedException e) {
100              throw e;
101            } catch (Throwable t) {
102              return ShellResponse.internalError(t);
103            }
104    
105            // Append anything that was in the buffer
106            if (ctx.getBuffer() != null) {
107              out.append(ctx.getBuffer().toString());
108            }
109    
110            // Append produced if possible
111            if (current.invoker.getProducedType() == Void.class) {
112              // Do nothing
113            } else {
114              produced.addAll(ctx.getProducedItems());
115            }
116          }
117    
118          //
119          if (next != null) {
120            return next.execute(crash, context, produced);
121          } else {
122            ShellResponse response;
123            if (out.length() > 0) {
124              response = ShellResponse.display(produced, out.toString());
125            } else {
126              response = ShellResponse.ok(produced);
127            }
128            return response;
129          }
130        }
131    
132        @Override
133        Term lastTerm() {
134          if (next != null) {
135            return next.lastTerm();
136          }
137          if (term != null) {
138            return term.lastTerm();
139          }
140          return null;
141        }
142      }
143    
144      static class Term extends AST {
145    
146        /** . */
147        final String line;
148    
149        /** . */
150        final Term next;
151    
152        /** . */
153        final String name;
154    
155        /** . */
156        final String rest;
157    
158        /** . */
159        private ShellCommand command;
160    
161        /** . */
162        private CommandInvoker invoker;
163    
164        Term(String line) {
165          this(line, null);
166        }
167    
168        Term(String line, Term next) {
169    
170          Pattern p = Pattern.compile("^\\s*(\\S+)");
171          java.util.regex.Matcher m = p.matcher(line);
172          String name = null;
173          String rest = null;
174          if (m.find()) {
175            name = m.group(1);
176            rest = line.substring(m.end());
177          }
178    
179          //
180          this.name = name;
181          this.rest = rest;
182          this.line = line;
183          this.next = next;
184        }
185    
186        private void create(CRaSHSession crash) throws CreateCommandException {
187          CommandInvoker invoker = null;
188          if (name != null) {
189            command = crash.getCommand(name);
190            if (command != null) {
191              invoker = command.createInvoker(rest);
192            }
193          }
194    
195          //
196          if (invoker == null) {
197            throw new CreateCommandException(ShellResponse.unknownCommand(name));
198          } else {
199            this.invoker = invoker;
200          }
201    
202          //
203          if (next != null) {
204            next.create(crash);
205          }
206        }
207    
208        String getLine() {
209          return line;
210        }
211    
212        @Override
213        Term lastTerm() {
214          if (next != null) {
215            return next.lastTerm();
216          } else {
217            return this;
218          }
219        }
220      }
221    }