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