001: /*
002: * Copyright 2001-2007 Geert Bevin <gbevin[remove] at uwyn dot com>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: * $Id: Groovy2ElementInfo.java 3701 2007-03-18 12:24:23Z gbevin $
007: */
008: package com.uwyn.rife.engine;
009:
010: import com.uwyn.rife.config.RifeConfig;
011: import com.uwyn.rife.engine.exceptions.EngineException;
012: import com.uwyn.rife.engine.exceptions.NotFoundProcessingErrorException;
013: import com.uwyn.rife.engine.exceptions.ParsingErrorException;
014: import com.uwyn.rife.engine.exceptions.ProcessingErrorException;
015: import com.uwyn.rife.ioc.PropertyValueObject;
016: import com.uwyn.rife.resources.ResourceFinder;
017: import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException;
018: import com.uwyn.rife.tools.Convert;
019: import com.uwyn.rife.tools.InnerClassException;
020: import com.uwyn.rife.tools.InputStreamUser;
021: import groovy.lang.Binding;
022: import groovy.lang.GroovyClassLoader;
023: import groovy.lang.GroovyCodeSource;
024: import groovy.lang.Script;
025: import groovy.util.BuilderSupport;
026: import java.io.InputStream;
027: import java.net.URL;
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.Map;
031: import org.codehaus.groovy.control.CompilerConfiguration;
032: import org.codehaus.groovy.runtime.InvokerHelper;
033:
034: class Groovy2ElementInfo implements ElementInfoProcessor {
035: Groovy2ElementInfo() {
036: }
037:
038: public void processElementInfo(ElementInfoBuilder builder,
039: String declarationName, ResourceFinder resourceFinder)
040: throws EngineException {
041: GroovyProcessor processor = new GroovyProcessor(builder);
042:
043: String processed_path = null;
044: try {
045: // process the element declaration
046: try {
047: processed_path = declarationName;
048: processor.processGroovy(processed_path, resourceFinder);
049: } catch (NotFoundProcessingErrorException e) {
050: processed_path = DEFAULT_ELEMENTS_PATH
051: + declarationName;
052: processor.processGroovy(processed_path, resourceFinder);
053: }
054: } catch (Exception e) {
055: throw new ProcessingErrorException("element",
056: declarationName, e);
057: }
058:
059: // obtain the modification time
060: if (RifeConfig.Engine.getSiteAutoReload()) {
061: URL resource = resourceFinder.getResource(processed_path);
062: if (null == resource) {
063: throw new NotFoundProcessingErrorException("element",
064: processed_path, null);
065: }
066:
067: try {
068: builder.addResourceModificationTime(new UrlResource(
069: resource, processed_path), resourceFinder
070: .getModificationTime(resource));
071: } catch (ResourceFinderErrorException e) {
072: throw new ProcessingErrorException(
073: "element",
074: declarationName,
075: "Error while retrieving the modification time.",
076: e);
077: }
078: }
079: }
080:
081: private class GroovyProcessor extends BuilderSupport {
082: private ElementInfoBuilder mElementInfoBuilder = null;
083: private String mGroovyPath = null;
084:
085: private String mCurrentInput = null;
086: private String mCurrentOutput = null;
087: private String mCurrentIncookie = null;
088: private String mCurrentOutcookie = null;
089: private String mCurrentParameter = null;
090: private ArrayList<String> mDefaults = null;
091: private SubmissionBuilder mSubmissionBuilder = null;
092:
093: private GroovyProcessor(ElementInfoBuilder builder) {
094: mElementInfoBuilder = builder;
095: }
096:
097: public synchronized void processGroovy(final String groovyPath,
098: ResourceFinder resourceFinder) {
099: if (null == groovyPath)
100: throw new IllegalArgumentException(
101: "groovyPath can't be null.");
102: if (groovyPath.length() == 0)
103: throw new IllegalArgumentException(
104: "groovyPath can't be empty.");
105: if (null == resourceFinder)
106: throw new IllegalArgumentException(
107: "resourceFinder can't be null.");
108:
109: mGroovyPath = groovyPath;
110:
111: // retrieve a stream towards the groovy script
112: Class script_class = null;
113: try {
114: script_class = resourceFinder.useStream(groovyPath,
115: new InputStreamUser() {
116: public Class useInputStream(
117: InputStream stream)
118: throws InnerClassException {
119: if (null == stream) {
120: throw new NotFoundProcessingErrorException(
121: "element", groovyPath, null);
122: }
123:
124: // parse the groovy script and create a class
125: GroovyClassLoader mLoader = new GroovyClassLoader(
126: getClass().getClassLoader(),
127: new CompilerConfiguration());
128: GroovyCodeSource code_source = new GroovyCodeSource(
129: stream,
130: "elementinfobuilder.groovy",
131: "/groovy/shell");
132: try {
133: return mLoader
134: .parseClass(code_source);
135: } catch (Throwable e) {
136: throw new ParsingErrorException(
137: "element", groovyPath, e);
138: }
139: }
140: });
141: } catch (ResourceFinderErrorException e) {
142: throw new NotFoundProcessingErrorException("element",
143: groovyPath, e);
144: }
145:
146: // setup the script bindings and run it
147: Binding binding = new Binding();
148: binding.setVariable("processor", this );
149: binding.setVariable("builder", mElementInfoBuilder);
150: Script script = InvokerHelper.createScript(script_class,
151: binding);
152: script.run();
153: }
154:
155: protected void setParent(Object parent, Object child) {
156: // System.out.println("setParent "+parent+", "+child);
157: }
158:
159: protected Object createNode(Object node) {
160: return createNode(node, null, null);
161: }
162:
163: protected Object createNode(Object node, Object value) {
164: return createNode(node, null, value);
165: }
166:
167: protected Object createNode(Object node, Map attributes) {
168: return createNode(node, attributes, null);
169: }
170:
171: protected Object createNode(Object node, Map atts, Object value) {
172: // System.out.println("createNode "+qName+", "+atts+", "+value);
173:
174: if (null == atts) {
175: atts = new HashMap();
176: }
177:
178: if (node.equals("element")) {
179: String content_type = Convert.toString(atts
180: .get("contenttype"));
181: String extending = Convert
182: .toString(atts.get("extends"));
183: String implementation = Convert.toString(atts
184: .get("implementation"));
185:
186: mElementInfoBuilder.setContentType(content_type);
187:
188: // process the class it extends from
189: if (extending != null) {
190: mElementInfoBuilder.extendsFrom(extending);
191: }
192:
193: if (implementation != null) {
194: mElementInfoBuilder
195: .setImplementation(implementation);
196: }
197: } else if (node.equals("property")) {
198: mElementInfoBuilder.addStaticProperty(Convert
199: .toString(atts.get("name")),
200: new PropertyValueObject(value));
201: } else if (node.equals("input")) {
202: mCurrentInput = Convert.toString(atts.get("name"));
203: mDefaults = new ArrayList<String>();
204: } else if (node.equals("inbean")) {
205: String classname = Convert.toString(atts
206: .get("classname"));
207: String prefix = Convert.toString(atts.get("prefix"));
208: String name = Convert.toString(atts.get("name"));
209: String group = Convert.toString(atts.get("group"));
210:
211: mElementInfoBuilder.addInBean(classname, prefix, name,
212: group);
213: } else if (node.equals("output")) {
214: mCurrentOutput = Convert.toString(atts.get("name"));
215: mDefaults = new ArrayList<String>();
216: } else if (node.equals("outbean")) {
217: String classname = Convert.toString(atts
218: .get("classname"));
219: String prefix = Convert.toString(atts.get("prefix"));
220: String name = Convert.toString(atts.get("name"));
221: String group = Convert.toString(atts.get("group"));
222:
223: mElementInfoBuilder.addOutBean(classname, prefix, name,
224: group);
225: } else if (node.equals("incookie")) {
226: mCurrentIncookie = Convert.toString(atts.get("name"));
227: mDefaults = new ArrayList<String>();
228: } else if (node.equals("outcookie")) {
229: mCurrentOutcookie = Convert.toString(atts.get("name"));
230: mDefaults = new ArrayList<String>();
231: } else if (node.equals("childtrigger")) {
232: mElementInfoBuilder.addChildTrigger(Convert
233: .toString(atts.get("name")));
234: } else if (node.equals("submission")) {
235: mSubmissionBuilder = mElementInfoBuilder
236: .enterSubmission(Convert.toString(atts
237: .get("name")));
238:
239: boolean cancel_continuations = false;
240: String continuations = Convert.toString(atts
241: .get("continuations"));
242: if (continuations != null
243: && continuations.equals("cancel")) {
244: cancel_continuations = true;
245: }
246:
247: mSubmissionBuilder
248: .cancelContinuations(cancel_continuations);
249: } else if (node.equals("param")) {
250: if (Convert.toString(atts.get("name")) != null
251: && Convert.toString(atts.get("regexp")) != null) {
252: throw new ParsingErrorException(
253: "element",
254: mGroovyPath,
255: "A submission parameter can't have both a name and a regexp attribute.",
256: null);
257: }
258:
259: if (Convert.toString(atts.get("name")) != null) {
260: mCurrentParameter = Convert.toString(atts
261: .get("name"));
262: mDefaults = new ArrayList<String>();
263: } else if (Convert.toString(atts.get("regexp")) != null) {
264: mSubmissionBuilder.addParameterRegexp(Convert
265: .toString(atts.get("regexp")));
266: mDefaults = null;
267: } else {
268: throw new ParsingErrorException(
269: "element",
270: mGroovyPath,
271: "A submission parameter needs either a name or a regexp attribute.",
272: null);
273: }
274: } else if (node.equals("bean")) {
275: String classname = Convert.toString(atts
276: .get("classname"));
277: String prefix = Convert.toString(atts.get("prefix"));
278: String name = Convert.toString(atts.get("name"));
279: String group = Convert.toString(atts.get("group"));
280:
281: mSubmissionBuilder.addBean(classname, prefix, name,
282: group);
283: } else if (node.equals("file")) {
284: mSubmissionBuilder.addFile(Convert.toString(atts
285: .get("name")));
286: } else if (node.equals("defaultvalue")) {
287: if (null == mDefaults) {
288: throw new ParsingErrorException(
289: "element",
290: mGroovyPath,
291: "A submission parameter that's defined by a regular expression can't have default values.",
292: null);
293: }
294:
295: mDefaults.add((String) value);
296: } else if (node.equals("exit")) {
297: mElementInfoBuilder.addExit(Convert.toString(atts
298: .get("name")));
299: } else {
300: throw new ParsingErrorException("element", mGroovyPath,
301: "Unsupport element name '" + node + "'.", null);
302: }
303:
304: return node;
305: }
306:
307: protected void nodeCompleted(Object parent, Object node) {
308: // System.out.println("nodeCompleted "+parent+", "+node);
309:
310: if (node.equals("input")) {
311: String[] defaults = null;
312: if (mDefaults.size() > 0) {
313: defaults = new String[mDefaults.size()];
314: defaults = mDefaults.toArray(defaults);
315: }
316: mElementInfoBuilder.addInput(mCurrentInput, defaults);
317: mCurrentInput = null;
318: mDefaults = null;
319: } else if (node.equals("output")) {
320: String[] defaults = null;
321: if (mDefaults.size() > 0) {
322: defaults = new String[mDefaults.size()];
323: defaults = mDefaults.toArray(defaults);
324: }
325: mElementInfoBuilder.addOutput(mCurrentOutput, defaults);
326: mCurrentOutput = null;
327: mDefaults = null;
328: } else if (node.equals("incookie")) {
329: String defaultValue = null;
330: if (mDefaults.size() > 0) {
331: defaultValue = mDefaults.get(0);
332: }
333: mElementInfoBuilder.addIncookie(mCurrentIncookie,
334: defaultValue);
335: mCurrentIncookie = null;
336: mDefaults = null;
337: } else if (node.equals("outcookie")) {
338: String defaultValue = null;
339: if (mDefaults.size() > 0) {
340: defaultValue = mDefaults.get(0);
341: }
342: mElementInfoBuilder.addOutcookie(mCurrentOutcookie,
343: defaultValue);
344: mCurrentOutcookie = null;
345: mDefaults = null;
346: } else if (node.equals("submission")) {
347: mSubmissionBuilder.leaveSubmission();
348: } else if (node.equals("param")) {
349: if (mDefaults != null) {
350: String[] defaults = null;
351: if (mDefaults.size() > 0) {
352: defaults = new String[mDefaults.size()];
353: defaults = mDefaults.toArray(defaults);
354: }
355: mSubmissionBuilder.addParameter(mCurrentParameter,
356: defaults);
357: }
358: mCurrentParameter = null;
359: mDefaults = null;
360: }
361: }
362: }
363: }
|