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