001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.template.instruction;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022: import java.util.Stack;
023:
024: import org.apache.cocoon.components.expression.ExpressionContext;
025: import org.apache.cocoon.template.environment.ErrorHolder;
026: import org.apache.cocoon.template.environment.ExecutionContext;
027: import org.apache.cocoon.template.environment.ParsingContext;
028: import org.apache.cocoon.template.expression.JXTExpression;
029: import org.apache.cocoon.template.script.Invoker;
030: import org.apache.cocoon.template.script.event.AttributeEvent;
031: import org.apache.cocoon.template.script.event.Characters;
032: import org.apache.cocoon.template.script.event.Event;
033: import org.apache.cocoon.template.script.event.IgnorableWhitespace;
034: import org.apache.cocoon.template.script.event.StartElement;
035: import org.apache.cocoon.template.script.event.TextEvent;
036: import org.apache.cocoon.xml.XMLConsumer;
037: import org.apache.commons.lang.StringUtils;
038: import org.xml.sax.Attributes;
039: import org.xml.sax.Locator;
040: import org.xml.sax.SAXException;
041: import org.xml.sax.SAXParseException;
042:
043: /**
044: * @version $Id: Call.java 449189 2006-09-23 06:52:29Z crossley $
045: */
046: public class Call extends Instruction {
047:
048: private Object macro;
049: private JXTExpression targetNamespace;
050: private Map parameters;
051: private Event body;
052:
053: public Call(Define definition, StartElement startElement)
054: throws SAXException {
055: super (startElement);
056: this .parameters = new HashMap();
057: setBody(startElement);
058: setNext(startElement.getNext());
059: setDefinition(definition);
060:
061: Iterator i = startElement.getAttributeEvents().iterator();
062: while (i.hasNext()) {
063: AttributeEvent attrEvent = (AttributeEvent) i.next();
064: addParameterInstance(attrEvent);
065: }
066: }
067:
068: public Call(ParsingContext parsingContext, StartElement raw,
069: Attributes attrs, Stack stack) throws SAXException {
070: super (raw);
071: this .parameters = new HashMap();
072: Locator locator = getLocation();
073:
074: String name = attrs.getValue("macro");
075: if (name == null) {
076: throw new SAXParseException("if: \"test\" is required",
077: locator, null);
078: }
079: this .macro = parsingContext.getStringTemplateParser()
080: .compileExpr(name, "call: \"macro\": ", locator);
081:
082: String namespace = StringUtils.defaultString(attrs
083: .getValue("targetNamespace"));
084: this .targetNamespace = parsingContext.getStringTemplateParser()
085: .compileExpr(namespace, "call: \"targetNamespace\": ",
086: locator);
087: }
088:
089: public void setDefinition(Define definition) {
090: this .macro = definition;
091: }
092:
093: public void addParameterInstance(AttributeEvent attributeEvent)
094: throws SAXException {
095: ParameterInstance parameter = new ParameterInstance(
096: attributeEvent);
097: this .parameters.put(parameter.getName(), parameter);
098: }
099:
100: public Event execute(XMLConsumer consumer,
101: ExpressionContext expressionContext,
102: ExecutionContext executionContext,
103: MacroContext macroContext, Event startEvent, Event endEvent)
104: throws SAXException {
105: Map attributeMap = new HashMap();
106: Iterator i = parameters.keySet().iterator();
107: while (i.hasNext()) {
108: String parameterName = (String) i.next();
109: ParameterInstance parameter = (ParameterInstance) parameters
110: .get(parameterName);
111: Object parameterValue = parameter
112: .getValue(expressionContext);
113: attributeMap.put(parameterName, parameterValue);
114: }
115: ExpressionContext localExpressionContext = new ExpressionContext(
116: expressionContext);
117: HashMap macro = new HashMap();
118: macro.put("body", this .body);
119: macro.put("arguments", attributeMap);
120: localExpressionContext.put("macro", macro);
121:
122: Define definition = resolveMacroDefinition(expressionContext,
123: executionContext);
124: Iterator iter = definition.getParameters().entrySet()
125: .iterator();
126: while (iter.hasNext()) {
127: Map.Entry e = (Map.Entry) iter.next();
128: String key = (String) e.getKey();
129: Parameter startParam = (Parameter) e.getValue();
130: Object default_ = startParam.getDefaultValue();
131: Object val = attributeMap.get(key);
132: if (val == null) {
133: val = default_;
134: }
135: localExpressionContext.put(key, val);
136: }
137:
138: Event macroBodyStart = getNext();
139: Event macroBodyEnd = null;
140:
141: if (getEndInstruction() != null)
142: macroBodyEnd = getEndInstruction();
143: else
144: macroBodyEnd = getStartElement().getEndElement();
145:
146: MacroContext newMacroContext = new MacroContext(definition
147: .getQname(), macroBodyStart, macroBodyEnd);
148: try {
149: Invoker.execute(consumer, localExpressionContext,
150: executionContext, newMacroContext, definition
151: .getBody(), definition.getEndInstruction());
152: } catch (SAXParseException exc) {
153: throw new SAXParseException(newMacroContext.getMacroQName()
154: + ": " + exc.getMessage(), location, exc);
155: }
156:
157: if (getEndInstruction() != null)
158: return getEndInstruction().getNext();
159: else
160: return getStartElement().getEndElement().getNext();
161: }
162:
163: /**
164: * @param executionContext
165: * @throws SAXParseException
166: */
167: private Define resolveMacroDefinition(
168: ExpressionContext expressionContext,
169: ExecutionContext executionContext) throws SAXParseException {
170: if (this .macro instanceof Define)
171: return (Define) macro;
172:
173: Object macroName;
174: Object namespace;
175: JXTExpression macroNameExpression = (JXTExpression) macro;
176: try {
177: macroName = macroNameExpression.getValue(expressionContext);
178: namespace = targetNamespace.getValue(expressionContext);
179: if (namespace == null)
180: namespace = "";
181: } catch (Exception e) {
182: throw new SAXParseException(e.getMessage(), getLocation(),
183: e);
184: } catch (Error err) {
185: throw new SAXParseException(err.getMessage(),
186: getLocation(), new ErrorHolder(err));
187: }
188: Define definition = (Define) executionContext.getDefinitions()
189: .get(
190: "{" + namespace.toString() + "}"
191: + macroName.toString());
192: if (definition == null)
193: throw new SAXParseException("no macro definition: "
194: + macroName, getLocation());
195: return definition;
196: }
197:
198: /**
199: * @param body
200: */
201: public void setBody(Event body) {
202: this .body = body;
203:
204: }
205:
206: public void endNotify() throws SAXException {
207: // FIXME: copy/pasted from StartDefine (almost)
208: Event e = next;
209: boolean params = true;
210: while (e != this .getEndInstruction()) {
211: if (e instanceof ParameterInstance) {
212: ParameterInstance startParamInstance = (ParameterInstance) e;
213: if (!params) {
214: throw new SAXParseException(
215: "<parameter value> not allowed here: \""
216: + startParamInstance.name + "\"",
217: startParamInstance.getLocation(), null);
218: }
219: Object prev = this .parameters.put(
220: startParamInstance.name, startParamInstance);
221: if (prev != null) {
222: throw new SAXParseException(
223: "duplicate parameter value: \""
224: + startParamInstance.name + "\"",
225: location, null);
226: }
227: e = startParamInstance.getEndInstruction();
228: } else if (e instanceof IgnorableWhitespace) {
229: // EMPTY
230: } else if (e instanceof Characters) {
231: // check for whitespace
232: char[] ch = ((TextEvent) e).getRaw();
233: int len = ch.length;
234: for (int i = 0; i < len; i++) {
235: if (!Character.isWhitespace(ch[i])) {
236: if (params) {
237: params = false;
238: this .body = e;
239: }
240: break;
241: }
242: }
243: } else {
244: if (params) {
245: params = false;
246: this.body = e;
247: }
248: }
249: e = e.getNext();
250: }
251: if (this.body == null) {
252: this.body = this.getEndInstruction();
253: }
254: setNext(this.body);
255: }
256: }
|