Author: lgawron Date: Thu Dec 9 04:38:49 2004 New Revision: 111375 URL: http://svn.apache.org/viewcvs?view=rev&rev=111375 Log: moved Jonas' template solution to o.a.c.template.v2 refactored JXTemplate generator introduced as o.a.c.template.jxtg.JXTemplateGenerator Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/JXTemplateGenerator.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/TransformerAdapter.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ErrorHolder.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JSIntrospector.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXCacheKey.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXSourceValidity.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/LocatorFacade.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/MyVariables.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ValueHelper.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/JXTExpression.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Literal.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/MyJexlContext.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Subst.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/Parser.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/AttributeEvent.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Characters.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/CopyAttribute.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndCDATA.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDTD.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDocument.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndElement.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndEntity.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndInstruction.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndPrefixMapping.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Event.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/IgnorableWhitespace.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/LoopTagStatus.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/ProcessingInstruction.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SkippedEntity.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartCDATA.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartChoose.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartComment.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDTD.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDefine.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDocument.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartElement.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEntity.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEval.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEvalBody.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartForEach.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatDate.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatNumber.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartIf.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartImport.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartInstruction.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOtherwise.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOut.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartParameter.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartPrefixMapping.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartSet.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartTemplate.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartWhen.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SubstituteAttribute.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/TextEvent.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/generation/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/generation/TemplateGenerator.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AbstractToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AttributeToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/CharactersToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ElementToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ExpressionToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/PlainElementToken.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Script.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptCompiler.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptContext.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptInvoker.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/TagRepository.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Token.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/AbstractTag.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/Tag.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/samples/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/samples/DuplicateTag.java Removed: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/generation/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/script/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/tag/ Modified: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java
Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/JXTemplateGenerator.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/JXTemplateGenerator.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/JXTemplateGenerator.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,1230 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg; + +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.cocoon.ProcessingException; +import org.apache.cocoon.caching.CacheableProcessingComponent; +import org.apache.cocoon.components.flow.FlowHelper; +import org.apache.cocoon.components.flow.WebContinuation; +import org.apache.cocoon.components.flow.javascript.fom.FOM_JavaScriptFlowHelper; +import org.apache.cocoon.components.source.SourceUtil; +import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.environment.Request; +import org.apache.cocoon.environment.SourceResolver; +import org.apache.cocoon.generation.ServiceableGenerator; +import org.apache.cocoon.template.jxtg.environment.ErrorHolder; +import org.apache.cocoon.template.jxtg.environment.JSIntrospector; +import org.apache.cocoon.template.jxtg.environment.JXCacheKey; +import org.apache.cocoon.template.jxtg.environment.JXSourceValidity; +import org.apache.cocoon.template.jxtg.environment.LocatorFacade; +import org.apache.cocoon.template.jxtg.environment.MyVariables; +import org.apache.cocoon.template.jxtg.environment.ValueHelper; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.cocoon.template.jxtg.expression.Literal; +import org.apache.cocoon.template.jxtg.expression.MyJexlContext; +import org.apache.cocoon.template.jxtg.expression.Subst; +import org.apache.cocoon.template.jxtg.script.Parser; +import org.apache.cocoon.template.jxtg.script.event.*; +import org.apache.cocoon.xml.IncludeXMLConsumer; +import org.apache.cocoon.xml.XMLConsumer; +import org.apache.cocoon.xml.XMLUtils; +import org.apache.cocoon.xml.dom.DOMBuilder; +import org.apache.cocoon.xml.dom.DOMStreamer; +import org.apache.commons.jexl.Expression; +import org.apache.commons.jexl.JexlContext; +import org.apache.commons.jexl.util.Introspector; +import org.apache.commons.jexl.util.introspection.Info; +import org.apache.commons.jxpath.CompiledExpression; +import org.apache.commons.jxpath.DynamicPropertyHandler; +import org.apache.commons.jxpath.JXPathBeanInfo; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.jxpath.JXPathContextFactory; +import org.apache.commons.jxpath.JXPathIntrospector; +import org.apache.commons.jxpath.Pointer; +import org.apache.commons.jxpath.Variables; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.excalibur.source.Source; +import org.apache.excalibur.source.SourceException; +import org.apache.excalibur.source.SourceValidity; +import org.apache.excalibur.xml.sax.XMLizable; +import org.mozilla.javascript.NativeArray; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.LocatorImpl; + +/** + * @cocoon.sitemap.component.documentation Provides a generic page template with + * embedded JSTL and XPath expression + * substitution to access data sent by + * Cocoon Flowscripts. + * + * @cocoon.sitemap.component.name jx + * @cocoon.sitemap.component.label content + * @cocoon.sitemap.component.logger sitemap.generator.jx + * + * @cocoon.sitemap.component.pooling.min 2 + * @cocoon.sitemap.component.pooling.max 16 + * @cocoon.sitemap.component.pooling.grow 2 + * + * + * @version CVS $Id: JXTemplateGenerator.java 106437 2004-11-24 17:35:45Z unico $ + */ +public class JXTemplateGenerator extends ServiceableGenerator implements + CacheableProcessingComponent { + /** The namespace used by this generator */ + public final static String NS = "http://apache.org/cocoon/templates/jx/1.0"; + + private static final JXPathContextFactory jxpathContextFactory = JXPathContextFactory + .newInstance(); + private static final Attributes EMPTY_ATTRS = new AttributesImpl(); + + private static final Iterator EMPTY_ITER = new Iterator() { + public boolean hasNext() { + return false; + } + + public Object next() { + return null; + } + + public void remove() { + // EMPTY + } + }; + + private static final Iterator NULL_ITER = new Iterator() { + public boolean hasNext() { + return true; + } + + public Object next() { + return null; + } + + public void remove() { + // EMPTY + } + }; + + public static final Locator NULL_LOCATOR = new LocatorImpl(); + + public final static String CACHE_KEY = "cache-key"; + public final static String VALIDITY = "cache-validity"; + + private JXPathContext jxpathContext; + private MyJexlContext globalJexlContext; + private Variables variables; + private static Map cache = new HashMap(); + private Source inputSource; + private Map definitions; + private Map cocoon; + + static { + // Hack: there's no _nice_ way to add my introspector to Jexl right now + try { + Field field = Introspector.class.getDeclaredField("uberSpect"); + field.setAccessible(true); + field.set(null, new JSIntrospector()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public XMLConsumer getConsumer() { + return this.xmlConsumer; + } + + public JXPathContext getJXPathContext() { + return jxpathContext; + } + + public MyJexlContext getJexlContext() { + return globalJexlContext; + } + + public void recycle() { + if (this.resolver != null) { + this.resolver.release(this.inputSource); + } + this.inputSource = null; + this.jxpathContext = null; + this.globalJexlContext = null; + this.variables = null; + this.definitions = null; + this.cocoon = null; + super.recycle(); + } + + /* + * (non-Javadoc) + * + * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, + * java.util.Map, java.lang.String, + * org.apache.avalon.framework.parameters.Parameters) + */ + public void setup(SourceResolver resolver, Map objectModel, String src, + Parameters parameters) throws ProcessingException, SAXException, + IOException { + + super.setup(resolver, objectModel, src, parameters); + if (src != null) { + try { + this.inputSource = resolver.resolveURI(src); + } catch (SourceException se) { + throw SourceUtil.handle("Error during resolving of '" + src + + "'.", se); + } + final String uri = inputSource.getURI(); + boolean regenerate = false; + StartDocument startEvent = null; + synchronized (cache) { + startEvent = (StartDocument) cache.get(uri); + if (startEvent != null) { + int valid = SourceValidity.UNKNOWN; + if (startEvent.getCompileTime() != null) { + valid = startEvent.getCompileTime().isValid(); + } + if (valid == SourceValidity.UNKNOWN + && startEvent.getCompileTime() != null) { + SourceValidity validity = inputSource.getValidity(); + valid = startEvent.getCompileTime().isValid(validity); + } + if (valid != SourceValidity.VALID) { + cache.remove(uri); + regenerate = true; + } + } else { + regenerate = true; + } + } + if (regenerate) { + Parser parser = new Parser(); + SourceUtil.parse(this.manager, this.inputSource, parser); + startEvent = parser.getStartEvent(); + startEvent.setCompileTime(this.inputSource.getValidity()); + synchronized (cache) { + cache.put(uri, startEvent); + } + } + } + Object bean = FlowHelper.getContextObject(objectModel); + WebContinuation kont = FlowHelper.getWebContinuation(objectModel); + setContexts(bean, kont, parameters, objectModel); + this.definitions = new HashMap(); + } + + private void fillContext(Object contextObject, Map map) { + if (contextObject != null) { + // Hack: I use jxpath to populate the context object's properties + // in the jexl context + final JXPathBeanInfo bi = JXPathIntrospector + .getBeanInfo(contextObject.getClass()); + if (bi.isDynamic()) { + Class cl = bi.getDynamicPropertyHandlerClass(); + try { + DynamicPropertyHandler h = (DynamicPropertyHandler) cl + .newInstance(); + String[] result = h.getPropertyNames(contextObject); + int len = result.length; + for (int i = 0; i < len; i++) { + try { + map.put(result[i], h.getProperty(contextObject, + result[i])); + } catch (Exception exc) { + exc.printStackTrace(); + } + } + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } else { + PropertyDescriptor[] props = bi.getPropertyDescriptors(); + int len = props.length; + for (int i = 0; i < len; i++) { + try { + Method read = props[i].getReadMethod(); + if (read != null) { + map.put(props[i].getName(), read.invoke( + contextObject, null)); + } + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + } + } + } + + private void setContexts(Object contextObject, WebContinuation kont, + Parameters parameters, Map objectModel) { + final Request request = ObjectModelHelper.getRequest(objectModel); + final Object session = request.getSession(false); + final Object app = ObjectModelHelper.getContext(objectModel); + cocoon = new HashMap(); + cocoon.put("request", FOM_JavaScriptFlowHelper + .getFOM_Request(objectModel)); + if (session != null) { + cocoon.put("session", FOM_JavaScriptFlowHelper + .getFOM_Session(objectModel)); + } + cocoon.put("context", FOM_JavaScriptFlowHelper + .getFOM_Context(objectModel)); + cocoon.put("continuation", FOM_JavaScriptFlowHelper + .getFOM_WebContinuation(objectModel)); + cocoon.put("parameters", Parameters.toProperties(parameters)); + this.variables = new MyVariables(cocoon, contextObject, kont, request, + session, app, parameters); + Map map; + if (contextObject instanceof Map) { + map = (Map) contextObject; + } else { + map = new HashMap(); + fillContext(contextObject, map); + } + jxpathContext = jxpathContextFactory.newContext(null, contextObject); + jxpathContext.setVariables(variables); + jxpathContext.setLenient(parameters.getParameterAsBoolean( + "lenient-xpath", false)); + globalJexlContext = new MyJexlContext(); + globalJexlContext.setVars(map); + map = globalJexlContext.getVars(); + map.put("cocoon", cocoon); + if (contextObject != null) { + map.put("flowContext", contextObject); + // FIXME (VG): Is this required (what it's used for - examples)? + // Here I use Rhino's live-connect objects to allow Jexl to call + // java constructors + Object javaPkg = FOM_JavaScriptFlowHelper + .getJavaPackage(objectModel); + Object pkgs = FOM_JavaScriptFlowHelper.getPackages(objectModel); + map.put("java", javaPkg); + map.put("Packages", pkgs); + } + if (kont != null) { + map.put("continuation", kont); + } + map.put("request", request); + map.put("context", app); + map.put("parameters", parameters); + if (session != null) { + map.put("session", session); + } + } + + /* + * (non-Javadoc) + * + * @see org.apache.cocoon.generation.Generator#generate() + */ + public void generate() throws IOException, SAXException, + ProcessingException { + final String cacheKey = this.inputSource.getURI(); + + StartDocument startEvent; + synchronized (cache) { + startEvent = (StartDocument) cache.get(cacheKey); + } + performGeneration(this.xmlConsumer, globalJexlContext, jxpathContext, + null, startEvent, null); + } + + public void performGeneration(final XMLConsumer consumer, + MyJexlContext jexlContext, JXPathContext jxpathContext, + StartElement macroCall, Event startEvent, Event endEvent) + throws SAXException { + cocoon.put("consumer", consumer); + execute(this.xmlConsumer, globalJexlContext, jxpathContext, null, + startEvent, null); + } + + interface CharHandler { + public void characters(char[] ch, int offset, int length) + throws SAXException; + } + + private void characters(JexlContext jexlContext, + JXPathContext jxpathContext, TextEvent event, CharHandler handler) + throws SAXException { + Iterator iter = event.getSubstitutions().iterator(); + while (iter.hasNext()) { + Object subst = iter.next(); + char[] chars; + if (subst instanceof char[]) { + chars = (char[]) subst; + } else { + JXTExpression expr = (JXTExpression) subst; + try { + Object val = ValueHelper.getValue(expr, jexlContext, + jxpathContext); + chars = val != null ? val.toString().toCharArray() + : ArrayUtils.EMPTY_CHAR_ARRAY; + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), event + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), event + .getLocation(), new ErrorHolder(err)); + } + } + handler.characters(chars, 0, chars.length); + } + } + + /** + * dump a DOM document, using an IncludeXMLConsumer to filter out start/end + * document events + */ + private void executeDOM(final XMLConsumer consumer, + MyJexlContext jexlContext, JXPathContext jxpathContext, Node node) + throws SAXException { + IncludeXMLConsumer includer = new IncludeXMLConsumer(consumer); + DOMStreamer streamer = new DOMStreamer(includer); + streamer.stream(node); + } + + private void call(Locator location, StartElement macroCall, + final XMLConsumer consumer, MyJexlContext jexlContext, + JXPathContext jxpathContext, Event startEvent, Event endEvent) + throws SAXException { + try { + execute(consumer, jexlContext, jxpathContext, macroCall, + startEvent, endEvent); + } catch (SAXParseException exc) { + throw new SAXParseException(macroCall.getLocalName() + ": " + + exc.getMessage(), location, exc); + } + } + + private void execute(final XMLConsumer consumer, MyJexlContext jexlContext, + JXPathContext jxpathContext, StartElement macroCall, + Event startEvent, Event endEvent) throws SAXException { + Event ev = startEvent; + LocatorFacade loc = new LocatorFacade(ev.getLocation()); + consumer.setDocumentLocator(loc); + while (ev != endEvent) { + loc.setDocumentLocator(ev.getLocation()); + if (ev instanceof Characters) { + TextEvent text = (TextEvent) ev; + Iterator iter = text.getSubstitutions().iterator(); + while (iter.hasNext()) { + Object subst = iter.next(); + char[] chars; + if (subst instanceof char[]) { + chars = (char[]) subst; + } else { + JXTExpression expr = (JXTExpression) subst; + try { + Object val = ValueHelper.getNode(expr, jexlContext, + jxpathContext); + if (val instanceof Node) { + executeDOM(consumer, jexlContext, + jxpathContext, (Node) val); + continue; + } else if (val instanceof NodeList) { + NodeList nodeList = (NodeList) val; + int len = nodeList.getLength(); + for (int i = 0; i < len; i++) { + Node n = nodeList.item(i); + executeDOM(consumer, jexlContext, + jxpathContext, n); + } + continue; + } else if (val instanceof Node[]) { + Node[] nodeList = (Node[]) val; + int len = nodeList.length; + for (int i = 0; i < len; i++) { + Node n = nodeList[i]; + executeDOM(consumer, jexlContext, + jxpathContext, n); + } + continue; + } else if (val instanceof XMLizable) { + ((XMLizable) val).toSAX(new IncludeXMLConsumer( + consumer)); + continue; + } + chars = val != null ? val.toString().toCharArray() + : ArrayUtils.EMPTY_CHAR_ARRAY; + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + } + consumer.characters(chars, 0, chars.length); + } + } else if (ev instanceof EndElement) { + EndElement endElement = (EndElement) ev; + StartElement startElement = endElement.getStartElement(); + consumer.endElement(startElement.getNamespaceURI(), + startElement.getLocalName(), startElement.getRaw()); + } else if (ev instanceof EndPrefixMapping) { + EndPrefixMapping endPrefixMapping = (EndPrefixMapping) ev; + consumer.endPrefixMapping(endPrefixMapping.getPrefix()); + } else if (ev instanceof IgnorableWhitespace) { + TextEvent text = (TextEvent) ev; + characters(jexlContext, jxpathContext, text, new CharHandler() { + public void characters(char[] ch, int offset, int len) + throws SAXException { + consumer.ignorableWhitespace(ch, offset, len); + } + }); + } else if (ev instanceof SkippedEntity) { + SkippedEntity skippedEntity = (SkippedEntity) ev; + consumer.skippedEntity(skippedEntity.getName()); + } else if (ev instanceof StartIf) { + StartIf startIf = (StartIf) ev; + Object val; + try { + val = ValueHelper.getValue(startIf.getTest(), jexlContext, + jxpathContext, Boolean.TRUE); + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + boolean result = false; + if (val instanceof Boolean) { + result = ((Boolean) val).booleanValue(); + } else { + result = (val != null); + } + if (!result) { + ev = startIf.getEndInstruction().getNext(); + continue; + } + } else if (ev instanceof StartForEach) { + StartForEach startForEach = (StartForEach) ev; + final Object items = startForEach.getItems(); + Iterator iter = null; + int begin, end, step; + String var, varStatus; + try { + if (items != null) { + JXTExpression expr = (JXTExpression) items; + if (expr.getCompiledExpression() instanceof CompiledExpression) { + CompiledExpression compiledExpression = (CompiledExpression) expr + .getCompiledExpression(); + Object val = compiledExpression.getPointer( + jxpathContext, expr.getRaw()).getNode(); + // FIXME: workaround for JXPath bug + iter = val instanceof NativeArray ? new JSIntrospector.NativeArrayIterator( + (NativeArray) val) + : compiledExpression + .iteratePointers(jxpathContext); + } else if (expr.getCompiledExpression() instanceof Expression) { + Expression e = (Expression) expr + .getCompiledExpression(); + Object result = e.evaluate(jexlContext); + if (result != null) { + iter = Introspector.getUberspect().getIterator( + result, + new Info( + ev.getLocation().getSystemId(), + ev.getLocation() + .getLineNumber(), ev + .getLocation() + .getColumnNumber())); + } + if (iter == null) { + iter = EMPTY_ITER; + } + } else { + // literal value + iter = new Iterator() { + Object val = items; + + public boolean hasNext() { + return val != null; + } + + public Object next() { + Object res = val; + val = null; + return res; + } + + public void remove() { + // EMPTY + } + }; + } + } else { + iter = NULL_ITER; + } + begin = startForEach.getBegin() == null ? 0 : ValueHelper + .getIntValue(startForEach.getBegin(), jexlContext, + jxpathContext); + end = startForEach.getEnd() == null ? Integer.MAX_VALUE + : ValueHelper.getIntValue(startForEach.getEnd(), + jexlContext, jxpathContext); + step = startForEach.getStep() == null ? 1 : ValueHelper + .getIntValue(startForEach.getStep(), jexlContext, + jxpathContext); + var = ValueHelper.getStringValue(startForEach.getVar(), + jexlContext, jxpathContext); + varStatus = ValueHelper.getStringValue(startForEach + .getVarStatus(), jexlContext, jxpathContext); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + MyJexlContext localJexlContext = new MyJexlContext(jexlContext); + MyVariables localJXPathVariables = new MyVariables( + (MyVariables) jxpathContext.getVariables()); + int i = 0; + // Move to the begin row + while (i < begin && iter.hasNext()) { + iter.next(); + i++; + } + LoopTagStatus status = null; + if (varStatus != null) { + status = new LoopTagStatus(); + status.setBegin(begin); + status.setEnd(end); + status.setStep(step); + status.setFirst(true); + localJexlContext.put(varStatus, status); + localJXPathVariables.declareVariable(varStatus, status); + } + int skipCounter, count = 1; + JXPathContext localJXPathContext = null; + while (i <= end && iter.hasNext()) { + Object value = iter.next(); + if (value instanceof Pointer) { + Pointer ptr = (Pointer) value; + localJXPathContext = jxpathContext + .getRelativeContext(ptr); + try { + value = ptr.getNode(); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), null); + } + } else { + localJXPathContext = jxpathContextFactory.newContext( + jxpathContext, value); + } + localJXPathContext.setVariables(localJXPathVariables); + if (var != null) { + localJexlContext.put(var, value); + } + if (status != null) { + status.setIndex(i); + status.setCount(count); + status.setFirst(i == begin); + status.setCurrent(value); + status.setLast((i == end || !iter.hasNext())); + } + execute(consumer, localJexlContext, localJXPathContext, + macroCall, startForEach.getNext(), startForEach + .getEndInstruction()); + // Skip rows + skipCounter = step; + while (--skipCounter > 0 && iter.hasNext()) { + iter.next(); + } + // Increase index + i += step; + count++; + } + ev = startForEach.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartChoose) { + StartChoose startChoose = (StartChoose) ev; + StartWhen startWhen = startChoose.getFirstChoice(); + while (startWhen != null) { + Object val; + try { + val = ValueHelper.getValue(startWhen.getTest(), jexlContext, + jxpathContext, Boolean.TRUE); + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } + boolean result; + if (val instanceof Boolean) { + result = ((Boolean) val).booleanValue(); + } else { + result = (val != null); + } + if (result) { + execute(consumer, jexlContext, jxpathContext, + macroCall, startWhen.getNext(), startWhen + .getEndInstruction()); + break; + } + startWhen = startWhen.getNextChoice(); + } + if (startWhen == null && startChoose.getOtherwise() != null) { + execute(consumer, jexlContext, jxpathContext, macroCall, + startChoose.getOtherwise().getNext(), startChoose + .getOtherwise().getEndInstruction()); + } + ev = startChoose.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartSet) { + StartSet startSet = (StartSet) ev; + Object value = null; + String var = null; + try { + if (startSet.getVar() != null) { + var = ValueHelper.getStringValue(startSet.getVar(), + jexlContext, jxpathContext); + } + if (startSet.getValue() != null) { + value = ValueHelper.getNode(startSet.getValue(), + jexlContext, jxpathContext); + } + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } + if (value == null) { + NodeList nodeList = toDOMNodeList("set", startSet, + jexlContext, macroCall); + // JXPath doesn't handle NodeList, so convert it to an array + int len = nodeList.getLength(); + Node[] nodeArr = new Node[len]; + for (int i = 0; i < len; i++) { + nodeArr[i] = nodeList.item(i); + } + value = nodeArr; + } + if (var != null) { + jxpathContext.getVariables().declareVariable(var, value); + jexlContext.put(var, value); + } + ev = startSet.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartElement) { + StartElement startElement = (StartElement) ev; + StartDefine def = (StartDefine) definitions.get(startElement + .getQname()); + if (def != null) { + Map attributeMap = new HashMap(); + Iterator i = startElement.getAttributeEvents().iterator(); + while (i.hasNext()) { + String attributeName; + Object attributeValue; + AttributeEvent attrEvent = (AttributeEvent) i.next(); + attributeName = attrEvent.getLocalName(); + if (attrEvent instanceof CopyAttribute) { + CopyAttribute copy = (CopyAttribute) attrEvent; + attributeValue = copy.getValue(); + } else if (attrEvent instanceof SubstituteAttribute) { + SubstituteAttribute substEvent = (SubstituteAttribute) attrEvent; + if (substEvent.getSubstitutions().size() == 1 + && substEvent.getSubstitutions().get(0) instanceof JXTExpression) { + JXTExpression expr = (JXTExpression) substEvent + .getSubstitutions().get(0); + Object val; + try { + val = ValueHelper.getNode(expr, + jexlContext, jxpathContext); + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), + ev.getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err + .getMessage(), ev.getLocation(), + new ErrorHolder(err)); + } + attributeValue = val != null ? val : ""; + } else { + StringBuffer buf = new StringBuffer(); + Iterator iterSubst = substEvent + .getSubstitutions().iterator(); + while (iterSubst.hasNext()) { + Subst subst = (Subst) iterSubst.next(); + if (subst instanceof Literal) { + Literal lit = (Literal) subst; + buf.append(lit.getValue()); + } else if (subst instanceof JXTExpression) { + JXTExpression expr = (JXTExpression) subst; + Object val; + try { + val = ValueHelper.getValue(expr, + jexlContext, jxpathContext); + } catch (Exception e) { + throw new SAXParseException(e + .getMessage(), ev + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err + .getMessage(), ev + .getLocation(), + new ErrorHolder(err)); + } + buf.append(val != null ? val.toString() + : ""); + } + } + attributeValue = buf.toString(); + } + } else { + throw new Error("this shouldn't have happened"); + } + attributeMap.put(attributeName, attributeValue); + } + MyVariables parent = (MyVariables) jxpathContext + .getVariables(); + MyVariables vars = new MyVariables(parent); + MyJexlContext localJexlContext = new MyJexlContext( + jexlContext); + HashMap macro = new HashMap(); + macro.put("body", startElement); + macro.put("arguments", attributeMap); + localJexlContext.put("macro", macro); + vars.declareVariable("macro", macro); + Iterator iter = def.getParameters().entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry e = (Map.Entry) iter.next(); + String key = (String) e.getKey(); + StartParameter startParam = (StartParameter) e + .getValue(); + Object default_ = startParam.getDefaultValue(); + Object val = attributeMap.get(key); + if (val == null) { + val = default_; + } + localJexlContext.put(key, val); + vars.declareVariable(key, val); + } + JXPathContext localJXPathContext = jxpathContextFactory + .newContext(null, jxpathContext.getContextBean()); + localJXPathContext.setVariables(vars); + call(ev.getLocation(), startElement, consumer, + localJexlContext, localJXPathContext, + def.getBody(), def.getEndInstruction()); + ev = startElement.getEndElement().getNext(); + continue; + } + Iterator i = startElement.getAttributeEvents().iterator(); + AttributesImpl attrs = new AttributesImpl(); + while (i.hasNext()) { + AttributeEvent attrEvent = (AttributeEvent) i.next(); + if (attrEvent instanceof CopyAttribute) { + CopyAttribute copy = (CopyAttribute) attrEvent; + attrs.addAttribute(copy.getNamespaceURI(), copy + .getLocalName(), copy.getRaw(), copy.getType(), + copy.getValue()); + } else if (attrEvent instanceof SubstituteAttribute) { + StringBuffer buf = new StringBuffer(); + SubstituteAttribute substEvent = (SubstituteAttribute) attrEvent; + Iterator iterSubst = substEvent.getSubstitutions() + .iterator(); + while (iterSubst.hasNext()) { + Subst subst = (Subst) iterSubst.next(); + if (subst instanceof Literal) { + Literal lit = (Literal) subst; + buf.append(lit.getValue()); + } else if (subst instanceof JXTExpression) { + JXTExpression expr = (JXTExpression) subst; + Object val; + try { + val = ValueHelper.getValue(expr, + jexlContext, jxpathContext); + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), + ev.getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err + .getMessage(), ev.getLocation(), + new ErrorHolder(err)); + } + buf.append(val != null ? val.toString() : ""); + } + } + attrs.addAttribute(attrEvent.getNamespaceURI(), + attrEvent.getLocalName(), attrEvent.getRaw(), + attrEvent.getType(), buf.toString()); + } + } + consumer.startElement(startElement.getNamespaceURI(), + startElement.getLocalName(), startElement.getRaw(), + attrs); + } else if (ev instanceof StartFormatNumber) { + StartFormatNumber startFormatNumber = (StartFormatNumber) ev; + try { + String result = startFormatNumber.format(jexlContext, + jxpathContext); + if (result != null) { + char[] chars = result.toCharArray(); + consumer.characters(chars, 0, chars.length); + } + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + } else if (ev instanceof StartFormatDate) { + StartFormatDate startFormatDate = (StartFormatDate) ev; + try { + String result = startFormatDate.format(jexlContext, + jxpathContext); + if (result != null) { + char[] chars = result.toCharArray(); + consumer.characters(chars, 0, chars.length); + } + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + } else if (ev instanceof StartPrefixMapping) { + StartPrefixMapping startPrefixMapping = (StartPrefixMapping) ev; + consumer.startPrefixMapping(startPrefixMapping.getPrefix(), + startPrefixMapping.getUri()); + } else if (ev instanceof StartComment) { + StartComment startJXComment = (StartComment) ev; + // Parse the body of the comment + NodeList nodeList = toDOMNodeList("comment", startJXComment, + jexlContext, macroCall); + // JXPath doesn't handle NodeList, so convert it to an array + int len = nodeList.getLength(); + final StringBuffer buf = new StringBuffer(); + Properties omit = XMLUtils.createPropertiesForXML(true); + for (int i = 0; i < len; i++) { + try { + String str = XMLUtils.serializeNode(nodeList.item(i), + omit); + buf.append(StringUtils.substringAfter(str, ">")); // cut + // the + // XML + // header + } catch (ProcessingException e) { + throw new SAXParseException(e.getMessage(), + startJXComment.getLocation(), e); + } + } + char[] chars = new char[buf.length()]; + buf.getChars(0, chars.length, chars, 0); + consumer.comment(chars, 0, chars.length); + ev = startJXComment.getEndInstruction().getNext(); + continue; + } else if (ev instanceof EndCDATA) { + consumer.endCDATA(); + } else if (ev instanceof EndDTD) { + consumer.endDTD(); + } else if (ev instanceof EndEntity) { + consumer.endEntity(((EndEntity) ev).getName()); + } else if (ev instanceof StartCDATA) { + consumer.startCDATA(); + } else if (ev instanceof StartDTD) { + StartDTD startDTD = (StartDTD) ev; + consumer.startDTD(startDTD.getName(), startDTD.getPublicId(), + startDTD.getSystemId()); + } else if (ev instanceof StartEntity) { + consumer.startEntity(((StartEntity) ev).getName()); + } else if (ev instanceof StartOut) { + StartOut startOut = (StartOut) ev; + Object val; + try { + val = ValueHelper.getNode(startOut.getCompiledExpression(), + jexlContext, jxpathContext, startOut.getLenient()); + if (val instanceof Node) { + executeDOM(consumer, jexlContext, jxpathContext, + (Node) val); + } else if (val instanceof NodeList) { + NodeList nodeList = (NodeList) val; + int len = nodeList.getLength(); + for (int i = 0; i < len; i++) { + Node n = nodeList.item(i); + executeDOM(consumer, jexlContext, jxpathContext, n); + } + } else if (val instanceof Node[]) { + Node[] nodeList = (Node[]) val; + int len = nodeList.length; + for (int i = 0; i < len; i++) { + Node n = nodeList[i]; + executeDOM(consumer, jexlContext, jxpathContext, n); + } + } else if (val instanceof XMLizable) { + ((XMLizable) val) + .toSAX(new IncludeXMLConsumer(consumer)); + } else { + char[] ch = val == null ? ArrayUtils.EMPTY_CHAR_ARRAY + : val.toString().toCharArray(); + consumer.characters(ch, 0, ch.length); + } + } catch (Exception e) { + throw new SAXParseException(e.getMessage(), ev + .getLocation(), e); + } + } else if (ev instanceof StartTemplate) { + // EMPTY + } else if (ev instanceof StartEval) { + StartEval startEval = (StartEval) ev; + JXTExpression expr = startEval.getValue(); + try { + Object val = ValueHelper.getNode(expr, jexlContext, + jxpathContext); + if (!(val instanceof StartElement)) { + throw new Exception( + "macro invocation required instead of: " + val); + } + StartElement call = (StartElement) val; + execute(consumer, jexlContext, jxpathContext, call, call + .getNext(), call.getEndElement()); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + ev = startEval.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartEvalBody) { + StartEvalBody startEval = (StartEvalBody) ev; + try { + execute(consumer, jexlContext, jxpathContext, null, + macroCall.getNext(), macroCall.getEndElement()); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + ev = startEval.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartDefine) { + StartDefine startDefine = (StartDefine) ev; + definitions.put(startDefine.getQname(), startDefine); + ev = startDefine.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartImport) { + StartImport startImport = (StartImport) ev; + String uri; + AttributeEvent e = startImport.getUri(); + if (e instanceof CopyAttribute) { + CopyAttribute copy = (CopyAttribute) e; + uri = copy.getValue(); + } else { + StringBuffer buf = new StringBuffer(); + SubstituteAttribute substAttr = (SubstituteAttribute) e; + Iterator i = substAttr.getSubstitutions().iterator(); + while (i.hasNext()) { + Subst subst = (Subst) i.next(); + if (subst instanceof Literal) { + Literal lit = (Literal) subst; + buf.append(lit.getValue()); + } else if (subst instanceof JXTExpression) { + JXTExpression expr = (JXTExpression) subst; + Object val; + try { + val = ValueHelper.getValue(expr, jexlContext, + jxpathContext); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), + ev.getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), + ev.getLocation(), new ErrorHolder(err)); + } + buf.append(val != null ? val.toString() : ""); + } + } + uri = buf.toString(); + } + Source input = null; + StartDocument doc; + try { + input = resolver.resolveURI(uri); + SourceValidity validity = null; + synchronized (cache) { + doc = (StartDocument) cache.get(input.getURI()); + if (doc != null) { + boolean recompile = false; + if (doc.getCompileTime() == null) { + recompile = true; + } else { + int valid = doc.getCompileTime().isValid(); + if (valid == SourceValidity.UNKNOWN) { + validity = input.getValidity(); + valid = doc.getCompileTime().isValid( + validity); + } + if (valid != SourceValidity.VALID) { + recompile = true; + } + } + if (recompile) { + doc = null; // recompile + } + } + } + if (doc == null) { + Parser parser = new Parser(); + // call getValidity before using the stream is faster if + // the source is a SitemapSource + if (validity == null) { + validity = input.getValidity(); + } + SourceUtil.parse(this.manager, input, parser); + doc = parser.getStartEvent(); + doc.setCompileTime(validity); + synchronized (cache) { + cache.put(input.getURI(), doc); + } + } + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } finally { + resolver.release(input); + } + JXPathContext selectJXPath = jxpathContext; + MyJexlContext selectJexl = jexlContext; + if (startImport.getSelect() != null) { + try { + Object obj = ValueHelper.getValue(startImport + .getSelect(), jexlContext, jxpathContext); + selectJXPath = jxpathContextFactory.newContext(null, + obj); + selectJXPath.setVariables(variables); + selectJexl = new MyJexlContext(jexlContext); + fillContext(obj, selectJexl); + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), ev + .getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), ev + .getLocation(), new ErrorHolder(err)); + } + } + try { + execute(consumer, selectJexl, selectJXPath, macroCall, doc + .getNext(), doc.getEndDocument()); + } catch (Exception exc) { + throw new SAXParseException( + "Exception occurred in imported template " + uri + + ": " + exc.getMessage(), + ev.getLocation(), exc); + } + ev = startImport.getEndInstruction().getNext(); + continue; + } else if (ev instanceof StartDocument) { + if (((StartDocument) ev).getEndDocument() != null) { + // if this isn't a document fragment + consumer.startDocument(); + } + } else if (ev instanceof EndDocument) { + consumer.endDocument(); + } else if (ev instanceof ProcessingInstruction) { + ProcessingInstruction pi = (ProcessingInstruction) ev; + consumer.processingInstruction(pi.getTarget(), pi.getData()); + } + ev = ev.getNext(); + } + } + + /* + * (non-Javadoc) + * + * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey() + */ + public Serializable getKey() { + JXTExpression cacheKeyExpr = (JXTExpression) getCurrentTemplateProperty(JXTemplateGenerator.CACHE_KEY); + try { + final Serializable templateKey = (Serializable) ValueHelper + .getValue(cacheKeyExpr, globalJexlContext, jxpathContext); + if (templateKey != null) { + return new JXCacheKey(this.inputSource.getURI(), templateKey); + } + } catch (Exception e) { + getLogger().error("error evaluating cache key", e); + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity() + */ + public SourceValidity getValidity() { + JXTExpression validityExpr = (JXTExpression) getCurrentTemplateProperty(JXTemplateGenerator.VALIDITY); + try { + final SourceValidity sourceValidity = this.inputSource + .getValidity(); + final SourceValidity templateValidity = (SourceValidity) ValueHelper + .getValue(validityExpr, globalJexlContext, jxpathContext); + if (sourceValidity != null && templateValidity != null) { + return new JXSourceValidity(sourceValidity, templateValidity); + } + } catch (Exception e) { + getLogger().error("error evaluating cache validity", e); + } + return null; + } + + private Object getCurrentTemplateProperty(String propertyName) { + final String uri = this.inputSource.getURI(); + StartDocument startEvent; + synchronized (cache) { + startEvent = (StartDocument) cache.get(uri); + } + return (startEvent != null) ? startEvent.getTemplateProperties().get( + propertyName) : null; + } + + private NodeList toDOMNodeList(String elementName, StartInstruction si, + MyJexlContext jexlContext, StartElement macroCall) + throws SAXException { + DOMBuilder builder = new DOMBuilder(); + builder.startDocument(); + builder.startElement(NS, elementName, elementName, EMPTY_ATTRS); + execute(builder, jexlContext, jxpathContext, macroCall, si.getNext(), + si.getEndInstruction()); + builder.endElement(NS, elementName, elementName); + builder.endDocument(); + Node node = builder.getDocument().getDocumentElement(); + return node.getChildNodes(); + } + +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/TransformerAdapter.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/TransformerAdapter.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/TransformerAdapter.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,94 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg; + +import java.io.IOException; +import java.util.Map; + +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.cocoon.ProcessingException; +import org.apache.cocoon.environment.SourceResolver; +import org.apache.cocoon.template.jxtg.script.Parser; +import org.apache.cocoon.transformation.ServiceableTransformer; +import org.apache.cocoon.xml.XMLConsumer; +import org.xml.sax.SAXException; + + +/** + * Adapter that makes this generator usable as a transformer + * (Note there is a performance penalty for this however: + * you effectively recompile the template for every instance document) + */ +public class TransformerAdapter extends ServiceableTransformer { + static class TemplateConsumer extends Parser implements XMLConsumer { + + public TemplateConsumer() { + this.gen = new JXTemplateGenerator(); + } + + public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) + throws ProcessingException, SAXException, IOException { + this.gen.setup(resolver, objectModel, null, parameters); + } + + public void service(ServiceManager manager) + throws ServiceException { + this.gen.service(manager); + } + + public void endDocument() throws SAXException { + super.endDocument(); + gen.performGeneration(gen.getConsumer(), gen.getJexlContext(), gen.getJXPathContext(), null, getStartEvent(), null); + } + + void setConsumer(XMLConsumer consumer) { + gen.setConsumer(consumer); + } + + protected void recycle() { + super.recycle(); + gen.recycle(); + } + + JXTemplateGenerator gen; + } + + TemplateConsumer templateConsumer = new TemplateConsumer(); + + public void recycle() { + super.recycle(); + templateConsumer.recycle(); + } + + public void setup(SourceResolver resolver, Map objectModel, String src, Parameters parameters) + throws ProcessingException, SAXException, IOException { + super.setup(resolver, objectModel, src, parameters); + templateConsumer.setup(resolver, objectModel, src, parameters); + } + + public void service(ServiceManager manager) + throws ServiceException { + super.service(manager); + templateConsumer.service(manager); + } + + public void setConsumer(XMLConsumer xmlConsumer) { + super.setConsumer(templateConsumer); + templateConsumer.setConsumer(xmlConsumer); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ErrorHolder.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ErrorHolder.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ErrorHolder.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,47 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.io.PrintStream; +import java.io.PrintWriter; + + +public class ErrorHolder extends Exception { + + private Error err; + + public ErrorHolder(Error err) { + super(err.getMessage()); + this.err = err; + } + + public void printStackTrace(PrintStream ps) { + err.printStackTrace(ps); + } + + public void printStackTrace(PrintWriter pw) { + err.printStackTrace(pw); + } + + public void printStackTrace() { + err.printStackTrace(); + } + + public Error getError() { + return err; + } + +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JSIntrospector.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JSIntrospector.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JSIntrospector.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,318 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.util.Enumeration; +import java.util.Iterator; + +import org.apache.commons.jexl.util.introspection.Info; +import org.apache.commons.jexl.util.introspection.UberspectImpl; +import org.apache.commons.jexl.util.introspection.VelMethod; +import org.apache.commons.jexl.util.introspection.VelPropertyGet; +import org.apache.commons.jexl.util.introspection.VelPropertySet; +import org.apache.commons.lang.StringUtils; +import org.mozilla.javascript.*; + + +/** + * Jexl Introspector that supports Rhino JavaScript objects + * as well as Java Objects + */ +public class JSIntrospector extends UberspectImpl { + + static class JSMethod implements VelMethod { + + Scriptable scope; + String name; + + public JSMethod(Scriptable scope, String name) { + this.scope = scope; + this.name = name; + } + + public Object invoke(Object thisArg, Object[] args) throws Exception { + Context cx = Context.enter(); + try { + Object result; + Scriptable thisObj = !(thisArg instanceof Scriptable) ? + Context.toObject(thisArg, scope) : (Scriptable)thisArg; + result = ScriptableObject.getProperty(thisObj, name); + Object[] newArgs = null; + if (args != null) { + newArgs = new Object[args.length]; + int len = args.length; + for (int i = 0; i < len; i++) { + newArgs[i] = args[i]; + if (args[i] != null && + !(args[i] instanceof Number) && + !(args[i] instanceof Boolean) && + !(args[i] instanceof String) && + !(args[i] instanceof Scriptable)) { + newArgs[i] = Context.toObject(args[i], scope); + } + } + } + result = ScriptRuntime.call(cx, result, thisObj, newArgs, scope); + if (result == Undefined.instance || result == Scriptable.NOT_FOUND) { + result = null; + } else if (!(result instanceof NativeJavaClass)) { + while (result instanceof Wrapper) { + result = ((Wrapper)result).unwrap(); + } + } + return result; + } catch (JavaScriptException e) { + throw new java.lang.reflect.InvocationTargetException(e); + } finally { + Context.exit(); + } + } + + public boolean isCacheable() { + return false; + } + + public String getMethodName() { + return name; + } + + public Class getReturnType() { + return Object.class; + } + + } + + static class JSPropertyGet implements VelPropertyGet { + + Scriptable scope; + String name; + + public JSPropertyGet(Scriptable scope, String name) { + this.scope = scope; + this.name = name; + } + + public Object invoke(Object thisArg) throws Exception { + Context cx = Context.enter(); + try { + Scriptable thisObj = !(thisArg instanceof Scriptable) ? + Context.toObject(thisArg, scope) : (Scriptable)thisArg; + Object result = ScriptableObject.getProperty(thisObj, name); + if (result == Scriptable.NOT_FOUND) { + result = ScriptableObject.getProperty(thisObj, "get" + StringUtils.capitalize(name)); + if (result != Scriptable.NOT_FOUND && result instanceof Function) { + try { + result = ((Function)result).call( + cx, ScriptableObject.getTopLevelScope(thisObj), thisObj, new Object[] {}); + } catch (JavaScriptException exc) { + exc.printStackTrace(); + result = null; + } + } + } + if (result == Scriptable.NOT_FOUND || result == Undefined.instance) { + result = null; + } else if (result instanceof Wrapper && !(result instanceof NativeJavaClass)) { + result = ((Wrapper)result).unwrap(); + } + return result; + } finally { + Context.exit(); + } + } + + public boolean isCacheable() { + return false; + } + + public String getMethodName() { + return name; + } + } + + static class JSPropertySet implements VelPropertySet { + + Scriptable scope; + String name; + + public JSPropertySet(Scriptable scope, String name) { + this.scope = scope; + this.name = name; + } + + public Object invoke(Object thisArg, Object rhs) throws Exception { + Context.enter(); + try { + Scriptable thisObj; + Object arg = rhs; + if (!(thisArg instanceof Scriptable)) { + thisObj = Context.toObject(thisArg, scope); + } else { + thisObj = (Scriptable)thisArg; + } + if (arg != null && + !(arg instanceof Number) && + !(arg instanceof Boolean) && + !(arg instanceof String) && + !(arg instanceof Scriptable)) { + arg = Context.toObject(arg, scope); + } + ScriptableObject.putProperty(thisObj, name, arg); + return rhs; + } finally { + Context.exit(); + } + } + + public boolean isCacheable() { + return false; + } + + public String getMethodName() { + return name; + } + } + + public static class NativeArrayIterator implements Iterator { + + NativeArray arr; + int index; + + public NativeArrayIterator(NativeArray arr) { + this.arr = arr; + this.index = 0; + } + + public boolean hasNext() { + return index < (int)arr.jsGet_length(); + } + + public Object next() { + Context.enter(); + try { + Object result = arr.get(index++, arr); + if (result == Undefined.instance || + result == Scriptable.NOT_FOUND) { + result = null; + } else { + if (!(result instanceof NativeJavaClass)) { + while (result instanceof Wrapper) { + result = ((Wrapper)result).unwrap(); + } + } + } + return result; + } finally { + Context.exit(); + } + } + + public void remove() { + arr.delete(index); + } + } + + static class ScriptableIterator implements Iterator { + + Scriptable scope; + Object[] ids; + int index; + + public ScriptableIterator(Scriptable scope) { + this.scope = scope; + this.ids = scope.getIds(); + this.index = 0; + } + + public boolean hasNext() { + return index < ids.length; + } + + public Object next() { + Context.enter(); + try { + Object result = ScriptableObject.getProperty(scope, ids[index++].toString()); + if (result == Undefined.instance || result == Scriptable.NOT_FOUND) { + result = null; + } else if (!(result instanceof NativeJavaClass)) { + while (result instanceof Wrapper) { + result = ((Wrapper)result).unwrap(); + } + } + return result; + } finally { + Context.exit(); + } + } + + public void remove() { + Context.enter(); + try { + scope.delete(ids[index].toString()); + } finally { + Context.exit(); + } + } + } + + public Iterator getIterator(Object obj, Info i) throws Exception { + if (!(obj instanceof Scriptable)) { + // support Enumeration + if (obj instanceof Enumeration) { + final Enumeration e = (Enumeration)obj; + return new Iterator() { + + public boolean hasNext() { + return e.hasMoreElements(); + } + + public Object next() { + return e.nextElement(); + } + + public void remove() { + // no action + } + + }; + } + if (obj instanceof Iterator) { + // support Iterator + return (Iterator)obj; + } + return super.getIterator(obj, i); + } + if (obj instanceof NativeArray) { + return new NativeArrayIterator((NativeArray)obj); + } + return new ScriptableIterator((Scriptable)obj); + } + + public VelMethod getMethod(Object obj, String methodName, Object[] args, Info i) throws Exception { + return !(obj instanceof Scriptable) ? + super.getMethod(obj, methodName, args, i) : new JSMethod((Scriptable)obj, methodName); + } + + public VelPropertyGet getPropertyGet(Object obj, String identifier, Info i) throws Exception { + return !(obj instanceof Scriptable) ? + super.getPropertyGet(obj, identifier, i) : new JSPropertyGet((Scriptable)obj, identifier); + } + + public VelPropertySet getPropertySet(Object obj, String identifier, Object arg, Info i) throws Exception { + return !(obj instanceof Scriptable) ? + super.getPropertySet(obj, identifier, arg, i) : new JSPropertySet((Scriptable)obj, identifier); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXCacheKey.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXCacheKey.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXCacheKey.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.io.Serializable; + +public final class JXCacheKey implements Serializable { + private final String templateUri; + private final Serializable templateKey; + + public JXCacheKey(String templateUri, Serializable templateKey) { + this.templateUri = templateUri; + this.templateKey = templateKey; + } + + public int hashCode() { + return templateUri.hashCode() + templateKey.hashCode(); + } + + public String toString() { + return "TK:" + templateUri + "_" + templateKey; + } + + public boolean equals(Object o) { + if (o instanceof JXCacheKey) { + JXCacheKey jxck = (JXCacheKey) o; + return this.templateUri.equals(jxck.templateUri) + && this.templateKey.equals(jxck.templateKey); + } + return false; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXSourceValidity.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXSourceValidity.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/JXSourceValidity.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,70 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.io.Serializable; + +import org.apache.excalibur.source.SourceValidity; + +public final class JXSourceValidity implements SourceValidity, Serializable { + private final SourceValidity sourceValidity; + private final SourceValidity templateValidity; + + public JXSourceValidity(SourceValidity sourceValidity, + SourceValidity templateValidity) { + this.sourceValidity = sourceValidity; + this.templateValidity = templateValidity; + } + + public int isValid() { + switch (sourceValidity.isValid()) { + case SourceValidity.INVALID: + return SourceValidity.INVALID; + case SourceValidity.UNKNOWN: { + if (templateValidity.isValid() == SourceValidity.INVALID) { + return SourceValidity.INVALID; + } else { + return SourceValidity.UNKNOWN; + } + } + case SourceValidity.VALID: + return templateValidity.isValid(); + } + return SourceValidity.UNKNOWN; + } + + public int isValid(SourceValidity otherValidity) { + if (otherValidity instanceof JXSourceValidity) { + JXSourceValidity otherJXValidity = (JXSourceValidity) otherValidity; + switch (sourceValidity.isValid(otherJXValidity.sourceValidity)) { + case SourceValidity.INVALID: + return SourceValidity.INVALID; + case SourceValidity.UNKNOWN: { + if (templateValidity.isValid(otherJXValidity.templateValidity) == SourceValidity.INVALID) { + return SourceValidity.INVALID; + } else { + return SourceValidity.UNKNOWN; + } + } + case SourceValidity.VALID: + return templateValidity + .isValid(otherJXValidity.templateValidity); + } + } + return 0; + } + +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/LocatorFacade.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/LocatorFacade.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/LocatorFacade.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import org.xml.sax.Locator; + +/** + * Facade to the Locator to be set on the consumer prior to sending other + * events, location member changeable + */ +public class LocatorFacade implements Locator { + private Locator locator; + + public LocatorFacade(Locator initialLocator) { + this.locator = initialLocator; + } + + public void setDocumentLocator(Locator newLocator) { + this.locator = newLocator; + } + + public int getColumnNumber() { + return this.locator.getColumnNumber(); + } + + public int getLineNumber() { + return this.locator.getLineNumber(); + } + + public String getPublicId() { + return this.locator.getPublicId(); + } + + public String getSystemId() { + return this.locator.getSystemId(); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/MyVariables.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/MyVariables.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/MyVariables.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,103 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cocoon.components.flow.WebContinuation; +import org.apache.commons.jxpath.Variables; + +public class MyVariables implements Variables { + MyVariables closure; + Map localVariables = new HashMap(); + + static final String[] VARIABLES = new String[] { "cocoon", "continuation", + "flowContext", "request", "response", "context", "session", + "parameters" }; + + Object cocoon; + + // backward compatibility + Object bean, kont, request, response, session, context, parameters; + + public MyVariables(Object cocoon, Object bean, WebContinuation kont, + Object request, Object session, Object context, Object parameters) { + this.cocoon = cocoon; + this.bean = bean; + this.kont = kont; + this.request = request; + this.session = session; + this.context = context; + this.parameters = parameters; + } + + public MyVariables(MyVariables parent) { + this.closure = parent; + } + + public boolean isDeclaredVariable(String varName) { + int len = VARIABLES.length; + for (int i = 0; i < len; i++) { + if (varName.equals(VARIABLES[i])) { + return true; + } + } + if (localVariables.containsKey(varName)) { + return true; + } + if (closure != null) { + return closure.isDeclaredVariable(varName); + } + return false; + } + + public Object getVariable(String varName) { + Object result = localVariables.get(varName); + if (result != null) { + return result; + } + if (closure != null) { + return closure.getVariable(varName); + } + if (varName.equals("cocoon")) { + return cocoon; + } + // backward compatibility + if (varName.equals("continuation")) { + return kont; + } else if (varName.equals("flowContext")) { + return bean; + } else if (varName.equals("request")) { + return request; + } else if (varName.equals("session")) { + return session; + } else if (varName.equals("context")) { + return context; + } else if (varName.equals("parameters")) { + return parameters; + } + return null; + } + + public void declareVariable(String varName, Object value) { + localVariables.put(varName, value); + } + + public void undeclareVariable(String varName) { + localVariables.remove(varName); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ValueHelper.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ValueHelper.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/environment/ValueHelper.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,185 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.environment; + +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.commons.jexl.Expression; +import org.apache.commons.jexl.JexlContext; +import org.apache.commons.jxpath.CompiledExpression; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.jxpath.Pointer; +import org.apache.commons.lang.StringUtils; +import org.w3c.dom.Node; + +/** + */ +public class ValueHelper { + + public static Locale parseLocale(String locale, String variant) { + Locale ret = null; + String language = locale; + String country = null; + int index = StringUtils.indexOfAny(locale, "-_"); + + if (index > -1) { + language = locale.substring(0, index); + country = locale.substring(index + 1); + } + if (StringUtils.isEmpty(language)) { + throw new IllegalArgumentException("No language in locale"); + } + if (country == null) { + ret = variant != null ? new Locale(language, "", variant) : new Locale(language, ""); + } else if (country.length() > 0) { + ret = variant != null ? new Locale(language, country, variant) : new Locale(language, country); + } else { + throw new IllegalArgumentException("Empty country in locale"); + } + return ret; + } + + // Hack: try to prevent JXPath from converting result to a String + public static Object getNode(JXTExpression expr, JexlContext jexlContext, JXPathContext jxpathContext, Boolean lenient) + throws Exception { + try { + Object compiled = expr.getCompiledExpression(); + if (compiled instanceof CompiledExpression) { + CompiledExpression e = (CompiledExpression)compiled; + boolean oldLenient = jxpathContext.isLenient(); + if (lenient != null) jxpathContext.setLenient(lenient.booleanValue()); + try { + Iterator iter = e.iteratePointers(jxpathContext); + if (iter.hasNext()) { + Pointer first = (Pointer)iter.next(); + if (iter.hasNext()) { + List result = new LinkedList(); + result.add(first.getNode()); + boolean dom = (first.getNode() instanceof Node); + while (iter.hasNext()) { + Object obj = ((Pointer)iter.next()).getNode(); + dom = dom && (obj instanceof Node); + result.add(obj); + } + Object[] arr; + if (dom) { + arr = new Node[result.size()]; + } else { + arr = new Object[result.size()]; + } + result.toArray(arr); + return arr; + } + return first.getNode(); + } + return null; + } finally { + jxpathContext.setLenient(oldLenient); + } + } else if (compiled instanceof Expression) { + Expression e = (Expression)compiled; + return e.evaluate(jexlContext); + } + return expr.getRaw(); + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof Exception) { + throw (Exception)t; + } + throw (Error)t; + } + } + + public static Object getNode(JXTExpression expr, JexlContext jexlContext, JXPathContext jxpathContext) throws Exception { + return getNode(expr, jexlContext, jxpathContext, null); + } + + public static Boolean getBooleanValue(JXTExpression expr, JexlContext jexlContext, + JXPathContext jxpathContext) throws Exception { + Object res = ValueHelper.getValue(expr, jexlContext, jxpathContext); + return res instanceof Boolean ? (Boolean)res : null; + } + + public static String getStringValue(JXTExpression expr, JexlContext jexlContext, + JXPathContext jxpathContext) throws Exception { + Object res = ValueHelper.getValue(expr, jexlContext, jxpathContext); + if (res != null) { + return res.toString(); + } + if (expr != null && expr.getCompiledExpression() == null) { + return expr.getRaw(); + } + return null; + } + + public static Number getNumberValue(JXTExpression expr, JexlContext jexlContext, JXPathContext jxpathContext) throws Exception { + Object res = ValueHelper.getValue(expr, jexlContext, jxpathContext); + if (res instanceof Number) { + return (Number)res; + } + if (res != null) { + return Double.valueOf(res.toString()); + } + return null; + } + + public static int getIntValue(JXTExpression expr, JexlContext jexlContext, JXPathContext jxpathContext) throws Exception { + Object res = ValueHelper.getValue(expr, jexlContext, jxpathContext); + return res instanceof Number ? ((Number)res).intValue() : 0; + } + + public static Object getValue(JXTExpression expr, JexlContext jexlContext, JXPathContext jxpathContext) throws Exception { + return ValueHelper.getValue(expr, jexlContext, jxpathContext, null); + } + + public static Object getValue(JXTExpression expr, JexlContext jexlContext, + JXPathContext jxpathContext, Boolean lenient) throws Exception { + if (expr != null) { + Object compiled = expr.getCompiledExpression(); + try { + if (compiled instanceof CompiledExpression) { + CompiledExpression e = (CompiledExpression) compiled; + boolean oldLenient = jxpathContext.isLenient(); + if (lenient != null) { + jxpathContext.setLenient(lenient.booleanValue()); + } + try { + return e.getValue(jxpathContext); + } finally { + jxpathContext.setLenient(oldLenient); + } + } else if (compiled instanceof Expression) { + Expression e = (Expression) compiled; + return e.evaluate(jexlContext); + } + return compiled; + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof Exception) { + throw (Exception) t; + } + throw (Error) t; + } + } else { + return null; + } + } +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/JXTExpression.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/JXTExpression.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/JXTExpression.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.expression; + + +public class JXTExpression extends Subst { + public JXTExpression(String raw, Object expr) { + this.raw = raw; + this.compiledExpression = expr; + } + + String raw; + Object compiledExpression; + + public Object getCompiledExpression() { + return compiledExpression; + } + + public void setCompiledExpression(Object compiledExpression) { + this.compiledExpression = compiledExpression; + } + + public String getRaw() { + return raw; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Literal.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Literal.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Literal.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.expression; + +public class Literal extends Subst { + public Literal(String val) { + this.value = val; + } + + public String getValue() { + return value; + } + + private final String value; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/MyJexlContext.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/MyJexlContext.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/MyJexlContext.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.expression; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.jexl.JexlContext; + +public class MyJexlContext extends HashMap implements JexlContext { + private MyJexlContext closure; + + public MyJexlContext() { + this(null); + } + + public MyJexlContext(MyJexlContext closure) { + this.closure = closure; + } + + public Map getVars() { + return this; + } + + public void setVars(Map map) { + putAll(map); + } + + public boolean containsKey(Object key) { + return this.get(key) != null; + } + + public Object get(Object key) { + if (key.equals("this")) { + return this; + } + Object result = super.get(key); + if (result == null && closure != null) { + result = closure.get(key); + } + return result; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Subst.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Subst.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/expression/Subst.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,20 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.expression; + +public class Subst { + // VOID +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/Parser.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/Parser.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/Parser.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,585 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Iterator; +import java.util.Stack; + +import org.apache.cocoon.template.jxtg.JXTemplateGenerator; +import org.apache.cocoon.template.jxtg.environment.ErrorHolder; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.cocoon.template.jxtg.script.event.*; +import org.apache.commons.jexl.ExpressionFactory; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.lang.StringUtils; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.LocatorImpl; + +public class Parser implements ContentHandler, LexicalHandler { + + StartDocument startEvent; + Event lastEvent; + Stack stack = new Stack(); + Locator locator; + Locator charLocation; + StringBuffer charBuf; + + final static String TEMPLATE = "template"; + final static String FOR_EACH = "forEach"; + final static String IF = "if"; + final static String CHOOSE = "choose"; + final static String WHEN = "when"; + final static String OTHERWISE = "otherwise"; + final static String OUT = "out"; + final static String IMPORT = "import"; + final static String SET = "set"; + final static String MACRO = "macro"; + final static String EVALBODY = "evalBody"; + final static String EVAL = "eval"; + final static String PARAMETER = "parameter"; + final static String FORMAT_NUMBER = "formatNumber"; + final static String FORMAT_DATE = "formatDate"; + final static String COMMENT = "comment"; + + public Parser() { + // EMPTY + } + + public StartDocument getStartEvent() { + return this.startEvent; + } + + protected void recycle() { + startEvent = null; + lastEvent = null; + stack.clear(); + locator = null; + charLocation = null; + charBuf = null; + } + + private void addEvent(Event ev) throws SAXException { + if (ev != null) { + if (lastEvent == null) { + lastEvent = startEvent = new StartDocument(locator); + } else { + flushChars(); + } + lastEvent.setNext(ev); + lastEvent = ev; + } else { + throw new NullPointerException("null event"); + } + } + + void flushChars() throws SAXException { + if (charBuf != null) { + char[] chars = new char[charBuf.length()]; + charBuf.getChars(0, charBuf.length(), chars, 0); + Characters ev = new Characters(charLocation, chars, 0, chars.length); + lastEvent.setNext(ev); + lastEvent = ev; + charLocation = null; + charBuf = null; + } + } + + public void characters(char[] ch, int start, int length) + throws SAXException { + if (charBuf == null) { + charBuf = new StringBuffer(length); + charLocation = locator != null ? new LocatorImpl(locator) + : JXTemplateGenerator.NULL_LOCATOR; + } + charBuf.append(ch, start, length); + } + + public void endDocument() throws SAXException { + StartDocument startDoc = (StartDocument) stack.pop(); + EndDocument endDoc = new EndDocument(locator); + startDoc.setEndDocument(endDoc); + addEvent(endDoc); + } + + public void endElement(String namespaceURI, String localName, String raw) + throws SAXException { + Event start = (Event) stack.pop(); + Event newEvent = null; + if (JXTemplateGenerator.NS.equals(namespaceURI)) { + StartInstruction startInstruction = (StartInstruction) start; + EndInstruction endInstruction = new EndInstruction(locator, + startInstruction); + newEvent = endInstruction; + if (start instanceof StartWhen) { + StartWhen startWhen = (StartWhen) start; + StartChoose startChoose = (StartChoose) stack.peek(); + if (startChoose.getFirstChoice() != null) { + StartWhen w = startChoose.getFirstChoice(); + while (w.getNextChoice() != null) { + w = w.getNextChoice(); + } + w.setNextChoice(startWhen); + } else { + startChoose.setFirstChoice(startWhen); + } + } else if (start instanceof StartOtherwise) { + StartOtherwise startOtherwise = (StartOtherwise) start; + StartChoose startChoose = (StartChoose) stack.peek(); + startChoose.setOtherwise(startOtherwise); + } + } else { + StartElement startElement = (StartElement) start; + newEvent = new EndElement(locator, startElement); + startElement.setEndElement((EndElement) newEvent); + } + addEvent(newEvent); + if (start instanceof StartDefine) { + StartDefine startDefine = (StartDefine) start; + startDefine.finish(); + } + } + + public void endPrefixMapping(String prefix) throws SAXException { + EndPrefixMapping endPrefixMapping = new EndPrefixMapping(locator, + prefix); + addEvent(endPrefixMapping); + } + + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + Event ev = new IgnorableWhitespace(locator, ch, start, length); + addEvent(ev); + } + + public void processingInstruction(String target, String data) + throws SAXException { + Event pi = new ProcessingInstruction(locator, target, data); + addEvent(pi); + } + + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + public void skippedEntity(String name) throws SAXException { + addEvent(new SkippedEntity(locator, name)); + } + + public void startDocument() { + startEvent = new StartDocument(locator); + lastEvent = startEvent; + stack.push(lastEvent); + } + + public void startElement(String namespaceURI, String localName, + String qname, Attributes attrs) throws SAXException { + Event newEvent = null; + AttributesImpl elementAttributes = new AttributesImpl(attrs); + int attributeCount = elementAttributes.getLength(); + for (int i = 0; i < attributeCount; i++) { + String attributeURI = elementAttributes.getURI(i); + if (StringUtils.equals(attributeURI, JXTemplateGenerator.NS)) { + getStartEvent().getTemplateProperties().put( + elementAttributes.getLocalName(i), + compileExpr(elementAttributes.getValue(i), null, + locator)); + elementAttributes.removeAttribute(i--); + } + } + StartElement startElement = new StartElement(locator, namespaceURI, + localName, qname, elementAttributes); + if (JXTemplateGenerator.NS.equals(namespaceURI)) { + if (localName.equals(FOR_EACH)) { + String items = attrs.getValue("items"); + String select = attrs.getValue("select"); + JXTExpression begin = compileInt(attrs.getValue("begin"), + FOR_EACH, locator); + JXTExpression end = compileInt(attrs.getValue("end"), FOR_EACH, + locator); + JXTExpression step = compileInt(attrs.getValue("step"), + FOR_EACH, locator); + JXTExpression var = compileExpr(attrs.getValue("var"), null, + locator); + JXTExpression varStatus = compileExpr(attrs + .getValue("varStatus"), null, locator); + if (items == null) { + if (select == null && (begin == null || end == null)) { + throw new SAXParseException( + "forEach: \"select\", \"items\", or both \"begin\" and \"end\" must be specified", + locator, null); + } + } else if (select != null) { + throw new SAXParseException( + "forEach: only one of \"select\" or \"items\" may be specified", + locator, null); + } + JXTExpression expr = compileExpr( + items == null ? select : items, null, locator); + String lenientValue = attrs.getValue("lenient"); + Boolean lenient = (lenientValue == null) ? null : Boolean + .valueOf(lenientValue); + StartForEach startForEach = new StartForEach(startElement, + expr, var, varStatus, begin, end, step, lenient); + newEvent = startForEach; + } else if (localName.equals(FORMAT_NUMBER)) { + JXTExpression value = compileExpr(attrs.getValue("value"), + null, locator); + JXTExpression type = compileExpr(attrs.getValue("type"), null, + locator); + JXTExpression pattern = compileExpr(attrs.getValue("pattern"), + null, locator); + JXTExpression currencyCode = compileExpr(attrs + .getValue("currencyCode"), null, locator); + JXTExpression currencySymbol = compileExpr(attrs + .getValue("currencySymbol"), null, locator); + JXTExpression isGroupingUsed = compileBoolean(attrs + .getValue("isGroupingUsed"), null, locator); + JXTExpression maxIntegerDigits = compileInt(attrs + .getValue("maxIntegerDigits"), null, locator); + JXTExpression minIntegerDigits = compileInt(attrs + .getValue("minIntegerDigits"), null, locator); + JXTExpression maxFractionDigits = compileInt(attrs + .getValue("maxFractionDigits"), null, locator); + JXTExpression minFractionDigits = compileInt(attrs + .getValue("minFractionDigits"), null, locator); + JXTExpression var = compileExpr(attrs.getValue("var"), null, + locator); + JXTExpression locale = compileExpr(attrs.getValue("locale"), + null, locator); + StartFormatNumber startFormatNumber = new StartFormatNumber( + startElement, var, value, type, pattern, currencyCode, + currencySymbol, isGroupingUsed, maxIntegerDigits, + minIntegerDigits, maxFractionDigits, minFractionDigits, + locale); + newEvent = startFormatNumber; + } else if (localName.equals(FORMAT_DATE)) { + JXTExpression var = compileExpr(attrs.getValue("var"), null, + locator); + JXTExpression value = compileExpr(attrs.getValue("value"), + null, locator); + JXTExpression type = compileExpr(attrs.getValue("type"), null, + locator); + JXTExpression pattern = compileExpr(attrs.getValue("pattern"), + null, locator); + JXTExpression timeZone = compileExpr( + attrs.getValue("timeZone"), null, locator); + JXTExpression dateStyle = compileExpr(attrs + .getValue("dateStyle"), null, locator); + JXTExpression timeStyle = compileExpr(attrs + .getValue("timeStyle"), null, locator); + JXTExpression locale = compileExpr(attrs.getValue("locale"), + null, locator); + StartFormatDate startFormatDate = new StartFormatDate( + startElement, var, value, type, pattern, timeZone, + dateStyle, timeStyle, locale); + newEvent = startFormatDate; + } else if (localName.equals(CHOOSE)) { + StartChoose startChoose = new StartChoose(startElement); + newEvent = startChoose; + } else if (localName.equals(WHEN)) { + if (stack.size() == 0 || !(stack.peek() instanceof StartChoose)) { + throw new SAXParseException( + "<when> must be within <choose>", locator, null); + } + String test = attrs.getValue("test"); + if (test != null) { + JXTExpression expr = compileExpr(test, "when: \"test\": ", + locator); + StartWhen startWhen = new StartWhen(startElement, expr); + newEvent = startWhen; + } else { + throw new SAXParseException("when: \"test\" is required", + locator, null); + } + } else if (localName.equals(OUT)) { + String value = attrs.getValue("value"); + if (value != null) { + JXTExpression expr = compileExpr(value, "out: \"value\": ", + locator); + String lenientValue = attrs.getValue("lenient"); + Boolean lenient = lenientValue == null ? null : Boolean + .valueOf(lenientValue); + newEvent = new StartOut(startElement, expr, lenient); + } else { + throw new SAXParseException("out: \"value\" is required", + locator, null); + } + } else if (localName.equals(OTHERWISE)) { + if (stack.size() != 0 && (stack.peek() instanceof StartChoose)) { + StartOtherwise startOtherwise = new StartOtherwise( + startElement); + newEvent = startOtherwise; + } else { + throw new SAXParseException( + "<otherwise> must be within <choose>", locator, + null); + } + } else if (localName.equals(IF)) { + String test = attrs.getValue("test"); + if (test != null) { + JXTExpression expr = compileExpr(test, "if: \"test\": ", + locator); + StartIf startIf = new StartIf(startElement, expr); + newEvent = startIf; + } else { + throw new SAXParseException("if: \"test\" is required", + locator, null); + } + } else if (localName.equals(MACRO)) { + // <macro name="myTag" targetNamespace="myNamespace"> + // <parameter name="paramName" required="Boolean" + // default="value"/> + // body + // </macro> + String namespace = StringUtils.defaultString(attrs + .getValue("targetNamespace")); + String name = attrs.getValue("name"); + if (name != null) { + StartDefine startDefine = new StartDefine(startElement, + namespace, name); + newEvent = startDefine; + } else { + throw new SAXParseException("macro: \"name\" is required", + locator, null); + } + } else if (localName.equals(PARAMETER)) { + if (stack.size() == 0 || !(stack.peek() instanceof StartDefine)) { + throw new SAXParseException("<parameter> not allowed here", + locator, null); + } else { + String name = attrs.getValue("name"); + String optional = attrs.getValue("optional"); + String default_ = attrs.getValue("default"); + if (name != null) { + StartParameter startParameter = new StartParameter( + startElement, name, optional, default_); + newEvent = startParameter; + } else { + throw new SAXParseException( + "parameter: \"name\" is required", locator, + null); + } + } + } else if (localName.equals(EVALBODY)) { + newEvent = new StartEvalBody(startElement); + } else if (localName.equals(EVAL)) { + String value = attrs.getValue("select"); + JXTExpression valueExpr = compileExpr(value, + "eval: \"select\":", locator); + newEvent = new StartEval(startElement, valueExpr); + } else if (localName.equals(SET)) { + String var = attrs.getValue("var"); + String value = attrs.getValue("value"); + JXTExpression varExpr = null; + JXTExpression valueExpr = null; + if (var != null) { + varExpr = compileExpr(var, "set: \"var\":", locator); + } + if (value != null) { + valueExpr = compileExpr(value, "set: \"value\":", locator); + } + StartSet startSet = new StartSet(startElement, varExpr, + valueExpr); + newEvent = startSet; + } else if (localName.equals(IMPORT)) { + // <import uri="${root}/foo/bar.xml" context="${foo}"/> + AttributeEvent uri = null; + Iterator iter = startElement.getAttributeEvents().iterator(); + while (iter.hasNext()) { + AttributeEvent e = (AttributeEvent) iter.next(); + if (e.getLocalName().equals("uri")) { + uri = e; + break; + } + } + if (uri != null) { + // If "context" is present then its value will be used + // as the context object in the imported template + String select = attrs.getValue("context"); + JXTExpression expr = null; + if (select != null) { + expr = compileExpr(select, "import: \"context\": ", + locator); + } + StartImport startImport = new StartImport(startElement, + uri, expr); + newEvent = startImport; + } else { + throw new SAXParseException("import: \"uri\" is required", + locator, null); + } + } else if (localName.equals(TEMPLATE)) { + StartTemplate startTemplate = new StartTemplate(startElement); + newEvent = startTemplate; + } else if (localName.equals(COMMENT)) { + // <jx:comment>This will be parsed</jx:comment> + StartComment startJXComment = new StartComment(startElement); + newEvent = startJXComment; + } else { + throw new SAXParseException("unrecognized tag: " + localName, + locator, null); + } + } else { + newEvent = startElement; + } + stack.push(newEvent); + addEvent(newEvent); + } + + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + addEvent(new StartPrefixMapping(locator, prefix, uri)); + } + + public void comment(char ch[], int start, int length) throws SAXException { + //DO NOTHING + } + + public void endCDATA() throws SAXException { + addEvent(new EndCDATA(locator)); + } + + public void endDTD() throws SAXException { + addEvent(new EndDTD(locator)); + } + + public void endEntity(String name) throws SAXException { + addEvent(new EndEntity(locator, name)); + } + + public void startCDATA() throws SAXException { + addEvent(new StartCDATA(locator)); + } + + public void startDTD(String name, String publicId, String systemId) + throws SAXException { + addEvent(new StartDTD(locator, name, publicId, systemId)); + } + + public void startEntity(String name) throws SAXException { + addEvent(new StartEntity(locator, name)); + } + + public static JXTExpression compile(final String variable, boolean xpath) + throws Exception { + Object compiled; + if (xpath) { + compiled = JXPathContext.compile(variable); + } else { + compiled = ExpressionFactory.createExpression(variable); + } + return new JXTExpression(variable, compiled); + } + + public static JXTExpression compileBoolean(String val, String msg, + Locator location) throws SAXException { + JXTExpression res = compileExpr(val, msg, location); + if (res != null) { + if (res.getCompiledExpression() == null) { + res.setCompiledExpression(Boolean.valueOf(res.getRaw())); + } + return res; + } + return null; + } + + /* + * Compile an integer expression (returns either a Compiled Expression or an + * Integer literal) + */ + public static JXTExpression compileInt(String val, String msg, + Locator location) throws SAXException { + JXTExpression res = compileExpr(val, msg, location); + if (res != null) { + if (res.getCompiledExpression() == null) { + res.setCompiledExpression(Integer.valueOf(res.getRaw())); + } + return res; + } + return null; + } + + public static JXTExpression compileExpr(String inStr) throws Exception { + try { + if (inStr == null) { + return null; + } + StringReader in = new StringReader(inStr.trim()); + int ch; + boolean xpath = false; + boolean inExpr = false; + StringBuffer expr = new StringBuffer(); + while ((ch = in.read()) != -1) { + char c = (char) ch; + if (inExpr) { + if (c == '\\') { + ch = in.read(); + expr.append((ch == -1) ? '\\' : (char) ch); + } else if (c == '}') { + return compile(expr.toString(), xpath); + } else { + expr.append(c); + } + } else { + if (c == '$' || c == '#') { + ch = in.read(); + if (ch == '{') { + inExpr = true; + xpath = c == '#'; + continue; + } + } + // hack: invalid expression? + // just return the original and swallow exception + return new JXTExpression(inStr, null); + } + } + if (inExpr) { + // unclosed #{} or ${} + throw new Exception("Unterminated " + (xpath ? "#" : "$") + "{"); + } + } catch (IOException ignored) { + ignored.printStackTrace(); + } + return new JXTExpression(inStr, null); + } + + /** + * Compile a single Jexl expr (contained in ${}) or XPath expression + * (contained in #{}) + */ + + public static JXTExpression compileExpr(String expr, String errorPrefix, + Locator location) throws SAXParseException { + try { + return compileExpr(expr); + } catch (Exception exc) { + throw new SAXParseException(errorPrefix + exc.getMessage(), + location, exc); + } catch (Error err) { + throw new SAXParseException(errorPrefix + err.getMessage(), + location, new ErrorHolder(err)); + } + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/AttributeEvent.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/AttributeEvent.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/AttributeEvent.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,48 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public abstract class AttributeEvent { + public AttributeEvent(String namespaceURI, String localName, String raw, + String type) { + this.namespaceURI = namespaceURI; + this.localName = localName; + this.raw = raw; + this.type = type; + } + + final String namespaceURI; + + public String getLocalName() { + return localName; + } + + public String getNamespaceURI() { + return namespaceURI; + } + + public String getRaw() { + return raw; + } + + public String getType() { + return type; + } + + final String localName; + final String raw; + final String type; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Characters.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Characters.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Characters.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + +public class Characters extends TextEvent { + public Characters(Locator location, char[] chars, int start, int length) + throws SAXException { + super(location, chars, start, length); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/CopyAttribute.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/CopyAttribute.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/CopyAttribute.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class CopyAttribute extends AttributeEvent { + public CopyAttribute(String namespaceURI, String localName, String raw, + String type, String value) { + super(namespaceURI, localName, raw, type); + this.value = value; + } + + public String getValue() { + return value; + } + + private final String value; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndCDATA.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndCDATA.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndCDATA.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndCDATA extends Event { + public EndCDATA(Locator location) { + super(location); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDTD.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDTD.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDTD.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndDTD extends Event { + public EndDTD(Locator location) { + super(location); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDocument.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDocument.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndDocument.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndDocument extends Event { + public EndDocument(Locator location) { + super(location); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndElement.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndElement.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndElement.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndElement extends Event { + public EndElement(Locator location, StartElement startElement) { + super(location); + this.startElement = startElement; + } + + final StartElement startElement; + + public StartElement getStartElement() { + return startElement; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndEntity.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndEntity.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndEntity.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndEntity extends Event { + public EndEntity(Locator location, String name) { + super(location); + this.name = name; + } + + public String getName() { + return name; + } + + private final String name; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndInstruction.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndInstruction.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndInstruction.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,32 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndInstruction extends Event { + public EndInstruction(Locator locator, StartInstruction startInstruction) { + super(locator); + this.startInstruction = startInstruction; + startInstruction.setEndInstruction(this); + } + + final StartInstruction startInstruction; + + public StartInstruction getStartInstruction() { + return startInstruction; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndPrefixMapping.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndPrefixMapping.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/EndPrefixMapping.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class EndPrefixMapping extends Event { + public EndPrefixMapping(Locator location, String prefix) { + super(location); + this.prefix = prefix; + } + + final String prefix; + + public String getPrefix() { + return prefix; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Event.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Event.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/Event.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.JXTemplateGenerator; +import org.xml.sax.Locator; +import org.xml.sax.helpers.LocatorImpl; + +public class Event { + protected final Locator location; + protected Event next; // in document order + + public Event(Locator locator) { + this.location = locator != null ? new LocatorImpl(locator) + : JXTemplateGenerator.NULL_LOCATOR; + } + + public final Locator getLocation() { + return location; + } + + public Event getNext() { + return next; + } + + public void setNext(Event next) { + this.next = next; + } + + public String locationString() { + StringBuffer buf = new StringBuffer(); + buf.append(location.getSystemId()); + if (buf.length() > 0) { + buf.append(", "); + } + buf.append("Line " + location.getLineNumber()); + int col = location.getColumnNumber(); + if (col > 0) { + buf.append("." + col); + } + return buf.toString(); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/IgnorableWhitespace.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/IgnorableWhitespace.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/IgnorableWhitespace.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + +public class IgnorableWhitespace extends TextEvent { + public IgnorableWhitespace(Locator location, char[] chars, int start, + int length) throws SAXException { + super(location, chars, start, length); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/LoopTagStatus.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/LoopTagStatus.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/LoopTagStatus.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,76 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + + +public class LoopTagStatus { + private Object current; + private int index; + private int count; + private boolean first; + private boolean last; + private int begin; + private int end; + private int step; + public void setBegin(int begin) { + this.begin = begin; + } + public int getBegin() { + return begin; + } + public void setEnd(int end) { + this.end = end; + } + public int getEnd() { + return end; + } + public void setStep(int step) { + this.step = step; + } + public int getStep() { + return step; + } + public void setFirst(boolean first) { + this.first = first; + } + public boolean isFirst() { + return first; + } + public void setIndex(int index) { + this.index = index; + } + public int getIndex() { + return index; + } + public void setCount(int count) { + this.count = count; + } + public int getCount() { + return count; + } + public void setCurrent(Object current) { + this.current = current; + } + public Object getCurrent() { + return current; + } + public void setLast(boolean last) { + this.last = last; + } + public boolean isLast() { + return last; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/ProcessingInstruction.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/ProcessingInstruction.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/ProcessingInstruction.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class ProcessingInstruction extends Event { + public ProcessingInstruction(Locator location, String target, String data) { + super(location); + this.target = target; + this.data = data; + } + + public String getData() { + return data; + } + + public String getTarget() { + return target; + } + + private final String target; + private final String data; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SkippedEntity.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SkippedEntity.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SkippedEntity.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class SkippedEntity extends Event { + public SkippedEntity(Locator location, String name) { + super(location); + this.name = name; + } + + final String name; + + public String getName() { + return name; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartCDATA.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartCDATA.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartCDATA.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,24 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class StartCDATA extends Event { + public StartCDATA(Locator location) { + super(location); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartChoose.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartChoose.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartChoose.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartChoose extends StartInstruction { + public StartChoose(StartElement raw) { + super(raw); + } + + public void setFirstChoice(StartWhen firstChoice) { + this.firstChoice = firstChoice; + } + + public StartWhen getFirstChoice() { + return firstChoice; + } + + public void setOtherwise(StartOtherwise otherwise) { + this.otherwise = otherwise; + } + + public StartOtherwise getOtherwise() { + return otherwise; + } + + private StartWhen firstChoice; + private StartOtherwise otherwise; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartComment.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartComment.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartComment.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartComment extends StartInstruction { + public StartComment(StartElement raw) { + super(raw); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDTD.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDTD.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDTD.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,44 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class StartDTD extends Event { + public StartDTD(Locator location, String name, String publicId, + String systemId) { + super(location); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public String getName() { + return name; + } + + public String getPublicId() { + return publicId; + } + + public String getSystemId() { + return systemId; + } + + private final String name; + private final String publicId; + private final String systemId; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDefine.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDefine.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDefine.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,100 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.util.HashMap; +import java.util.Map; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +public class StartDefine extends StartInstruction { + public StartDefine(StartElement raw, String namespace, String name) { + super(raw); + this.namespace = namespace; + this.name = name; + this.qname = "{" + namespace + "}" + name; + this.parameters = new HashMap(); + } + + final String name; + final String namespace; + private final String qname; + private final Map parameters; + private Event body; + + public void finish() throws SAXException { + Event e = next; + boolean params = true; + while (e != this.endInstruction) { + if (e instanceof StartParameter) { + StartParameter startParam = (StartParameter) e; + if (!params) { + throw new SAXParseException( + "<parameter> not allowed here: \"" + + startParam.name + "\"", startParam + .getLocation(), null); + } + Object prev = getParameters().put(startParam.name, startParam); + if (prev != null) { + throw new SAXParseException("duplicate parameter: \"" + + startParam.name + "\"", location, null); + } + e = startParam.endInstruction; + } else if (e instanceof IgnorableWhitespace) { + // EMPTY + } else if (e instanceof Characters) { + // check for whitespace + char[] ch = ((TextEvent) e).getRaw(); + int len = ch.length; + for (int i = 0; i < len; i++) { + if (!Character.isWhitespace(ch[i])) { + if (params) { + params = false; + setBody(e); + } + break; + } + } + } else { + if (params) { + params = false; + setBody(e); + } + } + e = e.getNext(); + } + if (this.getBody() == null) { + this.setBody(this.endInstruction); + } + } + + public Map getParameters() { + return parameters; + } + + void setBody(Event body) { + this.body = body; + } + + public Event getBody() { + return body; + } + + public String getQname() { + return qname; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDocument.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDocument.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartDocument.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,61 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.excalibur.source.SourceValidity; +import org.xml.sax.Locator; + +public class StartDocument extends Event { + public StartDocument(Locator location) { + super(location); + templateProperties = new HashMap(); + } + + private SourceValidity compileTime; + EndDocument endDocument; // null if document fragment + Map templateProperties; + + public EndDocument getEndDocument() { + return endDocument; + } + + public void setEndDocument(EndDocument endDoc) { + this.endDocument = endDoc; + } + + public Map getTemplateProperties() { + return templateProperties; + } + + /** + * @param compileTime + * The compileTime to set. + */ + public void setCompileTime(SourceValidity compileTime) { + this.compileTime = compileTime; + } + + /** + * @return Returns the compileTime. + */ + public SourceValidity getCompileTime() { + return compileTime; + } + +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartElement.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartElement.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartElement.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,174 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.io.IOException; +import java.io.StringReader; +import java.util.LinkedList; +import java.util.List; + +import org.apache.cocoon.template.jxtg.environment.ErrorHolder; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.cocoon.template.jxtg.expression.Literal; +import org.apache.cocoon.template.jxtg.script.Parser; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; + +public class StartElement extends Event { + public StartElement(Locator location, String namespaceURI, + String localName, String raw, Attributes attrs) throws SAXException { + super(location); + this.namespaceURI = namespaceURI; + this.localName = localName; + this.raw = raw; + this.qname = "{" + namespaceURI + "}" + localName; + StringBuffer buf = new StringBuffer(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) { + String uri = attrs.getURI(i); + String local = attrs.getLocalName(i); + String qname = attrs.getQName(i); + String type = attrs.getType(i); + String value = attrs.getValue(i); + StringReader in = new StringReader(value); + int ch; + buf.setLength(0); + boolean inExpr = false; + List substEvents = new LinkedList(); + boolean xpath = false; + try { + top: while ((ch = in.read()) != -1) { + char c = (char) ch; + processChar: while (true) { + if (inExpr) { + if (c == '\\') { + ch = in.read(); + buf.append(ch == -1 ? '\\' : (char) ch); + } else if (c == '}') { + String str = buf.toString(); + JXTExpression compiledExpression; + try { + compiledExpression = Parser.compile(str, + xpath); + } catch (Exception exc) { + throw new SAXParseException(exc + .getMessage(), location, exc); + } catch (Error err) { + throw new SAXParseException(err + .getMessage(), location, + new ErrorHolder(err)); + } + substEvents.add(compiledExpression); + buf.setLength(0); + inExpr = false; + } else { + buf.append(c); + } + } else if (c == '$' || c == '#') { + ch = in.read(); + if (ch == '{') { + if (buf.length() > 0) { + substEvents + .add(new Literal(buf.toString())); + buf.setLength(0); + } + inExpr = true; + xpath = c == '#'; + continue top; + } + buf.append(c); + if (ch != -1) { + c = (char) ch; + continue processChar; + } + } else { + buf.append(c); + } + break; + } + } + } catch (IOException ignored) { + ignored.printStackTrace(); + } + if (inExpr) { + // unclosed #{} or ${} + String msg = "Unterminated " + (xpath ? "#" : "$") + "{"; + throw new SAXParseException(msg, location, null); + } + if (buf.length() > 0) { + if (substEvents.size() == 0) { + getAttributeEvents().add( + new CopyAttribute(uri, local, qname, type, value)); + } else { + substEvents.add(new Literal(buf.toString())); + getAttributeEvents().add( + new SubstituteAttribute(uri, local, qname, type, + substEvents)); + } + } else { + if (substEvents.size() > 0) { + getAttributeEvents().add( + new SubstituteAttribute(uri, local, qname, type, + substEvents)); + } else { + getAttributeEvents().add( + new CopyAttribute(uri, local, qname, type, "")); + } + } + } + this.attributes = new AttributesImpl(attrs); + } + + final String namespaceURI; + final String localName; + final String raw; + private final String qname; + private final List attributeEvents = new LinkedList(); + final Attributes attributes; + EndElement endElement; + + public EndElement getEndElement() { + return endElement; + } + + public String getLocalName() { + return localName; + } + + public String getNamespaceURI() { + return namespaceURI; + } + + public String getRaw() { + return raw; + } + + public String getQname() { + return qname; + } + + public List getAttributeEvents() { + return attributeEvents; + } + + public void setEndElement(EndElement endElement) { + this.endElement = endElement; + + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEntity.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEntity.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEntity.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class StartEntity extends Event { + public StartEntity(Locator location, String name) { + super(location); + this.name = name; + } + + public String getName() { + return name; + } + + private final String name; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEval.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEval.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEval.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartEval extends StartInstruction { + public StartEval(StartElement raw, JXTExpression value) { + super(raw); + this.value = value; + } + + public JXTExpression getValue() { + return value; + } + + private final JXTExpression value; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEvalBody.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEvalBody.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartEvalBody.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartEvalBody extends StartInstruction { + public StartEvalBody(StartElement raw) { + super(raw); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartForEach.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartForEach.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartForEach.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartForEach extends StartInstruction { + public StartForEach(StartElement raw, JXTExpression items, + JXTExpression var, JXTExpression varStatus, JXTExpression begin, + JXTExpression end, JXTExpression step, Boolean lenient) { + super(raw); + this.items = items; + this.var = var; + this.varStatus = varStatus; + this.begin = begin; + this.end = end; + this.step = step; + this.lenient = lenient; + } + + final JXTExpression items; + final JXTExpression var; + final JXTExpression varStatus; + final JXTExpression begin; + final JXTExpression end; + final JXTExpression step; + final Boolean lenient; + + public JXTExpression getBegin() { + return begin; + } + + public JXTExpression getEnd() { + return end; + } + + public JXTExpression getItems() { + return items; + } + + public Boolean getLenient() { + return lenient; + } + + public JXTExpression getStep() { + return step; + } + + public JXTExpression getVar() { + return var; + } + + public JXTExpression getVarStatus() { + return varStatus; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatDate.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatDate.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatDate.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,164 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.cocoon.template.jxtg.environment.ValueHelper; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.commons.jexl.JexlContext; +import org.apache.commons.jxpath.JXPathContext; + +public class StartFormatDate extends StartInstruction { + + private static final String DATE = "date"; + private static final String TIME = "time"; + private static final String DATETIME = "both"; + + JXTExpression var; + JXTExpression value; + JXTExpression type; + JXTExpression pattern; + JXTExpression timeZone; + JXTExpression dateStyle; + JXTExpression timeStyle; + JXTExpression locale; + + public StartFormatDate(StartElement raw, JXTExpression var, + JXTExpression value, JXTExpression type, JXTExpression pattern, + JXTExpression timeZone, JXTExpression dateStyle, + JXTExpression timeStyle, JXTExpression locale) { + super(raw); + this.var = var; + this.value = value; + this.type = type; + this.pattern = pattern; + this.timeZone = timeZone; + this.dateStyle = dateStyle; + this.timeStyle = timeStyle; + this.locale = locale; + } + + public String format(JexlContext jexl, JXPathContext jxp) throws Exception { + String var = ValueHelper.getStringValue(this.var, jexl, jxp); + Object value = ValueHelper.getValue(this.value, jexl, jxp); + Object locVal = ValueHelper.getValue(this.locale, jexl, jxp); + String pattern = ValueHelper.getStringValue(this.pattern, jexl, + jxp); + Object timeZone = ValueHelper + .getValue(this.timeZone, jexl, jxp); + + String type = ValueHelper.getStringValue(this.type, jexl, jxp); + String timeStyle = ValueHelper.getStringValue(this.timeStyle, + jexl, jxp); + String dateStyle = ValueHelper.getStringValue(this.dateStyle, + jexl, jxp); + + String formatted = null; + + // Create formatter + Locale locale; + if (locVal != null) { + locale = locVal instanceof Locale ? (Locale) locVal + : ValueHelper.parseLocale(locVal.toString(), null); + } else { + locale = Locale.getDefault(); + } + DateFormat formatter = createFormatter(locale, type, dateStyle, + timeStyle); + // Apply pattern, if present + if (pattern != null) { + try { + ((SimpleDateFormat) formatter).applyPattern(pattern); + } catch (ClassCastException cce) { + formatter = new SimpleDateFormat(pattern, locale); + } + } + // Set time zone + TimeZone tz = null; + if ((timeZone instanceof String) && ((String) timeZone).equals("")) { + timeZone = null; + } + if (timeZone != null) { + if (timeZone instanceof String) { + tz = TimeZone.getTimeZone((String) timeZone); + } else if (timeZone instanceof TimeZone) { + tz = (TimeZone) timeZone; + } else { + throw new IllegalArgumentException("Illegal timeZone value: \"" + + timeZone + "\""); + } + } + if (tz != null) { + formatter.setTimeZone(tz); + } + formatted = formatter.format(value); + if (var != null) { + jexl.getVars().put(var, formatted); + jxp.getVariables().declareVariable(var, formatted); + return null; + } + return formatted; + } + + private DateFormat createFormatter(Locale loc, String type, + String dateStyle, String timeStyle) throws Exception { + DateFormat formatter = null; + if ((type == null) || DATE.equalsIgnoreCase(type)) { + formatter = DateFormat.getDateInstance(getStyle(dateStyle), loc); + } else if (TIME.equalsIgnoreCase(type)) { + formatter = DateFormat.getTimeInstance(getStyle(timeStyle), loc); + } else if (DATETIME.equalsIgnoreCase(type)) { + formatter = DateFormat.getDateTimeInstance(getStyle(dateStyle), + getStyle(timeStyle), loc); + } else { + throw new IllegalArgumentException("Invalid type: \"" + type + "\""); + } + return formatter; + } + + private static final String DEFAULT = "default"; + private static final String SHORT = "short"; + private static final String MEDIUM = "medium"; + private static final String LONG = "long"; + private static final String FULL = "full"; + + private int getStyle(String style) { + int ret = DateFormat.DEFAULT; + if (style != null) { + if (DEFAULT.equalsIgnoreCase(style)) { + ret = DateFormat.DEFAULT; + } else if (SHORT.equalsIgnoreCase(style)) { + ret = DateFormat.SHORT; + } else if (MEDIUM.equalsIgnoreCase(style)) { + ret = DateFormat.MEDIUM; + } else if (LONG.equalsIgnoreCase(style)) { + ret = DateFormat.LONG; + } else if (FULL.equalsIgnoreCase(style)) { + ret = DateFormat.FULL; + } else { + throw new IllegalArgumentException( + "Invalid style: \"" + + style + + "\": should be \"default\" or \"short\" or \"medium\" or \"long\" or \"full\""); + } + } + return ret; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatNumber.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatNumber.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartFormatNumber.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,253 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.lang.reflect.Method; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; + +import org.apache.cocoon.template.jxtg.environment.ValueHelper; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.commons.jexl.JexlContext; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.lang.StringUtils; + +public class StartFormatNumber extends StartInstruction { + + JXTExpression value; + JXTExpression type; + JXTExpression pattern; + JXTExpression currencyCode; + JXTExpression currencySymbol; + JXTExpression isGroupingUsed; + JXTExpression maxIntegerDigits; + JXTExpression minIntegerDigits; + JXTExpression maxFractionDigits; + JXTExpression minFractionDigits; + JXTExpression locale; + + JXTExpression var; + + private static Class currencyClass; + private static final String NUMBER = "number"; + private static final String CURRENCY = "currency"; + private static final String PERCENT = "percent"; + + static { + try { + currencyClass = Class.forName("java.util.Currency"); + // container's runtime is J2SE 1.4 or greater + } catch (Exception cnfe) { + // EMPTY + } + } + + public StartFormatNumber(StartElement raw, JXTExpression var, + JXTExpression value, JXTExpression type, JXTExpression pattern, + JXTExpression currencyCode, JXTExpression currencySymbol, + JXTExpression isGroupingUsed, JXTExpression maxIntegerDigits, + JXTExpression minIntegerDigits, JXTExpression maxFractionDigits, + JXTExpression minFractionDigits, JXTExpression locale) { + super(raw); + this.var = var; + this.value = value; + this.type = type; + this.pattern = pattern; + this.currencyCode = currencyCode; + this.currencySymbol = currencySymbol; + this.isGroupingUsed = isGroupingUsed; + this.maxIntegerDigits = maxIntegerDigits; + this.minIntegerDigits = minIntegerDigits; + this.maxFractionDigits = maxFractionDigits; + this.minFractionDigits = minFractionDigits; + this.locale = locale; + } + + public String format(JexlContext jexl, JXPathContext jxp) throws Exception { + // Determine formatting locale + String var = ValueHelper.getStringValue(this.var, jexl, jxp); + Number input = ValueHelper + .getNumberValue(this.value, jexl, jxp); + String type = ValueHelper.getStringValue(this.type, jexl, jxp); + String pattern = ValueHelper.getStringValue(this.pattern, jexl, + jxp); + String currencyCode = ValueHelper.getStringValue( + this.currencyCode, jexl, jxp); + String currencySymbol = ValueHelper.getStringValue( + this.currencySymbol, jexl, jxp); + Boolean isGroupingUsed = ValueHelper.getBooleanValue( + this.isGroupingUsed, jexl, jxp); + Number maxIntegerDigits = ValueHelper.getNumberValue( + this.maxIntegerDigits, jexl, jxp); + Number minIntegerDigits = ValueHelper.getNumberValue( + this.minIntegerDigits, jexl, jxp); + Number maxFractionDigits = ValueHelper.getNumberValue( + this.maxFractionDigits, jexl, jxp); + Number minFractionDigits = ValueHelper.getNumberValue( + this.minFractionDigits, jexl, jxp); + String localeStr = ValueHelper.getStringValue(this.locale, + jexl, jxp); + Locale loc = localeStr != null ? ValueHelper.parseLocale( + localeStr, null) : Locale.getDefault(); + String formatted; + if (loc != null) { + // Create formatter + NumberFormat formatter = null; + if (StringUtils.isNotEmpty(pattern)) { + // if 'pattern' is specified, 'type' is ignored + DecimalFormatSymbols symbols = new DecimalFormatSymbols(loc); + formatter = new DecimalFormat(pattern, symbols); + } else { + formatter = createFormatter(loc, type); + } + if (StringUtils.isNotEmpty(pattern) + || CURRENCY.equalsIgnoreCase(type)) { + setCurrency(formatter, currencyCode, currencySymbol); + } + configureFormatter(formatter, isGroupingUsed, maxIntegerDigits, + minIntegerDigits, maxFractionDigits, minFractionDigits); + formatted = formatter.format(input); + } else { + // no formatting locale available, use toString() + formatted = input.toString(); + } + if (var != null) { + jexl.getVars().put(var, formatted); + jxp.getVariables().declareVariable(var, formatted); + return null; + } + return formatted; + } + + private NumberFormat createFormatter(Locale loc, String type) + throws Exception { + NumberFormat formatter = null; + if ((type == null) || NUMBER.equalsIgnoreCase(type)) { + formatter = NumberFormat.getNumberInstance(loc); + } else if (CURRENCY.equalsIgnoreCase(type)) { + formatter = NumberFormat.getCurrencyInstance(loc); + } else if (PERCENT.equalsIgnoreCase(type)) { + formatter = NumberFormat.getPercentInstance(loc); + } else { + throw new IllegalArgumentException("Invalid type: \"" + type + + "\": should be \"number\" or \"currency\" or \"percent\""); + } + return formatter; + } + + /* + * Applies the 'groupingUsed', 'maxIntegerDigits', 'minIntegerDigits', + * 'maxFractionDigits', and 'minFractionDigits' attributes to the given + * formatter. + */ + private void configureFormatter(NumberFormat formatter, + Boolean isGroupingUsed, Number maxIntegerDigits, + Number minIntegerDigits, Number maxFractionDigits, + Number minFractionDigits) { + if (isGroupingUsed != null) + formatter.setGroupingUsed(isGroupingUsed.booleanValue()); + if (maxIntegerDigits != null) + formatter.setMaximumIntegerDigits(maxIntegerDigits.intValue()); + if (minIntegerDigits != null) + formatter.setMinimumIntegerDigits(minIntegerDigits.intValue()); + if (maxFractionDigits != null) + formatter.setMaximumFractionDigits(maxFractionDigits.intValue()); + if (minFractionDigits != null) + formatter.setMinimumFractionDigits(minFractionDigits.intValue()); + } + + /* + * Override the formatting locale's default currency symbol with the + * specified currency code (specified via the "currencyCode" attribute) or + * currency symbol (specified via the "currencySymbol" attribute). + * + * If both "currencyCode" and "currencySymbol" are present, "currencyCode" + * takes precedence over "currencySymbol" if the java.util.Currency class is + * defined in the container's runtime (that is, if the container's runtime + * is J2SE 1.4 or greater), and "currencySymbol" takes precendence over + * "currencyCode" otherwise. + * + * If only "currencyCode" is given, it is used as a currency symbol if + * java.util.Currency is not defined. + * + * Example: + * + * JDK "currencyCode" "currencySymbol" Currency symbol being displayed + * ----------------------------------------------------------------------- + * all --- --- Locale's default currency symbol + * + * <1.4 EUR --- EUR >=1.4 EUR --- Locale's currency symbol for Euro + * + * all --- \u20AC \u20AC + * + * <1.4 EUR \u20AC \u20AC >=1.4 EUR \u20AC Locale's currency symbol for Euro + */ + private void setCurrency(NumberFormat formatter, String currencyCode, + String currencySymbol) throws Exception { + String code = null; + String symbol = null; + + if (currencyCode == null) { + if (currencySymbol == null) { + return; + } + symbol = currencySymbol; + } else if (currencySymbol != null) { + if (currencyClass != null) { + code = currencyCode; + } else { + symbol = currencySymbol; + } + } else if (currencyClass != null) { + code = currencyCode; + } else { + symbol = currencyCode; + } + if (code != null) { + Object[] methodArgs = new Object[1]; + + /* + * java.util.Currency.getInstance() + */ + Method m = currencyClass.getMethod("getInstance", + new Class[] { String.class }); + + methodArgs[0] = code; + Object currency = m.invoke(null, methodArgs); + + /* + * java.text.NumberFormat.setCurrency() + */ + Class[] paramTypes = new Class[1]; + paramTypes[0] = currencyClass; + Class numberFormatClass = Class.forName("java.text.NumberFormat"); + m = numberFormatClass.getMethod("setCurrency", paramTypes); + methodArgs[0] = currency; + m.invoke(formatter, methodArgs); + } else { + /* + * Let potential ClassCastException propagate up (will almost never + * happen) + */ + DecimalFormat df = (DecimalFormat) formatter; + DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + dfs.setCurrencySymbol(symbol); + df.setDecimalFormatSymbols(dfs); + } + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartIf.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartIf.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartIf.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartIf extends StartInstruction { + public StartIf(StartElement raw, JXTExpression test) { + super(raw); + this.test = test; + } + + final JXTExpression test; + + public JXTExpression getTest() { + return test; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartImport.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartImport.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartImport.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartImport extends StartInstruction { + public StartImport(StartElement raw, AttributeEvent uri, + JXTExpression select) { + super(raw); + this.uri = uri; + this.select = select; + } + + public AttributeEvent getUri() { + return uri; + } + + public JXTExpression getSelect() { + return select; + } + + private final AttributeEvent uri; + private final JXTExpression select; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartInstruction.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartInstruction.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartInstruction.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,35 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + + +public class StartInstruction extends Event { + StartInstruction(StartElement startElement) { + super(startElement.getLocation()); + this.startElement = startElement; + } + + final StartElement startElement; + EndInstruction endInstruction; + + public EndInstruction getEndInstruction() { + return endInstruction; + } + + public void setEndInstruction(EndInstruction endInstruction) { + this.endInstruction = endInstruction; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOtherwise.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOtherwise.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOtherwise.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartOtherwise extends StartInstruction { + public StartOtherwise(StartElement raw) { + super(raw); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOut.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOut.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartOut.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartOut extends StartInstruction { + public StartOut(StartElement raw, JXTExpression expr, Boolean lenient) { + super(raw); + this.compiledExpression = expr; + this.lenient = lenient; + } + + public JXTExpression getCompiledExpression() { + return compiledExpression; + } + + public Boolean getLenient() { + return lenient; + } + + private final JXTExpression compiledExpression; + private final Boolean lenient; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartParameter.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartParameter.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartParameter.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,34 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartParameter extends StartInstruction { + public StartParameter(StartElement raw, String name, String optional, + String defaultValue) { + super(raw); + this.name = name; + this.optional = optional; + this.defaultValue = defaultValue; + } + + public String getDefaultValue() { + return defaultValue; + } + + final String name; + final String optional; + private final String defaultValue; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartPrefixMapping.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartPrefixMapping.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartPrefixMapping.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.xml.sax.Locator; + +public class StartPrefixMapping extends Event { + public StartPrefixMapping(Locator location, String prefix, String uri) { + super(location); + this.prefix = prefix; + this.uri = uri; + } + + public String getPrefix() { + return prefix; + } + + public String getUri() { + return uri; + } + + private final String prefix; + private final String uri; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartSet.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartSet.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartSet.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,37 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartSet extends StartInstruction { + public StartSet(StartElement raw, JXTExpression var, JXTExpression value) { + super(raw); + this.var = var; + this.value = value; + } + + public JXTExpression getVar() { + return var; + } + + public JXTExpression getValue() { + return value; + } + + private final JXTExpression var; + private final JXTExpression value; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartTemplate.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartTemplate.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartTemplate.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,22 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +public class StartTemplate extends StartInstruction { + public StartTemplate(StartElement raw) { + super(raw); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartWhen.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartWhen.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/StartWhen.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import org.apache.cocoon.template.jxtg.expression.JXTExpression; + +public class StartWhen extends StartInstruction { + public StartWhen(StartElement raw, JXTExpression test) { + super(raw); + this.test = test; + } + + public JXTExpression getTest() { + return test; + } + + public void setNextChoice(StartWhen nextChoice) { + this.nextChoice = nextChoice; + } + + public StartWhen getNextChoice() { + return nextChoice; + } + + private final JXTExpression test; + private StartWhen nextChoice; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SubstituteAttribute.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SubstituteAttribute.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/SubstituteAttribute.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,33 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.util.List; + + +public class SubstituteAttribute extends AttributeEvent { + public SubstituteAttribute(String namespaceURI, String localName, + String raw, String type, List substs) { + super(namespaceURI, localName, raw, type); + this.substitutions = substs; + } + + public List getSubstitutions() { + return substitutions; + } + + private final List substitutions; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/TextEvent.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/TextEvent.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/jxtg/script/event/TextEvent.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,132 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.jxtg.script.event; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; + +import org.apache.cocoon.template.jxtg.environment.ErrorHolder; +import org.apache.cocoon.template.jxtg.expression.JXTExpression; +import org.apache.commons.jexl.ExpressionFactory; +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.lang.ArrayUtils; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +public class TextEvent extends Event { + public TextEvent(Locator location, char[] chars, int start, int length) + throws SAXException { + super(location); + StringBuffer buf = new StringBuffer(); + this.raw = new char[length]; + System.arraycopy(chars, start, this.raw, 0, length); + CharArrayReader in = new CharArrayReader(chars, start, length); + int ch; + boolean inExpr = false; + boolean xpath = false; + try { + top: while ((ch = in.read()) != -1) { + // column++; + char c = (char) ch; + processChar: while (true) { + if (inExpr) { + if (c == '\\') { + ch = in.read(); + buf.append(ch == -1 ? '\\' : (char) ch); + } else if (c == '}') { + String str = buf.toString(); + Object compiledExpression; + try { + if (xpath) { + compiledExpression = JXPathContext + .compile(str); + } else { + compiledExpression = ExpressionFactory + .createExpression(str); + } + } catch (Exception exc) { + throw new SAXParseException(exc.getMessage(), + this.getLocation(), exc); + } catch (Error err) { + throw new SAXParseException(err.getMessage(), + this.getLocation(), + new ErrorHolder(err)); + + } + substitutions.add(new JXTExpression(str, + compiledExpression)); + buf.setLength(0); + inExpr = false; + } else { + buf.append(c); + } + } else if (c == '$' || c == '#') { + ch = in.read(); + if (ch == '{') { + xpath = c == '#'; + inExpr = true; + if (buf.length() > 0) { + char[] charArray = new char[buf.length()]; + + buf.getChars(0, buf.length(), charArray, 0); + substitutions.add(charArray); + buf.setLength(0); + } + continue top; + } + buf.append(c); + if (ch != -1) { + c = (char) ch; + continue processChar; + } + } else { + buf.append(c); + } + break; + } + } + } catch (IOException ignored) { + // won't happen + ignored.printStackTrace(); + } + if (inExpr) { + // unclosed #{} or ${} + buf.insert(0, (xpath ? "#" : "$") + "{"); + } + if (buf.length() > 0) { + char[] charArray = new char[buf.length()]; + + buf.getChars(0, buf.length(), charArray, 0); + substitutions.add(charArray); + } else if (substitutions.isEmpty()) { + substitutions.add(ArrayUtils.EMPTY_CHAR_ARRAY); + } + } + + final List substitutions = new LinkedList(); + final char[] raw; + + public char[] getRaw() { + return raw; + } + + public List getSubstitutions() { + return substitutions; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/generation/TemplateGenerator.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/generation/TemplateGenerator.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/generation/TemplateGenerator.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,95 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.generation; + +import java.io.IOException; +import java.util.HashMap; + +import org.apache.avalon.framework.configuration.Configurable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.logger.Logger; +import org.apache.cocoon.ProcessingException; +import org.apache.cocoon.components.source.SourceUtil; +import org.apache.cocoon.el.ExpressionCompiler; +import org.apache.cocoon.el.GenericExpressionCompiler; +import org.apache.cocoon.generation.ServiceableGenerator; +import org.apache.cocoon.template.v2.script.Script; +import org.apache.cocoon.template.v2.script.ScriptCompiler; +import org.apache.cocoon.template.v2.script.ScriptContext; +import org.apache.cocoon.template.v2.script.ScriptInvoker; +import org.apache.cocoon.template.v2.script.TagRepository; +import org.apache.cocoon.util.IncludingConfiguration; +import org.apache.excalibur.source.Source; +import org.xml.sax.SAXException; + +public class TemplateGenerator extends ServiceableGenerator implements + Configurable { + static HashMap cache = new HashMap(); + + TagRepository tagRepository = new TagRepository(); + + ExpressionCompiler expressionCompiler = GenericExpressionCompiler + .getInstance(); + + public void enableLogging(Logger logger) { + super.enableLogging(logger); + tagRepository.enableLogging(logger); + } + + public void configure(Configuration conf) throws ConfigurationException { + IncludingConfiguration newConf = new IncludingConfiguration(conf, + manager); + tagRepository.configure(newConf); + } + + public TagRepository getTagRepository() { + return tagRepository; + } + + public void generate() throws IOException, SAXException, + ProcessingException { + try { + Source inputSource = resolver.resolveURI(source); + + Script script = null; + synchronized (cache) { + script = (Script) cache.get(inputSource.getURI()); + if (script == null) { + script = compileScript(inputSource); + cache.put(inputSource.getURI(), script); + } + } + + ScriptContext context = new ScriptContext(); + context.setConsumer(xmlConsumer); + + // TODO: populate context + + ScriptInvoker scriptInvoker = new ScriptInvoker(script, context); + scriptInvoker.invoke(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected Script compileScript(Source inputSource) throws Exception { + ScriptCompiler compiler = new ScriptCompiler(tagRepository, + expressionCompiler); + SourceUtil.parse(manager, inputSource, compiler); + return compiler.getScript(); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AbstractToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AbstractToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AbstractToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,38 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public abstract class AbstractToken implements Token { + protected int start; + protected int end; + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AttributeToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AttributeToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/AttributeToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,41 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public class AttributeToken extends AbstractToken { + String namespace; + String lname; + String qname; + + public void setup(String namespace, String lname, String qname) { + this.namespace = namespace; + this.lname = lname; + this.qname = qname; + } + + public String getNamespace() { + return namespace; + } + + public String getLName() { + return lname; + } + + public String getQName() { + return qname; + } +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/CharactersToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/CharactersToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/CharactersToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public class CharactersToken extends AbstractToken { + char[] characters; + + public void setup(CharSequence characters) { + // TODO: this should be done better + this.characters = characters.toString().toCharArray(); + } + + public char[] getCharacters() { + return characters; + } +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ElementToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ElementToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ElementToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,23 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public interface ElementToken extends Token { + public int getBodyStart(); + + public void setBodyStart(int bodyStart); +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ExpressionToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ExpressionToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ExpressionToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,31 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import org.apache.cocoon.el.Expression; + +public class ExpressionToken extends AbstractToken { + Expression expression; + + public void setup(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/PlainElementToken.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/PlainElementToken.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/PlainElementToken.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,50 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public class PlainElementToken extends AbstractToken implements ElementToken { + protected String namespace; + protected String lname; + protected String qname; + protected int bodyStart; + + public void setup(String namespace, String lname, String qname) { + this.namespace = namespace; + this.lname = lname; + this.qname = qname; + } + + public String getNamespace() { + return namespace; + } + + public String getLName() { + return lname; + } + + public String getQName() { + return qname; + } + + public int getBodyStart() { + return bodyStart; + } + + public void setBodyStart(int bodyStart) { + this.bodyStart = bodyStart; + } +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Script.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Script.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Script.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,45 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import java.util.ArrayList; +import java.util.List; + +public class Script { + ArrayList tokens = new ArrayList(); + + public void add(Token token) { + token.setStart(size()); + tokens.add(token); + } + + public void addAtom(Token token) { + add(token); + token.setEnd(size()); + } + + public Token get(int i) { + return (Token) tokens.get(i); + } + + public int size() { + return tokens.size(); + } + + public List getTokens() { + return tokens; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptCompiler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptCompiler.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptCompiler.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,97 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import java.nio.CharBuffer; +import java.util.Stack; + +import org.apache.cocoon.el.ExpressionCompiler; +import org.apache.cocoon.el.util.ELUtils; +import org.apache.cocoon.el.util.ParseHandler; +import org.apache.cocoon.xml.AbstractXMLConsumer; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +public class ScriptCompiler extends AbstractXMLConsumer { + static final int TEXT = 1; + static final int EXPRESSION = 2; + Script script = new Script(); + TextParseHandler parseHandler = new TextParseHandler(); + Stack openedTokens = new Stack(); + TagRepository tagRepository; + ExpressionCompiler expressionCompiler; + + public ScriptCompiler(TagRepository tagRepository, + ExpressionCompiler expressionCompiler) { + this.tagRepository = tagRepository; + this.expressionCompiler = expressionCompiler; + } + + public Script getScript() { + return script; + } + + public void startElement(String namespace, String lname, String qname, + Attributes atts) throws SAXException { + ElementToken token; + + if (tagRepository.contains(namespace, lname)) { + token = tagRepository.getTag(namespace, lname); + } else { + token = new PlainElementToken(); + ((PlainElementToken) token).setup(namespace, lname, qname); + } + + script.add(token); + openedTokens.push(token); + + for (int i = 0; i < atts.getLength(); i++) { + AttributeToken attrToken = new AttributeToken(); + attrToken.setup(atts.getURI(i), atts.getLocalName(i), atts + .getQName(i)); + script.add(attrToken); + ELUtils.parse(CharBuffer.wrap(atts.getValue(i)), parseHandler); + attrToken.setEnd(script.size()); + } + + token.setBodyStart(script.size()); + } + + public void endElement(String namespace, String lname, String qname) + throws SAXException { + Token token = (Token) openedTokens.pop(); + token.setEnd(script.size()); + } + + public void characters(char ch[], int start, int length) + throws SAXException { + ELUtils.parse(CharBuffer.wrap(ch, start, length), parseHandler); + } + + public class TextParseHandler implements ParseHandler { + public void handleExpression(CharSequence characters) { + ExpressionToken token = new ExpressionToken(); + token.setup(expressionCompiler.compile(characters.toString())); + script.addAtom(token); + } + + public void handleText(CharSequence characters) { + CharactersToken token = new CharactersToken(); + token.setup(characters); + script.addAtom(token); + } + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptContext.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptContext.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptContext.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import org.apache.cocoon.el.DefaultContext; +import org.apache.cocoon.xml.XMLConsumer; + +public class ScriptContext extends DefaultContext { + XMLConsumer consumer; + ScriptInvoker scriptInvoker; + + public XMLConsumer getConsumer() { + return consumer; + } + + public void setConsumer(XMLConsumer consumer) { + this.consumer = consumer; + } + + public ScriptInvoker getScriptInvoker() { + return scriptInvoker; + } + + public void setScriptInvoker(ScriptInvoker scriptInvoker) { + this.scriptInvoker = scriptInvoker; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptInvoker.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptInvoker.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/ScriptInvoker.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,117 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import org.apache.cocoon.template.v2.tag.Tag; +import org.apache.cocoon.xml.XMLConsumer; +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; + +public class ScriptInvoker { + + public static final String CDATA = "CDATA"; + + Script script; + + ScriptContext context; + + XMLConsumer consumer; + + public ScriptInvoker(Script script, ScriptContext context) { + this.script = script; + this.context = context; + this.consumer = context.getConsumer(); + context.setScriptInvoker(this); + } + + public void invoke() throws Exception { + consumer.startDocument(); + invoke(0, script.size()); + consumer.endDocument(); + } + + public void invoke(int start, int end) throws Exception { + + for (int i = start; i < end;) { + Token tok = script.get(i); + + if (tok instanceof PlainElementToken) { + PlainElementToken token = (PlainElementToken) tok; + Attributes attributes = getElementAttributes( + token.getStart() + 1, token.getBodyStart()); + consumer.startElement(token.getNamespace(), token.getLName(), + token.getQName(), attributes); + invoke(token.getBodyStart(), token.getEnd()); + consumer.endElement(token.getNamespace(), token.getLName(), + token.getQName()); + + } else if (tok instanceof Tag) { + ((Tag) tok).invoke(context); + + } else if (tok instanceof CharactersToken) { + char[] characters = ((CharactersToken) tok).getCharacters(); + consumer.characters(characters, 0, characters.length); + + } else if (tok instanceof ExpressionToken) { + char[] value = ((ExpressionToken) tok).getExpression() + .toCharArray(context); + consumer.characters(value, 0, value.length); + + } else { + throw new RuntimeException("Illegal token"); + } + + i = tok.getEnd(); + } + } + + public Attributes getElementAttributes(int start, int end) throws Exception { + AttributesImpl attributes = new AttributesImpl(); + + for (int i = start; i < end;) { + Token tok = script.get(i); + + if (tok instanceof AttributeToken) { + AttributeToken token = (AttributeToken) tok; + String value = getText(token.getStart() + 1, token.getEnd()); + attributes.addAttribute(token.getNamespace(), token.getLName(), + token.getQName(), CDATA, value); + i = token.getEnd(); + } else { + throw new RuntimeException("Illegal token"); + } + } + + return attributes; + } + + public String getText(int start, int end) throws Exception { + StringBuffer text = new StringBuffer(); + + for (int i = start; i < end; i++) { + Token token = script.get(i); + + if (token instanceof CharactersToken) + text.append(((CharactersToken) token).getCharacters()); + else if (token instanceof ExpressionToken) + text.append(((ExpressionToken) token).getExpression().toString( + context)); + else + throw new RuntimeException("Illegal token"); + } + return text.toString(); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/TagRepository.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/TagRepository.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/TagRepository.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,73 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +import java.util.HashMap; + +import org.apache.avalon.framework.configuration.Configurable; +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.cocoon.template.v2.tag.Tag; + +public class TagRepository extends AbstractLogEnabled implements Configurable { + HashMap tagMap = new HashMap(); + + public void configure(Configuration conf) throws ConfigurationException { + configureTags(conf.getChildren("tag")); + } + + public void configureTags(Configuration[] confs) + throws ConfigurationException { + for (int i = 0; i < confs.length; i++) { + registerTag(confs[i].getAttribute("namespace"), confs[i] + .getAttribute("name"), confs[i].getAttribute("src")); + } + } + + public void registerTag(String namespace, String name, String src) { + try { + registerTag(namespace, name, Class.forName(src)); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Class not found", e); + } + + } + + public void registerTag(String namespace, String name, Class clazz) { + tagMap.put(createKey(namespace, name), clazz); + if (getLogger().isInfoEnabled()) + getLogger().info("Registered tag: namespace=" + namespace + ", name=" + + name + ", src=" + clazz.getName()); + } + + public Tag getTag(String namespace, String name) { + try { + Class type = (Class) tagMap.get(createKey(namespace, name)); + return (Tag) type.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public boolean contains(String namespace, String name) { + return tagMap.containsKey(createKey(namespace, name)); + } + + protected String createKey(String namespace, String name) { + return namespace + " " + name; + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Token.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Token.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/script/Token.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,27 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.script; + +public interface Token { + public int getStart(); + + public void setStart(int start); + + public int getEnd(); + + public void setEnd(int end); +} + Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/AbstractTag.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/AbstractTag.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/AbstractTag.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,39 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.tag; + +import org.apache.cocoon.template.v2.script.AbstractToken; +import org.apache.cocoon.template.v2.script.ElementToken; +import org.apache.cocoon.template.v2.script.ScriptContext; + +public abstract class AbstractTag extends AbstractToken implements + ElementToken, Tag { + protected int bodyStart; + + public int getBodyStart() { + return bodyStart; + } + + public void setBodyStart(int bodyStart) { + this.bodyStart = bodyStart; + } + + public abstract void invoke(ScriptContext context) throws Exception; + + public void invokeBody(ScriptContext context) throws Exception { + context.getScriptInvoker().invoke(bodyStart, end); + } +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/Tag.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/Tag.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/Tag.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,23 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.tag; + +import org.apache.cocoon.template.v2.script.ElementToken; +import org.apache.cocoon.template.v2.script.ScriptContext; + +public interface Tag extends ElementToken { + public void invoke(ScriptContext context) throws Exception; +} \ No newline at end of file Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/samples/DuplicateTag.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/samples/DuplicateTag.java?view=auto&rev=111375 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/template/v2/tag/samples/DuplicateTag.java Thu Dec 9 04:38:49 2004 @@ -0,0 +1,26 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.template.v2.tag.samples; + +import org.apache.cocoon.template.v2.script.ScriptContext; +import org.apache.cocoon.template.v2.tag.AbstractTag; + +public class DuplicateTag extends AbstractTag { + public void invoke(ScriptContext context) throws Exception { + invokeBody(context); + invokeBody(context); + } +} \ No newline at end of file Modified: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java?view=diff&rev=111375&p1=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java&r1=111374&p2=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java&r2=111375 ============================================================================== --- cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java (original) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/generation/TemplateGeneratorTestCase.java Thu Dec 9 04:38:49 2004 @@ -18,7 +18,8 @@ import org.apache.avalon.framework.logger.ConsoleLogger; import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.ExtendedSitemapComponentTestCase; -import org.apache.cocoon.template.tag.samples.DuplicateTag; +import org.apache.cocoon.template.v2.generation.TemplateGenerator; +import org.apache.cocoon.template.v2.tag.samples.DuplicateTag; import org.apache.cocoon.xml.dom.DOMBuilder; public class TemplateGeneratorTestCase extends ExtendedSitemapComponentTestCase { Modified: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java?view=diff&rev=111375&p1=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java&r1=111374&p2=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java&r2=111375 ============================================================================== --- cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java (original) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptCompilerTestCase.java Thu Dec 9 04:38:49 2004 @@ -19,7 +19,15 @@ import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.ExtendedSitemapComponentTestCase; import org.apache.cocoon.el.GenericExpressionCompiler; -import org.apache.cocoon.template.tag.AbstractTag; +import org.apache.cocoon.template.v2.script.AttributeToken; +import org.apache.cocoon.template.v2.script.CharactersToken; +import org.apache.cocoon.template.v2.script.ExpressionToken; +import org.apache.cocoon.template.v2.script.PlainElementToken; +import org.apache.cocoon.template.v2.script.Script; +import org.apache.cocoon.template.v2.script.ScriptCompiler; +import org.apache.cocoon.template.v2.script.ScriptContext; +import org.apache.cocoon.template.v2.script.TagRepository; +import org.apache.cocoon.template.v2.tag.AbstractTag; import org.xml.sax.helpers.AttributesImpl; public class ScriptCompilerTestCase extends ExtendedSitemapComponentTestCase { Modified: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java?view=diff&rev=111375&p1=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java&r1=111374&p2=cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java&r2=111375 ============================================================================== --- cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java (original) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/template/script/ScriptInvokerTestCase.java Thu Dec 9 04:38:49 2004 @@ -19,7 +19,12 @@ import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.ExtendedSitemapComponentTestCase; import org.apache.cocoon.el.GenericExpressionCompiler; -import org.apache.cocoon.template.tag.samples.DuplicateTag; +import org.apache.cocoon.template.v2.script.Script; +import org.apache.cocoon.template.v2.script.ScriptCompiler; +import org.apache.cocoon.template.v2.script.ScriptContext; +import org.apache.cocoon.template.v2.script.ScriptInvoker; +import org.apache.cocoon.template.v2.script.TagRepository; +import org.apache.cocoon.template.v2.tag.samples.DuplicateTag; import org.apache.cocoon.xml.XMLConsumer; import org.apache.cocoon.xml.dom.DOMBuilder;