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.webapps.session.transformation;
018:
019: import java.io.ByteArrayInputStream;
020: import java.io.IOException;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import javax.xml.transform.OutputKeys;
025:
026: import org.apache.avalon.framework.configuration.Configuration;
027: import org.apache.avalon.framework.configuration.ConfigurationException;
028: import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
029: import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
030: import org.apache.cocoon.ProcessingException;
031: import org.apache.cocoon.acting.ValidatorActionResult;
032: import org.apache.cocoon.components.source.SourceUtil;
033: import org.apache.cocoon.environment.Session;
034: import org.apache.cocoon.webapps.session.SessionConstants;
035: import org.apache.cocoon.xml.XMLUtils;
036: import org.apache.excalibur.source.Source;
037: import org.apache.excalibur.source.SourceException;
038: import org.apache.excalibur.source.SourceParameters;
039: import org.w3c.dom.DocumentFragment;
040: import org.w3c.dom.Node;
041: import org.xml.sax.Attributes;
042: import org.xml.sax.SAXException;
043: import org.xml.sax.helpers.AttributesImpl;
044:
045: /**
046: * This is the session post transformer. It does all the setting and
047: * destroying. Thus it should be the last transformer (before the xsl) in
048: * the pipeline.
049: * For performance and simplicity reasons this transformer inherits from
050: * the SessionPreTransformer, although this is not needed (but then the
051: * implementation of the SessionTransformer would be very unperformant).
052: *
053: * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
054: * @deprecated This block is deprecated and will be removed in future versions.
055: * @version CVS $Id: SessionPostTransformer.java 433543 2006-08-22 06:22:54Z crossley $
056: */
057: public class SessionPostTransformer extends SessionPreTransformer {
058:
059: public static final String DELETECONTEXT_ELEMENT = "deletecontext";
060: public static final String DELETECONTEXT_NAME_ATTRIBUTE = "name";
061:
062: public static final String SETXML_ELEMENT = "setxml";
063: public static final String SETXML_CONTEXT_ATTRIBUTE = "context";
064: public static final String SETXML_PATH_ATTRIBUTE = "path";
065:
066: public static final String APPENDXML_ELEMENT = "appendxml";
067: public static final String APPENDXML_CONTEXT_ATTRIBUTE = "context";
068: public static final String APPENDXML_PATH_ATTRIBUTE = "path";
069:
070: public static final String REMOVEXML_ELEMENT = "removexml";
071: public static final String REMOVEXML_CONTEXT_ATTRIBUTE = "context";
072: public static final String REMOVEXML_PATH_ATTRIBUTE = "path";
073:
074: public static final String MERGEXML_ELEMENT = "mergexml";
075: public static final String MERGEXML_CONTEXT_ATTRIBUTE = "context";
076: public static final String MERGEXML_PATH_ATTRIBUTE = "path";
077:
078: public static final String SAVECONTEXT_ELEMENT = "savexml";
079: public static final String SAVECONTEXT_CONTEXT_ATTRIBUTE = "context";
080: public static final String SAVECONTEXT_PATH_ATTRIBUTE = "path"; // optional
081:
082: public static final String INPUTXML_ELEMENT = "inputxml";
083: public static final String INPUTXML_CONTEXT_ATTRIBUTE = "context";
084: public static final String INPUTXML_PATH_ATTRIBUTE = "path";
085: public static final String INPUTXML_NAME_ATTRIBUTE = "name";
086: public static final String INPUTXML_TYPE_ATTRIBUTE = "type"; // optional
087: public static final String INPUTXML_VALIDATIONRESULT_ATTRIBUTE = "valresult";
088:
089: /** The form element */
090: public static final String FORM_ELEMENT = "form";
091:
092: /** The form action element */
093: public static final String FORM_ACTION_ELEMENT = "action";
094:
095: /** The form content element */
096: public static final String FORM_CONTENT_ELEMENT = "content";
097:
098: /** The form validation rules */
099: public static final String FORM_VALIDATION_ELEMENT = "validate";
100: public static final String FORM_VALIDATION_SOURCE_ATTRIBUTE = "src";
101: public static final String FORM_VALIDATESET_ELEMENT = "constraint-set";
102:
103: /** State: no element parsed */
104: private static final int STATE_OUTSIDE = 0;
105: /** State: form element */
106: private static final int STATE_FORM = 1;
107:
108: /** The current state */
109: private int state;
110:
111: /** The current form name */
112: private String formName;
113:
114: /** The validation results */
115: private Map validationResultMap;
116:
117: public void setupTransforming() throws ProcessingException,
118: SAXException, IOException {
119: super .setupTransforming();
120: this .state = STATE_OUTSIDE;
121: this .formName = null;
122: }
123:
124: /**
125: * This is the real implementation of the startElement event
126: * for the transformer
127: * The event is checked for a valid element and the corresponding command
128: * is executed.
129: */
130: public void startTransformingElement(String uri, String name,
131: String raw, Attributes attr) throws ProcessingException,
132: IOException, SAXException {
133: if (this .getLogger().isDebugEnabled()) {
134: this .getLogger().debug(
135: "BEGIN startTransformingElement uri=" + uri
136: + ", name=" + name + ", raw=" + raw
137: + ", attr=" + attr);
138: }
139: if (name.equals(DELETECONTEXT_ELEMENT)) {
140: this .getContextManager().deleteContext(
141: attr.getValue(DELETECONTEXT_NAME_ATTRIBUTE));
142:
143: } else if (name.equals(SETXML_ELEMENT)) {
144: this .startRecording();
145: stack.push(attr.getValue(SETXML_CONTEXT_ATTRIBUTE));
146: stack.push(attr.getValue(SETXML_PATH_ATTRIBUTE));
147:
148: // Element: mergexml
149: } else if (name.equals(MERGEXML_ELEMENT)) {
150: this .startRecording();
151: stack.push(attr.getValue(MERGEXML_CONTEXT_ATTRIBUTE));
152: stack.push(attr.getValue(MERGEXML_PATH_ATTRIBUTE));
153:
154: // Element: appendxml
155: } else if (name.equals(APPENDXML_ELEMENT)) {
156: this .startRecording();
157: stack.push(attr.getValue(APPENDXML_CONTEXT_ATTRIBUTE));
158: stack.push(attr.getValue(APPENDXML_PATH_ATTRIBUTE));
159:
160: // Element: removexml
161: } else if (name.equals(REMOVEXML_ELEMENT)) {
162: this .startTextRecording();
163: stack.push(attr.getValue(REMOVEXML_CONTEXT_ATTRIBUTE));
164: stack.push(attr.getValue(REMOVEXML_PATH_ATTRIBUTE));
165:
166: } else if (name.equals(SAVECONTEXT_ELEMENT)) {
167: this .startParametersRecording();
168: stack.push(attr.getValue(SAVECONTEXT_CONTEXT_ATTRIBUTE));
169: if (attr.getValue(SAVECONTEXT_PATH_ATTRIBUTE) != null) {
170: stack.push(attr.getValue(SAVECONTEXT_PATH_ATTRIBUTE));
171: } else {
172: stack.push("/");
173: }
174:
175: // Element: inputxml
176: } else if (name.equals(INPUTXML_ELEMENT)) {
177: stack.push(attr.getValue(INPUTXML_CONTEXT_ATTRIBUTE));
178: String fieldname = attr.getValue(INPUTXML_NAME_ATTRIBUTE);
179: stack.push(fieldname);
180: stack.push(attr.getValue(INPUTXML_PATH_ATTRIBUTE));
181:
182: AttributesImpl newattr = new AttributesImpl();
183: newattr.addAttribute("", INPUTXML_NAME_ATTRIBUTE,
184: INPUTXML_NAME_ATTRIBUTE, "CDATA", fieldname);
185: if (attr.getValue(INPUTXML_TYPE_ATTRIBUTE) != null) {
186: newattr.addAttribute("", INPUTXML_TYPE_ATTRIBUTE,
187: INPUTXML_TYPE_ATTRIBUTE, "CDATA", attr
188: .getValue(INPUTXML_TYPE_ATTRIBUTE));
189: }
190:
191: ValidatorActionResult validationResult = null;
192: if (validationResultMap != null
193: && validationResultMap.get(fieldname) != null) {
194: validationResult = (ValidatorActionResult) validationResultMap
195: .get(fieldname);
196: newattr.addAttribute("",
197: INPUTXML_VALIDATIONRESULT_ATTRIBUTE,
198: INPUTXML_VALIDATIONRESULT_ATTRIBUTE, "CDATA",
199: validationResult.toString());
200: }
201:
202: super .startTransformingElement("", name, name, newattr); // remove namespace
203: this .startRecording();
204:
205: // Element form
206: } else if (name.equals(FORM_ELEMENT)
207: && this .state == STATE_OUTSIDE) {
208: String formName = attr.getValue("name");
209: if (formName == null) {
210: throw new ProcessingException(
211: "The name attribute of the form element is required.");
212: }
213: this .stack.push(new Integer(this .state));
214: this .state = STATE_FORM;
215: this .stack.push(new AttributesImpl(attr));
216:
217: // Element form action
218: } else if (name.equals(FORM_ACTION_ELEMENT)
219: && this .state == STATE_FORM) {
220: this .startTextRecording();
221:
222: // Element form content
223: } else if (name.equals(FORM_CONTENT_ELEMENT)
224: && this .state == STATE_FORM) {
225: // get validation results to be used for inputxml elements
226: validationResultMap = (Map) this .getSessionManager()
227: .getSession(true).getAttribute(
228: this .formName + "validation-result");
229:
230: // Element form validation rules
231: } else if (name.equals(FORM_VALIDATION_ELEMENT)
232: && this .state == STATE_FORM) {
233: this .startRecording();
234: if (attr.getValue(FORM_VALIDATION_SOURCE_ATTRIBUTE) != null) {
235: stack.push(attr
236: .getValue(FORM_VALIDATION_SOURCE_ATTRIBUTE));
237: } else {
238: stack.push("EMPTY");
239: }
240:
241: } else {
242: super .startTransformingElement(uri, name, raw, attr);
243: }
244: if (this .getLogger().isDebugEnabled()) {
245: this .getLogger().debug("END startTransformingElement");
246: }
247: }
248:
249: public void endTransformingElement(String uri, String name,
250: String raw) throws ProcessingException, IOException,
251: SAXException {
252: if (this .getLogger().isDebugEnabled()) {
253: this .getLogger().debug(
254: "BEGIN endTransformingElement uri=" + uri
255: + ", name=" + name + ", raw=" + raw);
256: }
257: if (name.equals(DELETECONTEXT_ELEMENT)) {
258: // do nothing, the context was destroyed on the startElement event
259:
260: // Element: setxml
261: } else if (name.equals(SETXML_ELEMENT)) {
262: String path = (String) stack.pop();
263: String contextName = (String) stack.pop();
264: this .getSessionManager().setContextFragment(contextName,
265: path, this .endRecording());
266:
267: // Element: mergexml
268: } else if (name.equals(MERGEXML_ELEMENT)) {
269: String path = (String) stack.pop();
270: String contextName = (String) stack.pop();
271: this .getSessionManager().mergeContextFragment(contextName,
272: path, this .endRecording());
273:
274: // Element: appendxml
275: } else if (name.equals(APPENDXML_ELEMENT)) {
276: String path = (String) stack.pop();
277: String contextName = (String) stack.pop();
278: this .getSessionManager().appendContextFragment(contextName,
279: path, this .endRecording());
280:
281: // Element: removexml
282: } else if (name.equals(REMOVEXML_ELEMENT)) {
283: String path = (String) stack.pop();
284: String contextName = (String) stack.pop();
285: // result is ignored
286: endTextRecording();
287: this .getSessionManager().removeContextFragment(contextName,
288: path);
289:
290: // Element: savexml
291: } else if (name.equals(SAVECONTEXT_ELEMENT)) {
292: String path = (String) stack.pop();
293: String contextName = (String) stack.pop();
294: SourceParameters pars = this
295: .endParametersRecording((SourceParameters) null);
296: pars.setSingleParameterValue("contextname", contextName);
297: pars.setSingleParameterValue("path", path);
298:
299: this .getContextManager().getContext(contextName).saveXML(
300: path, pars);
301:
302: // Element: inputxml
303: } else if (name.equals(INPUTXML_ELEMENT)) {
304: String path = (String) this .stack.pop();
305: String fieldname = (String) this .stack.pop();
306: String contextname = (String) this .stack.pop();
307: DocumentFragment defaultFragment = this .endRecording();
308:
309: if (this .formName == null) {
310: throw new ProcessingException(
311: "The inputxml must be contained inside a form.");
312: }
313: DocumentFragment value = this .getFormManager()
314: .registerInputField(contextname, path, fieldname,
315: formName);
316: if (value == null) {
317: value = defaultFragment;
318: }
319: this .sendEvents(value);
320: super .endTransformingElement("", name, name);
321:
322: // Element form
323: } else if (name.equals(FORM_ELEMENT)
324: && this .state == STATE_FORM) {
325: this .state = ((Integer) this .stack.pop()).intValue();
326: this .sendEndElementEvent("form");
327: this .formName = null;
328:
329: // Element form action
330: } else if (name.equals(FORM_ACTION_ELEMENT)
331: && this .state == STATE_FORM) {
332: String action = this .endTextRecording();
333: AttributesImpl a = (AttributesImpl) this .stack.pop();
334: this .formName = a.getValue("name");
335: boolean hasPars = (action.indexOf("?") != -1);
336: action = this .response.encodeURL(action
337: + (hasPars ? '&' : '?')
338: + SessionConstants.SESSION_FORM_PARAMETER + '='
339: + this .formName);
340: a.addAttribute("", "action", "action", "CDATA", action);
341: if (a.getValue("method") == null) {
342: a.addAttribute("", "method", "method", "CDATA", "POST");
343: }
344: this .sendStartElementEvent("form", a);
345:
346: // Element form content
347: } else if (name.equals(FORM_CONTENT_ELEMENT)
348: && this .state == STATE_FORM) {
349: // ignore this
350:
351: // Element form validation rules
352: } else if (name.equals(FORM_VALIDATION_ELEMENT)
353: && this .state == STATE_FORM) {
354: if (this .formName == null) {
355: throw new ProcessingException(
356: "The validate element must be contained inside a form.");
357: }
358: DocumentFragment validationDoc = this .endRecording();
359: String source = (String) stack.pop();
360: if (!source.equals("EMPTY")) {
361: // get configuration from external file
362: // referenced by "src" attribute of "validate" element
363: try {
364: Source resource = this .resolver.resolveURI(source);
365: SAXConfigurationHandler saxBuilder = new SAXConfigurationHandler();
366: SourceUtil
367: .parse(this .manager, resource, saxBuilder);
368:
369: Configuration conf = saxBuilder.getConfiguration();
370: Session session = this .getSessionManager()
371: .getSession(true);
372: session.setAttribute(this .formName, conf);
373:
374: if (validationDoc != null) {
375: //validationDoc contains "constraint-set" element
376: validationDoc.normalize();
377: Node validationNode = validationDoc
378: .getFirstChild();
379: while (validationNode.getNodeType() != Node.ELEMENT_NODE) {
380: validationNode = validationNode
381: .getNextSibling();
382: if (validationNode == null) {
383: break;
384: }
385: }
386: if (validationNode != null
387: && validationNode.getNodeType() == Node.ELEMENT_NODE
388: && validationNode.getNodeName().equals(
389: FORM_VALIDATESET_ELEMENT)) {
390: Properties props = XMLUtils
391: .createPropertiesForXML(false);
392: props
393: .put(OutputKeys.ENCODING,
394: "ISO-8859-1");
395: String validationXML = XMLUtils
396: .serializeNode(validationNode,
397: props);
398: DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
399: conf = builder
400: .build(new ByteArrayInputStream(
401: validationXML.getBytes()));
402: session.setAttribute(this .formName
403: + "constraint-set", conf);
404: }
405: }
406:
407: } catch (SourceException se) {
408: throw new ProcessingException("Cannot resolve"
409: + source, se);
410: } catch (ConfigurationException ce) {
411: throw new ProcessingException(
412: "Error building Configuration out of constraint-set element",
413: ce);
414: }
415:
416: } else if (validationDoc != null) {
417: //validationDoc contains the validation rules inline
418: try {
419: validationDoc.normalize();
420: Node validationNode = validationDoc.getFirstChild();
421: while (validationNode.getNodeType() != Node.ELEMENT_NODE) {
422: validationNode = validationNode
423: .getNextSibling();
424: if (validationNode == null) {
425: break;
426: }
427: }
428: if (validationNode != null
429: && validationNode.getNodeType() == Node.ELEMENT_NODE
430: && validationNode.getNodeName().equals(
431: "root")) {
432: Properties props = XMLUtils
433: .createPropertiesForXML(false);
434: props.put(OutputKeys.ENCODING, "ISO-8859-1");
435: String validationXML = XMLUtils.serializeNode(
436: validationNode, props);
437: DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
438: Configuration conf = builder
439: .build(new ByteArrayInputStream(
440: validationXML.getBytes()));
441: Session session = this .getSessionManager()
442: .getSession(true);
443: session.setAttribute(this .formName, conf);
444: //the constraint-set to validate is the first and single one
445: session.setAttribute(this .formName
446: + "constraint-set", conf
447: .getChildren("constraint-set")[0]);
448:
449: }
450: } catch (ConfigurationException ce) {
451: throw new ProcessingException(
452: "Error building Configuration out of validation XML",
453: ce);
454: }
455: }
456:
457: } else {
458: super .endTransformingElement(uri, name, raw);
459: }
460: if (this .getLogger().isDebugEnabled()) {
461: this .getLogger().debug("END endTransformingElement");
462: }
463: }
464: }
|