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 boolean takeAlternateBuffer() {
081            return false;
082          }
083    
084          public boolean releaseAlternateBuffer() {
085            return false;
086          }
087    
088          public RenderPrintWriter getWriter() {
089            return ctx.getWriter();
090          }
091    
092          public Map<String, Object> getSession() {
093            return ctx.getSession();
094          }
095    
096          public Map<String, Object> getAttributes() {
097            return ctx.getAttributes();
098          }
099    
100          public int getWidth() {
101            return ctx.getWidth();
102          }
103    
104          public int getHeight() {
105            return ctx.getHeight();
106          }
107    
108          public String getProperty(String propertyName) {
109            return ctx.getProperty(propertyName);
110          }
111    
112          public String readLine(String msg, boolean echo) {
113            return null;
114          }
115    
116          public Class getConsumedType() {
117            return Object.class;
118          }
119    
120          public void provide(Object element) throws IOException {
121            Renderable current = Renderable.getRenderable(element.getClass());
122            if (current == null) {
123              current = Renderable.ANY;
124            }
125            if (current != null) {
126              if (renderable != null && !current.equals(renderable)) {
127                flush();
128              }
129              buffer.addLast(element);
130              renderable = current;
131            }
132          }
133    
134          public void flush() throws IOException {
135            // We don't really flush, we just compute renderables from the buffer
136            if (buffer.size() > 0) {
137              Renderer i = renderable.renderer(buffer.iterator());
138              buffer.clear();
139              renderers.add(i);
140            }
141          }
142        };
143    
144        if (cmd instanceof CRaSHCommand) {
145          ((CRaSHCommand)cmd).pushContext(nested);
146        } else {
147          ((GroovyScriptCommand)cmd).pushContext(nested);
148        }
149        try {
150          closure.call();
151        }
152        finally {
153          if (cmd instanceof CRaSHCommand) {
154            ((CRaSHCommand)cmd).popContext();
155          } else {
156            ((GroovyScriptCommand)cmd).popContext();
157          }
158        }
159    
160        // Be sure to flush
161        try {
162          nested.flush();
163        }
164        catch (IOException e) {
165          e.printStackTrace();
166        }
167    
168        //
169        return Renderer.vertical(renderers);
170      }
171    }