blob: d3c8244697989353073789e0e710525664c12563 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.webapps.session.transformation;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import javax.xml.transform.OutputKeys;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.acting.ValidatorActionResult;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.webapps.session.SessionConstants;
import org.apache.cocoon.xml.XMLUtils;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceParameters;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This is the session post transformer. It does all the setting and
* destroying. Thus it should be the last transformer (before the xsl) in
* the pipeline.
* For performance and simplicity reasons this transformer inherits from
* the SessionPreTransformer, although this is not needed (but then the
* implementation of the SessionTransformer would be very unperformant).
*
* @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
* @deprecated This block is deprecated and will be removed in future versions.
* @version CVS $Id$
*/
public class SessionPostTransformer extends SessionPreTransformer {
public static final String DELETECONTEXT_ELEMENT = "deletecontext";
public static final String DELETECONTEXT_NAME_ATTRIBUTE = "name";
public static final String SETXML_ELEMENT = "setxml";
public static final String SETXML_CONTEXT_ATTRIBUTE = "context";
public static final String SETXML_PATH_ATTRIBUTE = "path";
public static final String APPENDXML_ELEMENT = "appendxml";
public static final String APPENDXML_CONTEXT_ATTRIBUTE = "context";
public static final String APPENDXML_PATH_ATTRIBUTE = "path";
public static final String REMOVEXML_ELEMENT = "removexml";
public static final String REMOVEXML_CONTEXT_ATTRIBUTE = "context";
public static final String REMOVEXML_PATH_ATTRIBUTE = "path";
public static final String MERGEXML_ELEMENT = "mergexml";
public static final String MERGEXML_CONTEXT_ATTRIBUTE = "context";
public static final String MERGEXML_PATH_ATTRIBUTE = "path";
public static final String SAVECONTEXT_ELEMENT = "savexml";
public static final String SAVECONTEXT_CONTEXT_ATTRIBUTE = "context";
public static final String SAVECONTEXT_PATH_ATTRIBUTE = "path"; // optional
public static final String INPUTXML_ELEMENT = "inputxml";
public static final String INPUTXML_CONTEXT_ATTRIBUTE = "context";
public static final String INPUTXML_PATH_ATTRIBUTE = "path";
public static final String INPUTXML_NAME_ATTRIBUTE = "name";
public static final String INPUTXML_TYPE_ATTRIBUTE = "type"; // optional
public static final String INPUTXML_VALIDATIONRESULT_ATTRIBUTE = "valresult";
/** The form element */
public static final String FORM_ELEMENT = "form";
/** The form action element */
public static final String FORM_ACTION_ELEMENT = "action";
/** The form content element */
public static final String FORM_CONTENT_ELEMENT = "content";
/** The form validation rules */
public static final String FORM_VALIDATION_ELEMENT = "validate";
public static final String FORM_VALIDATION_SOURCE_ATTRIBUTE = "src";
public static final String FORM_VALIDATESET_ELEMENT = "constraint-set";
/** State: no element parsed */
private static final int STATE_OUTSIDE = 0;
/** State: form element */
private static final int STATE_FORM = 1;
/** The current state */
private int state;
/** The current form name */
private String formName;
/** The validation results */
private Map validationResultMap;
public void setupTransforming() throws ProcessingException, SAXException, IOException {
super.setupTransforming();
this.state = STATE_OUTSIDE;
this.formName = null;
}
/**
* This is the real implementation of the startElement event
* for the transformer
* The event is checked for a valid element and the corresponding command
* is executed.
*/
public void startTransformingElement(String uri, String name, String raw, Attributes attr)
throws ProcessingException, IOException, SAXException {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN startTransformingElement uri=" + uri + ", name=" + name
+ ", raw=" + raw + ", attr=" + attr);
}
if (name.equals(DELETECONTEXT_ELEMENT)) {
this.getContextManager().deleteContext(attr.getValue(DELETECONTEXT_NAME_ATTRIBUTE));
} else if (name.equals(SETXML_ELEMENT)) {
this.startRecording();
stack.push(attr.getValue(SETXML_CONTEXT_ATTRIBUTE));
stack.push(attr.getValue(SETXML_PATH_ATTRIBUTE));
// Element: mergexml
} else if (name.equals(MERGEXML_ELEMENT)) {
this.startRecording();
stack.push(attr.getValue(MERGEXML_CONTEXT_ATTRIBUTE));
stack.push(attr.getValue(MERGEXML_PATH_ATTRIBUTE));
// Element: appendxml
} else if (name.equals(APPENDXML_ELEMENT)) {
this.startRecording();
stack.push(attr.getValue(APPENDXML_CONTEXT_ATTRIBUTE));
stack.push(attr.getValue(APPENDXML_PATH_ATTRIBUTE));
// Element: removexml
} else if (name.equals(REMOVEXML_ELEMENT)) {
this.startTextRecording();
stack.push(attr.getValue(REMOVEXML_CONTEXT_ATTRIBUTE));
stack.push(attr.getValue(REMOVEXML_PATH_ATTRIBUTE));
} else if (name.equals(SAVECONTEXT_ELEMENT)) {
this.startParametersRecording();
stack.push(attr.getValue(SAVECONTEXT_CONTEXT_ATTRIBUTE));
if (attr.getValue(SAVECONTEXT_PATH_ATTRIBUTE) != null) {
stack.push(attr.getValue(SAVECONTEXT_PATH_ATTRIBUTE));
} else {
stack.push("/");
}
// Element: inputxml
} else if (name.equals(INPUTXML_ELEMENT)) {
stack.push(attr.getValue(INPUTXML_CONTEXT_ATTRIBUTE));
String fieldname = attr.getValue(INPUTXML_NAME_ATTRIBUTE);
stack.push(fieldname);
stack.push(attr.getValue(INPUTXML_PATH_ATTRIBUTE));
AttributesImpl newattr = new AttributesImpl();
newattr.addAttribute("", INPUTXML_NAME_ATTRIBUTE, INPUTXML_NAME_ATTRIBUTE, "CDATA", fieldname);
if (attr.getValue(INPUTXML_TYPE_ATTRIBUTE) != null) {
newattr.addAttribute("", INPUTXML_TYPE_ATTRIBUTE, INPUTXML_TYPE_ATTRIBUTE, "CDATA",
attr.getValue(INPUTXML_TYPE_ATTRIBUTE));
}
ValidatorActionResult validationResult = null;
if (validationResultMap != null && validationResultMap.get(fieldname) != null) {
validationResult = (ValidatorActionResult)validationResultMap.get(fieldname);
newattr.addAttribute("", INPUTXML_VALIDATIONRESULT_ATTRIBUTE,
INPUTXML_VALIDATIONRESULT_ATTRIBUTE,"CDATA", validationResult.toString());
}
super.startTransformingElement("", name, name, newattr); // remove namespace
this.startRecording();
// Element form
} else if (name.equals(FORM_ELEMENT) && this.state == STATE_OUTSIDE) {
String formName = attr.getValue("name");
if (formName == null) {
throw new ProcessingException("The name attribute of the form element is required.");
}
this.stack.push(new Integer(this.state));
this.state = STATE_FORM;
this.stack.push(new AttributesImpl(attr));
// Element form action
} else if (name.equals(FORM_ACTION_ELEMENT) && this.state == STATE_FORM) {
this.startTextRecording();
// Element form content
} else if (name.equals(FORM_CONTENT_ELEMENT) && this.state == STATE_FORM) {
// get validation results to be used for inputxml elements
validationResultMap = (Map)this.getSessionManager().getSession(true)
.getAttribute(this.formName + "validation-result");
// Element form validation rules
} else if (name.equals(FORM_VALIDATION_ELEMENT) && this.state == STATE_FORM) {
this.startRecording();
if (attr.getValue(FORM_VALIDATION_SOURCE_ATTRIBUTE) != null) {
stack.push(attr.getValue(FORM_VALIDATION_SOURCE_ATTRIBUTE));
} else {
stack.push("EMPTY");
}
} else {
super.startTransformingElement(uri, name, raw, attr);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END startTransformingElement");
}
}
public void endTransformingElement(String uri, String name, String raw)
throws ProcessingException, IOException, SAXException {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN endTransformingElement uri=" + uri + ", name=" + name + ", raw=" + raw);
}
if (name.equals(DELETECONTEXT_ELEMENT)) {
// do nothing, the context was destroyed on the startElement event
// Element: setxml
} else if (name.equals(SETXML_ELEMENT)) {
String path = (String)stack.pop();
String contextName = (String)stack.pop();
this.getSessionManager().setContextFragment(contextName, path, this.endRecording());
// Element: mergexml
} else if (name.equals(MERGEXML_ELEMENT)) {
String path = (String)stack.pop();
String contextName = (String)stack.pop();
this.getSessionManager().mergeContextFragment(contextName, path, this.endRecording());
// Element: appendxml
} else if (name.equals(APPENDXML_ELEMENT)) {
String path = (String)stack.pop();
String contextName = (String)stack.pop();
this.getSessionManager().appendContextFragment(contextName, path, this.endRecording());
// Element: removexml
} else if (name.equals(REMOVEXML_ELEMENT)) {
String path = (String)stack.pop();
String contextName = (String)stack.pop();
// result is ignored
endTextRecording();
this.getSessionManager().removeContextFragment(contextName, path);
// Element: savexml
} else if (name.equals(SAVECONTEXT_ELEMENT)) {
String path = (String)stack.pop();
String contextName = (String)stack.pop();
SourceParameters pars = this.endParametersRecording((SourceParameters)null);
pars.setSingleParameterValue("contextname", contextName);
pars.setSingleParameterValue("path", path);
this.getContextManager().getContext(contextName).saveXML(path, pars);
// Element: inputxml
} else if (name.equals(INPUTXML_ELEMENT)) {
String path = (String)this.stack.pop();
String fieldname = (String)this.stack.pop();
String contextname = (String)this.stack.pop();
DocumentFragment defaultFragment = this.endRecording();
if (this.formName == null) {
throw new ProcessingException("The inputxml must be contained inside a form.");
}
DocumentFragment value = this.getFormManager().registerInputField(contextname, path,
fieldname, formName);
if (value == null) {
value = defaultFragment;
}
this.sendEvents(value);
super.endTransformingElement("", name, name);
// Element form
} else if (name.equals(FORM_ELEMENT) && this.state == STATE_FORM) {
this.state = ((Integer)this.stack.pop()).intValue();
this.sendEndElementEvent("form");
this.formName = null;
// Element form action
} else if (name.equals(FORM_ACTION_ELEMENT) && this.state == STATE_FORM) {
String action = this.endTextRecording();
AttributesImpl a = (AttributesImpl)this.stack.pop();
this.formName = a.getValue("name");
boolean hasPars = (action.indexOf("?") != -1);
action = this.response.encodeURL(action + (hasPars ? '&' : '?')
+ SessionConstants.SESSION_FORM_PARAMETER + '=' + this.formName);
a.addAttribute("", "action", "action", "CDATA", action);
if (a.getValue("method") == null) {
a.addAttribute("", "method", "method", "CDATA", "POST");
}
this.sendStartElementEvent("form", a);
// Element form content
} else if (name.equals(FORM_CONTENT_ELEMENT) && this.state == STATE_FORM) {
// ignore this
// Element form validation rules
} else if (name.equals(FORM_VALIDATION_ELEMENT) && this.state == STATE_FORM) {
if (this.formName == null) {
throw new ProcessingException("The validate element must be contained inside a form.");
}
DocumentFragment validationDoc = this.endRecording();
String source = (String)stack.pop();
if (!source.equals("EMPTY")) {
// get configuration from external file
// referenced by "src" attribute of "validate" element
try {
Source resource = this.resolver.resolveURI(source);
SAXConfigurationHandler saxBuilder = new SAXConfigurationHandler();
SourceUtil.parse(this.manager, resource, saxBuilder);
Configuration conf = saxBuilder.getConfiguration();
Session session = this.getSessionManager().getSession(true);
session.setAttribute(this.formName, conf);
if (validationDoc != null) {
//validationDoc contains "constraint-set" element
validationDoc.normalize();
Node validationNode = validationDoc.getFirstChild();
while (validationNode.getNodeType() != Node.ELEMENT_NODE) {
validationNode = validationNode.getNextSibling();
if (validationNode == null) {
break;
}
}
if (validationNode != null && validationNode.getNodeType() == Node.ELEMENT_NODE
&& validationNode.getNodeName().equals(FORM_VALIDATESET_ELEMENT)) {
Properties props = XMLUtils.createPropertiesForXML(false);
props.put(OutputKeys.ENCODING, "ISO-8859-1");
String validationXML = XMLUtils.serializeNode(validationNode, props);
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
conf = builder.build(new ByteArrayInputStream(validationXML.getBytes()));
session.setAttribute(this.formName + "constraint-set", conf);
}
}
} catch (SourceException se) {
throw new ProcessingException("Cannot resolve" + source, se);
} catch (ConfigurationException ce) {
throw new ProcessingException("Error building Configuration out of constraint-set element", ce);
}
} else if (validationDoc != null) {
//validationDoc contains the validation rules inline
try {
validationDoc.normalize();
Node validationNode = validationDoc.getFirstChild();
while (validationNode.getNodeType() != Node.ELEMENT_NODE) {
validationNode = validationNode.getNextSibling();
if (validationNode == null) {
break;
}
}
if (validationNode != null && validationNode.getNodeType() == Node.ELEMENT_NODE
&& validationNode.getNodeName().equals("root")) {
Properties props = XMLUtils.createPropertiesForXML(false);
props.put(OutputKeys.ENCODING, "ISO-8859-1");
String validationXML = XMLUtils.serializeNode(validationNode, props);
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
Configuration conf = builder.build(new ByteArrayInputStream(validationXML.getBytes()));
Session session = this.getSessionManager().getSession(true);
session.setAttribute(this.formName, conf);
//the constraint-set to validate is the first and single one
session.setAttribute(this.formName + "constraint-set", conf.getChildren("constraint-set")[0]);
}
} catch (ConfigurationException ce) {
throw new ProcessingException("Error building Configuration out of validation XML", ce);
}
}
} else {
super.endTransformingElement(uri, name, raw);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END endTransformingElement");
}
}
}