/* * Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com) * Licensed under the Apache License, Version 2.0 (the "License") * $Id: Groovy2ElementInfo.java 3918 2008-04-14 17:35:35Z gbevin $ */ package com.uwyn.rife.engine; import com.uwyn.rife.config.RifeConfig; import com.uwyn.rife.engine.exceptions.EngineException; import com.uwyn.rife.engine.exceptions.NotFoundProcessingErrorException; import com.uwyn.rife.engine.exceptions.ParsingErrorException; import com.uwyn.rife.engine.exceptions.ProcessingErrorException; import com.uwyn.rife.ioc.PropertyValueObject; import com.uwyn.rife.resources.ResourceFinder; import com.uwyn.rife.resources.exceptions.ResourceFinderErrorException; import com.uwyn.rife.tools.Convert; import com.uwyn.rife.tools.exceptions.InnerClassException; import com.uwyn.rife.tools.InputStreamUser; import groovy.lang.Binding; import groovy.lang.GroovyClassLoader; import groovy.lang.GroovyCodeSource; import groovy.lang.Script; import groovy.util.BuilderSupport; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.runtime.InvokerHelper; class Groovy2ElementInfo implements ElementInfoProcessor { Groovy2ElementInfo() { } public void processElementInfo(ElementInfoBuilder builder, String declarationName, ResourceFinder resourceFinder) throws EngineException { GroovyProcessor processor = new GroovyProcessor(builder); String processed_path = null; try { // process the element declaration try { processed_path = declarationName; processor.processGroovy(processed_path, resourceFinder); } catch (NotFoundProcessingErrorException e) { processed_path = DEFAULT_ELEMENTS_PATH+declarationName; processor.processGroovy(processed_path, resourceFinder); } } catch (Exception e) { throw new ProcessingErrorException("element", declarationName, e); } // obtain the modification time if (RifeConfig.Engine.getSiteAutoReload()) { URL resource = resourceFinder.getResource(processed_path); if (null == resource) { throw new NotFoundProcessingErrorException("element", processed_path, null); } try { builder.addResourceModificationTime(new UrlResource(resource, processed_path), resourceFinder.getModificationTime(resource)); } catch (ResourceFinderErrorException e) { throw new ProcessingErrorException("element", declarationName, "Error while retrieving the modification time.", e); } } } private class GroovyProcessor extends BuilderSupport { private ElementInfoBuilder mElementInfoBuilder = null; private String mGroovyPath = null; private String mCurrentInput = null; private String mCurrentOutput = null; private String mCurrentIncookie = null; private String mCurrentOutcookie = null; private String mCurrentParameter = null; private ArrayList<String> mDefaults = null; private SubmissionBuilder mSubmissionBuilder = null; private GroovyProcessor(ElementInfoBuilder builder) { mElementInfoBuilder = builder; } public synchronized void processGroovy(final String groovyPath, ResourceFinder resourceFinder) { if (null == groovyPath) throw new IllegalArgumentException("groovyPath can't be null."); if (groovyPath.length() == 0) throw new IllegalArgumentException("groovyPath can't be empty."); if (null == resourceFinder) throw new IllegalArgumentException("resourceFinder can't be null."); mGroovyPath = groovyPath; // retrieve a stream towards the groovy script Class script_class = null; try { script_class = resourceFinder.useStream(groovyPath, new InputStreamUser() { public Class useInputStream(InputStream stream) throws InnerClassException { if (null == stream) { throw new NotFoundProcessingErrorException("element", groovyPath, null); } // parse the groovy script and create a class GroovyClassLoader mLoader = new GroovyClassLoader(getClass().getClassLoader(), new CompilerConfiguration()); GroovyCodeSource code_source = new GroovyCodeSource(stream, "elementinfobuilder.groovy", "/groovy/shell"); try { return mLoader.parseClass(code_source); } catch (Throwable e) { throw new ParsingErrorException("element", groovyPath, e); } } }); } catch (ResourceFinderErrorException e) { throw new NotFoundProcessingErrorException("element", groovyPath, e); } // setup the script bindings and run it Binding binding = new Binding(); binding.setVariable("processor", this); binding.setVariable("builder", mElementInfoBuilder); Script script = InvokerHelper.createScript(script_class, binding); script.run(); } protected void setParent(Object parent, Object child) { // System.out.println("setParent "+parent+", "+child); } protected Object createNode(Object node) { return createNode(node, null, null); } protected Object createNode(Object node, Object value) { return createNode(node, null, value); } protected Object createNode(Object node, Map attributes) { return createNode(node, attributes, null); } protected Object createNode(Object node, Map atts, Object value) { // System.out.println("createNode "+qName+", "+atts+", "+value); if (null == atts) { atts = new HashMap(); } if (node.equals("element")) { String content_type = Convert.toString(atts.get("contenttype")); String extending = Convert.toString(atts.get("extends")); String implementation = Convert.toString(atts.get("implementation")); mElementInfoBuilder.setContentType(content_type); // process the class it extends from if (extending != null) { mElementInfoBuilder.extendsFrom(extending); } if (implementation != null) { mElementInfoBuilder.setImplementation(implementation); } } else if (node.equals("property")) { mElementInfoBuilder.addStaticProperty(Convert.toString(atts.get("name")), new PropertyValueObject(value)); } else if (node.equals("input")) { mCurrentInput = Convert.toString(atts.get("name")); mDefaults = new ArrayList<String>(); } else if (node.equals("inbean")) { String classname = Convert.toString(atts.get("classname")); String prefix = Convert.toString(atts.get("prefix")); String name = Convert.toString(atts.get("name")); String group = Convert.toString(atts.get("group")); mElementInfoBuilder.addInBean(classname, prefix, name, group); } else if (node.equals("output")) { mCurrentOutput = Convert.toString(atts.get("name")); mDefaults = new ArrayList<String>(); } else if (node.equals("outbean")) { String classname = Convert.toString(atts.get("classname")); String prefix = Convert.toString(atts.get("prefix")); String name = Convert.toString(atts.get("name")); String group = Convert.toString(atts.get("group")); mElementInfoBuilder.addOutBean(classname, prefix, name, group); } else if (node.equals("incookie")) { mCurrentIncookie = Convert.toString(atts.get("name")); mDefaults = new ArrayList<String>(); } else if (node.equals("outcookie")) { mCurrentOutcookie = Convert.toString(atts.get("name")); mDefaults = new ArrayList<String>(); } else if (node.equals("childtrigger")) { mElementInfoBuilder.addChildTrigger(Convert.toString(atts.get("name"))); } else if (node.equals("submission")) { mSubmissionBuilder = mElementInfoBuilder.enterSubmission(Convert.toString(atts.get("name"))); boolean cancel_continuations = false; String continuations = Convert.toString(atts.get("continuations")); if (continuations != null && continuations.equals("cancel")) { cancel_continuations = true; } mSubmissionBuilder.cancelContinuations(cancel_continuations); } else if (node.equals("param")) { if (Convert.toString(atts.get("name")) != null && Convert.toString(atts.get("regexp")) != null) { throw new ParsingErrorException("element", mGroovyPath, "A submission parameter can't have both a name and a regexp attribute.", null); } if (Convert.toString(atts.get("name")) != null) { mCurrentParameter = Convert.toString(atts.get("name")); mDefaults = new ArrayList<String>(); } else if (Convert.toString(atts.get("regexp")) != null) { mSubmissionBuilder.addParameterRegexp(Convert.toString(atts.get("regexp"))); mDefaults = null; } else { throw new ParsingErrorException("element", mGroovyPath, "A submission parameter needs either a name or a regexp attribute.", null); } } else if (node.equals("bean")) { String classname = Convert.toString(atts.get("classname")); String prefix = Convert.toString(atts.get("prefix")); String name = Convert.toString(atts.get("name")); String group = Convert.toString(atts.get("group")); mSubmissionBuilder.addBean(classname, prefix, name, group); } else if (node.equals("file")) { mSubmissionBuilder.addFile(Convert.toString(atts.get("name"))); } else if (node.equals("defaultvalue")) { if (null == mDefaults) { throw new ParsingErrorException("element", mGroovyPath, "A submission parameter that's defined by a regular expression can't have default values.", null); } mDefaults.add((String)value); } else if (node.equals("exit")) { mElementInfoBuilder.addExit(Convert.toString(atts.get("name"))); } else { throw new ParsingErrorException("element", mGroovyPath, "Unsupport element name '"+node+"'.", null); } return node; } protected void nodeCompleted(Object parent, Object node) { // System.out.println("nodeCompleted "+parent+", "+node); if (node.equals("input")) { String[] defaults = null; if (mDefaults.size() > 0) { defaults = new String[mDefaults.size()]; defaults = mDefaults.toArray(defaults); } mElementInfoBuilder.addInput(mCurrentInput, defaults); mCurrentInput = null; mDefaults = null; } else if (node.equals("output")) { String[] defaults = null; if (mDefaults.size() > 0) { defaults = new String[mDefaults.size()]; defaults = mDefaults.toArray(defaults); } mElementInfoBuilder.addOutput(mCurrentOutput, defaults); mCurrentOutput = null; mDefaults = null; } else if (node.equals("incookie")) { String defaultValue = null; if (mDefaults.size() > 0) { defaultValue = mDefaults.get(0); } mElementInfoBuilder.addIncookie(mCurrentIncookie, defaultValue); mCurrentIncookie = null; mDefaults = null; } else if (node.equals("outcookie")) { String defaultValue = null; if (mDefaults.size() > 0) { defaultValue = mDefaults.get(0); } mElementInfoBuilder.addOutcookie(mCurrentOutcookie, defaultValue); mCurrentOutcookie = null; mDefaults = null; } else if (node.equals("submission")) { mSubmissionBuilder.leaveSubmission(); } else if (node.equals("param")) { if (mDefaults != null) { String[] defaults = null; if (mDefaults.size() > 0) { defaults = new String[mDefaults.size()]; defaults = mDefaults.toArray(defaults); } mSubmissionBuilder.addParameter(mCurrentParameter, defaults); } mCurrentParameter = null; mDefaults = null; } } } }