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.text.ui;
021    
022    import groovy.lang.Closure;
023    import org.crsh.command.CRaSHCommand;
024    import org.crsh.command.CommandInvoker;
025    import org.crsh.command.GroovyScriptCommand;
026    import org.crsh.command.InvocationContext;
027    import org.crsh.command.ScriptException;
028    import org.crsh.text.RenderPrintWriter;
029    import org.crsh.text.Renderable;
030    import org.crsh.text.Renderer;
031    
032    import java.io.IOException;
033    import java.util.LinkedList;
034    import java.util.Map;
035    
036    public class EvalElement extends Element {
037    
038      /** The closure to evaluate. */
039      Closure closure;
040    
041      public Renderer renderer() {
042    
043        Object owner = closure.getOwner();
044    
045        //
046        final InvocationContext ctx;
047        Object cmd;
048        while (true) {
049          if (owner instanceof CRaSHCommand) {
050            cmd = owner;
051            ctx = ((CRaSHCommand)cmd).peekContext();
052            break;
053          } else if (owner instanceof GroovyScriptCommand) {
054            cmd = owner;
055            ctx = ((GroovyScriptCommand)cmd).peekContext();
056            break;
057          } else if (owner instanceof Closure) {
058            owner = ((Closure)owner).getOwner();
059          } else {
060            throw new UnsupportedOperationException("Cannot resolver owner " + owner + " to command");
061          }
062        }
063    
064        //
065        final LinkedList<Renderer> renderers = new LinkedList<Renderer>();
066    
067        //
068        final InvocationContext nested = new InvocationContext() {
069    
070          /** . */
071          private LinkedList<Object> buffer = new LinkedList<Object>();
072    
073          /** . */
074          private Renderable renderable;
075    
076          public CommandInvoker<?, ?> resolve(String s) throws ScriptException, IOException {
077            return ctx.resolve(s);
078          }
079    
080          public RenderPrintWriter getWriter() {
081            return ctx.getWriter();
082          }
083    
084          public Map<String, Object> getSession() {
085            return ctx.getSession();
086          }
087    
088          public Map<String, Object> getAttributes() {
089            return ctx.getAttributes();
090          }
091    
092          public int getWidth() {
093            return ctx.getWidth();
094          }
095    
096          public int getHeight() {
097            return ctx.getHeight();
098          }
099    
100          public String getProperty(String propertyName) {
101            return ctx.getProperty(propertyName);
102          }
103    
104          public String readLine(String msg, boolean echo) {
105            return null;
106          }
107    
108          public Class getConsumedType() {
109            return Object.class;
110          }
111    
112          public void provide(Object element) throws IOException {
113            Renderable current = Renderable.getRenderable(element.getClass());
114            if (current == null) {
115              current = Renderable.ANY;
116            }
117            if (current != null) {
118              if (renderable != null && !current.equals(renderable)) {
119                flush();
120              }
121              buffer.addLast(element);
122              renderable = current;
123            }
124          }
125    
126          public void flush() throws IOException {
127            // We don't really flush, we just compute renderables from the buffer
128            if (buffer.size() > 0) {
129              Renderer i = renderable.renderer(buffer.iterator());
130              buffer.clear();
131              renderers.add(i);
132            }
133          }
134        };
135    
136        if (cmd instanceof CRaSHCommand) {
137          ((CRaSHCommand)cmd).pushContext(nested);
138        } else {
139          ((GroovyScriptCommand)cmd).pushContext(nested);
140        }
141        try {
142          closure.call();
143        }
144        finally {
145          if (cmd instanceof CRaSHCommand) {
146            ((CRaSHCommand)cmd).popContext();
147          } else {
148            ((GroovyScriptCommand)cmd).popContext();
149          }
150        }
151    
152        // Be sure to flush
153        try {
154          nested.flush();
155        }
156        catch (IOException e) {
157          e.printStackTrace();
158        }
159    
160        //
161        return Renderer.vertical(renderers);
162      }
163    }