blob: 9403b0a2c725e02e4573526b1f2f726a218bfb6c [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.context;
import java.io.IOException;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Map;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.Cookie;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.transformation.CIncludeTransformer;
import org.apache.cocoon.xml.IncludeXMLConsumer;
import org.apache.cocoon.xml.dom.DOMUtil;
import org.apache.commons.lang.BooleanUtils;
import org.apache.excalibur.source.SourceParameters;
import org.apache.excalibur.xml.sax.SAXParser;
import org.apache.excalibur.xml.xpath.XPathProcessor;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
/**
* A SessionContext which encapsulates the current Request object.
*
* It is not allowed to change this context.
* The following paths are valid:
* /parameter - lists all parameters, parameter names build the
* elements with the value of the first parameter with
* this name as text node childs
* /parameter/<parameter_name> - one text node containing the value of the first
* parameter with this name
* /querystring - the querystring with a leading '?' or null (the querystring is only for GET)
*
* /parametervalues - same as /parameter but values are listed as described
* below and each value of a parameter is listed.
* <cinclude:parameters>
* <cinclude:parameter>
* <cinclude:name>parameter name</cinclude:name>
* <cinclude:value>parameter value</cinclude:value>
* </cinclude:parameter>
* ...
* <cinclude:parameter>
* <cinclude:name>parameter name</cinclude:name>
* <cinclude:value>parameter value</cinclude:value>
* </session:parameter>
* </cinclude:parameters>
* If a parameter has more than one value for each value a
* <cinclude:parameter/> block is generated.
* This output has the namespace of the CIncludeTransformer
* to use it as input for a <cinclude:includexml> command.
* /attributes - lists all attributes, attribute names build the elements
* with the values as childs
* /headers - lists all headers, header names build the elements
* with the values as text node childs
* /cookies ----- <cookie name="...">
* <comment/>
* <domain/>
* <maxAge/>
* <name/>
* <path/>
* <secure/>
* <value/>
* <version/>
* /characterEncoding
* /contentLength
* /contentType
* /protocol
* /remoteAddress
* /remoteHost
* /scheme
* /serverName
* /serverPort
* /method
* /contextPath
* /pathInfo
* /pathTranslated
* /remoteUser
* /requestedSessionId
* /requestURI
* /servletPath
* /isRequestedSessionIdFromCookie
* /isRequestedSessionIdFromCookie
* /isRequestedSessionIdValid
*
* The following attributes of the servlet api 2.2 are missing:
* - getUserPrincipal()
* - getLocale()
* - getLocales()
* - getAuthType()
*
* @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 final class RequestSessionContext
implements SessionContext {
private static final String PARAMETERS_ELEMENT = "cinclude:" + CIncludeTransformer.CINCLUDE_PARAMETERS_ELEMENT;
private static final String PARAMETER_ELEMENT = "cinclude:" + CIncludeTransformer.CINCLUDE_PARAMETER_ELEMENT;
private static final String NAME_ELEMENT = "cinclude:" + CIncludeTransformer.CINCLUDE_NAME_ELEMENT;
private static final String VALUE_ELEMENT = "cinclude:" + CIncludeTransformer.CINCLUDE_VALUE_ELEMENT;
/** The logger. */
protected Logger logger;
/** Name of this context */
private String name;
/** The current {@link org.apache.cocoon.environment.Request} */
transient private Request request;
/** The content of this context */
private Document contextData;
/** The XPath Processor */
private XPathProcessor xpathProcessor;
public RequestSessionContext(Logger logger) {
this.logger = logger;
}
/**
* Setup this context
*/
public void setup(String value, String loadResource, String saveResource) {
this.name = value;
}
/**
* Set the Request
*/
public void setup(Map objectModel, ServiceManager manager, XPathProcessor processor)
throws ProcessingException {
this.xpathProcessor = processor;
this.request = ObjectModelHelper.getRequest(objectModel);
contextData = DOMUtil.createDocument();
contextData.appendChild(contextData.createElementNS(null, "context"));
Element root = contextData.getDocumentElement();
SAXParser parser = null;
try {
parser = (SAXParser) manager.lookup( SAXParser.ROLE );
this.buildParameterXML(root, parser);
} catch (ServiceException ce) {
throw new ProcessingException("Unable to lookup parser.", ce);
} finally {
manager.release(parser );
}
this.buildAttributesXML(root);
this.buildMiscXML(root);
this.buildCookiesXML(root);
this.buildHeadersXML(root);
}
/**
* Get the name of the context
*/
public String getName() {
return this.name;
}
/**
* Get the request object
*/
public Request getRequest() {
return this.request;
}
/**
* Build path
*/
private String createPath(String path) {
if (path == null) path = "/";
if (path.startsWith("/") == false) path = "/" + path;
path = "/context" + path;
if (path.endsWith("/") == true) path = path.substring(0, path.length() - 1);
return path;
}
private Node createTextNode(Document doc, String value) {
return doc.createTextNode(value != null ? value : "");
}
/**
* Build attributes XML
*/
private void buildMiscXML(Element root) {
Document doc = root.getOwnerDocument();
Element node;
node = doc.createElementNS(null, "characterEncoding");
node.appendChild(this.createTextNode(doc, this.request.getCharacterEncoding()));
root.appendChild(node);
node = doc.createElementNS(null, "contentLength");
node.appendChild(this.createTextNode(doc, "" + this.request.getContentLength()));
root.appendChild(node);
node = doc.createElementNS(null, "contentType");
node.appendChild(this.createTextNode(doc, this.request.getContentType()));
root.appendChild(node);
node = doc.createElementNS(null, "protocol");
node.appendChild(this.createTextNode(doc, this.request.getProtocol()));
root.appendChild(node);
node = doc.createElementNS(null, "remoteAddress");
node.appendChild(this.createTextNode(doc, this.request.getRemoteAddr()));
root.appendChild(node);
node = doc.createElementNS(null, "remoteHost");
node.appendChild(this.createTextNode(doc, this.request.getRemoteHost()));
root.appendChild(node);
node = doc.createElementNS(null, "scheme");
node.appendChild(this.createTextNode(doc, this.request.getScheme()));
root.appendChild(node);
node = doc.createElementNS(null, "serverName");
node.appendChild(this.createTextNode(doc, this.request.getServerName()));
root.appendChild(node);
node = doc.createElementNS(null, "serverPort");
node.appendChild(this.createTextNode(doc, ""+this.request.getServerPort()));
root.appendChild(node);
node = doc.createElementNS(null, "method");
node.appendChild(this.createTextNode(doc, this.request.getMethod()));
root.appendChild(node);
node = doc.createElementNS(null, "contextPath");
node.appendChild(this.createTextNode(doc, this.request.getContextPath()));
root.appendChild(node);
node = doc.createElementNS(null, "pathInfo");
node.appendChild(this.createTextNode(doc, this.request.getPathInfo()));
root.appendChild(node);
node = doc.createElementNS(null, "pathTranslated");
node.appendChild(this.createTextNode(doc, this.request.getPathTranslated()));
root.appendChild(node);
node = doc.createElementNS(null, "remoteUser");
node.appendChild(this.createTextNode(doc, this.request.getRemoteUser()));
root.appendChild(node);
node = doc.createElementNS(null, "requestedSessionId");
node.appendChild(this.createTextNode(doc, this.request.getRequestedSessionId()));
root.appendChild(node);
node = doc.createElementNS(null, "requestURI");
node.appendChild(this.createTextNode(doc, this.request.getRequestURI()));
root.appendChild(node);
node = doc.createElementNS(null, "servletPath");
node.appendChild(this.createTextNode(doc, this.request.getServletPath()));
root.appendChild(node);
node = doc.createElementNS(null, "isRequestedSessionIdFromCookie");
node.appendChild(doc.createTextNode(BooleanUtils.toStringTrueFalse(this.request.isRequestedSessionIdFromCookie())));
root.appendChild(node);
node = doc.createElementNS(null, "isRequestedSessionIdFromURL");
node.appendChild(doc.createTextNode(BooleanUtils.toStringTrueFalse(this.request.isRequestedSessionIdFromURL())));
root.appendChild(node);
node = doc.createElementNS(null, "isRequestedSessionIdValid");
node.appendChild(doc.createTextNode(BooleanUtils.toStringTrueFalse(this.request.isRequestedSessionIdValid())));
root.appendChild(node);
}
/**
* Build attributes XML
*/
private void buildAttributesXML(Element root)
throws ProcessingException {
Document doc = root.getOwnerDocument();
Element attrElement = doc.createElementNS(null, "attributes");
String attrName;
Element attr;
root.appendChild(attrElement);
Enumeration all = this.request.getAttributeNames();
while (all.hasMoreElements() == true) {
attrName = (String) all.nextElement();
try {
attr = doc.createElementNS(null, attrName);
attrElement.appendChild(attr);
DOMUtil.valueOf(attr, this.request.getAttribute(attrName));
} catch (DOMException de) {
// Some request attributes have names that are invalid as element names.
// Example : "FOM JavaScript GLOBAL SCOPE/file://my/path/to/flow/script.js"
this.logger.info("RequestSessionContext: Cannot create XML element from request attribute '" + attrName + "' : " + de.getMessage());
}
}
}
/**
* Build cookies XML
*/
private void buildCookiesXML(Element root) {
Document doc = root.getOwnerDocument();
Element cookiesElement = doc.createElementNS(null, "cookies");
root.appendChild(cookiesElement);
Cookie[] cookies = this.request.getCookies();
if (cookies != null) {
Cookie current;
Element node;
Element parent;
for(int i = 0; i < cookies.length; i++) {
current = cookies[i];
parent = doc.createElementNS(null, "cookie");
parent.setAttributeNS(null, "name", current.getName());
cookiesElement.appendChild(parent);
node = doc.createElementNS(null, "comment");
node.appendChild(this.createTextNode(doc, current.getComment()));
parent.appendChild(node);
node = doc.createElementNS(null, "domain");
node.appendChild(this.createTextNode(doc, current.getDomain()));
parent.appendChild(node);
node = doc.createElementNS(null, "maxAge");
node.appendChild(this.createTextNode(doc, "" + current.getMaxAge()));
parent.appendChild(node);
node = doc.createElementNS(null, "name");
node.appendChild(this.createTextNode(doc, current.getName()));
parent.appendChild(node);
node = doc.createElementNS(null, "path");
node.appendChild(this.createTextNode(doc, current.getPath()));
parent.appendChild(node);
node = doc.createElementNS(null, "secure");
node.appendChild(doc.createTextNode(BooleanUtils.toStringTrueFalse(current.getSecure())));
parent.appendChild(node);
node = doc.createElementNS(null, "value");
node.appendChild(this.createTextNode(doc, current.getValue()));
parent.appendChild(node);
node = doc.createElementNS(null, "version");
node.appendChild(this.createTextNode(doc, "" + current.getVersion()));
parent.appendChild(node);
}
}
}
/**
* Build headers XML
*/
private void buildHeadersXML(Element root) {
Document doc = root.getOwnerDocument();
Element headersElement = doc.createElementNS(null, "headers");
String headerName;
Element header;
root.appendChild(headersElement);
Enumeration all = this.request.getHeaderNames();
while (all.hasMoreElements() == true) {
headerName = (String) all.nextElement();
try {
header = doc.createElementNS(null, headerName);
headersElement.appendChild(header);
header.appendChild(this.createTextNode(doc, this.request.getHeader(headerName)));
} catch (Exception ignore) {
// if the header name is not a valid element name, we simply ignore it
}
}
}
/**
* Build parameter XML
*/
private void buildParameterXML(Element root, SAXParser parser) {
Document doc = root.getOwnerDocument();
// include all parameters
// process "/parameter" and "/parametervalues" at the same time
Element parameterElement = doc.createElementNS(null, "parameter");
Element parameterValuesElement = doc.createElementNS(null, "parametervalues");
root.appendChild(parameterElement);
root.appendChild(parameterValuesElement);
String parameterName = null;
Enumeration pars = this.request.getParameterNames();
Element parameter;
Element element;
Node valueNode;
String[] values;
String parValue;
element = doc.createElementNS(CIncludeTransformer.CINCLUDE_NAMESPACE_URI, PARAMETERS_ELEMENT);
element.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:cinclude", CIncludeTransformer.CINCLUDE_NAMESPACE_URI);
parameterValuesElement.appendChild(element);
parameterValuesElement = element;
while (pars.hasMoreElements() == true) {
parameterName = (String)pars.nextElement();
values = this.request.getParameterValues(parameterName);
for(int i = 0; i < values.length; i++) {
// this is a fast test, if the parameter value contains xml!
parValue = values[i].trim();
if (parValue.length() > 0 && parValue.charAt(0) == '<') {
try {
valueNode = DOMUtil.getDocumentFragment(parser, new StringReader(parValue));
valueNode = doc.importNode(valueNode, true);
} catch (Exception noXMLException) {
valueNode = doc.createTextNode(parValue);
}
} else {
valueNode = doc.createTextNode(parValue);
}
// create "/parameter" entry for first value
if (i == 0) {
try {
parameter = doc.createElementNS(null, parameterName);
parameter.appendChild(valueNode);
parameterElement.appendChild(parameter);
} catch (Exception local) {
// the exception is ignored and only this parameters is ignored
}
}
try {
// create "/parametervalues" entry
element = doc.createElementNS(CIncludeTransformer.CINCLUDE_NAMESPACE_URI, PARAMETER_ELEMENT);
parameterValuesElement.appendChild(element);
parameter = element;
element = doc.createElementNS(CIncludeTransformer.CINCLUDE_NAMESPACE_URI, NAME_ELEMENT);
parameter.appendChild(element);
element.appendChild(doc.createTextNode(parameterName));
element = doc.createElementNS(CIncludeTransformer.CINCLUDE_NAMESPACE_URI, VALUE_ELEMENT);
parameter.appendChild(element);
element.appendChild(valueNode.cloneNode(true));
} catch (Exception local) {
// the exception is ignored and only this parameters is ignored
}
}
}
// and now the query string
element = doc.createElementNS(null, "querystring");
root.appendChild(element);
String value = request.getQueryString();
if (value != null) {
element.appendChild(doc.createTextNode('?' + value));
}
}
/**
* Get the XML from the request object
*/
public DocumentFragment getXML(String path)
throws ProcessingException {
if (path == null || path.charAt(0) != '/') {
throw new ProcessingException("Not a valid XPath: " + path);
}
path = this.createPath(path);
DocumentFragment result = null;
NodeList list;
try {
list = DOMUtil.selectNodeList(this.contextData, path, this.xpathProcessor);
} catch (javax.xml.transform.TransformerException localException) {
throw new ProcessingException("Exception: " + localException, localException);
}
if (list != null && list.getLength() > 0) {
result = DOMUtil.getOwnerDocument(contextData).createDocumentFragment();
for(int i = 0; i < list.getLength(); i++) {
// the found node is either an attribute or an element
if (list.item(i).getNodeType() == Node.ATTRIBUTE_NODE) {
// if it is an attribute simple create a new text node with the value of the attribute
result.appendChild(DOMUtil.getOwnerDocument(contextData).createTextNode(list.item(i).getNodeValue()));
} else {
// now we have an element
// copy all children of this element in the resulting tree
NodeList childs = list.item(i).getChildNodes();
if (childs != null) {
for(int m = 0; m < childs.getLength(); m++) {
result.appendChild(DOMUtil.getOwnerDocument(contextData).importNode(childs.item(m), true));
}
}
}
}
}
return result;
}
/**
* Setting of xml is not possible for the request context
*/
public void setXML(String path, DocumentFragment fragment)
throws ProcessingException {
throw new ProcessingException("RequestSessionContext: Setting of xml not allowed");
}
/**
* Setting of xml is not possible for the request context
*/
public void setValueOfNode(String path, String value)
throws ProcessingException {
throw new ProcessingException("RequestSessionContext: Setting of xml not allowed");
}
/**
* Append a document fragment is not possible for the request context.
*/
public void appendXML(String path, DocumentFragment fragment)
throws ProcessingException {
throw new ProcessingException("RequestSessionContext: Appending of xml not allowed");
}
/**
* Removing is not possible for the request context.
*/
public void removeXML(String path)
throws ProcessingException {
throw new ProcessingException("RequestSessionContext: Removing of xml not allowed");
}
/**
* Set a context attribute. If value is null the attribute is removed.
*/
public void setAttribute(String key, Object value)
throws ProcessingException {
if (value == null) {
this.request.removeAttribute(key);
} else {
this.request.setAttribute(key, value);
}
}
/**
* Get a context attribute. If the attribute is not available return null
*/
public Object getAttribute(String key)
throws ProcessingException {
return this.request.getAttribute(key);
}
/**
* Get a context attribute. If the attribute is not available the defaultObject is returned
*/
public Object getAttribute(String key, Object defaultObject)
throws ProcessingException {
Object obj = this.getAttribute(key);
return (obj != null ? obj : defaultObject);
}
/**
* Get a copy the first node specified by the path.
*/
public Node getSingleNode(String path)
throws ProcessingException {
path = this.createPath(path);
Node node = null;
try {
node = DOMUtil.getSingleNode(this.contextData, path, this.xpathProcessor);
} catch (javax.xml.transform.TransformerException localException) {
throw new ProcessingException("Exception: " + localException, localException);
}
return node;
}
/**
* Get a copy all the nodes specified by the path.
*/
public NodeList getNodeList(String path)
throws ProcessingException {
path = this.createPath(path);
NodeList list = null;
try {
list = DOMUtil.selectNodeList(this.contextData, path, this.xpathProcessor);
} catch (javax.xml.transform.TransformerException localException) {
throw new ProcessingException("Exception: " + localException, localException);
}
return list;
}
/**
* Set the value of a node. The node is copied before insertion.
*/
public void setNode(String path, Node node)
throws ProcessingException {
throw new ProcessingException("RequestSessionContext: Setting of XML not allowed");
}
/**
* Get the value of this node. This is similiar to the xsl:value-of
* function. If the node does not exist, <code>null</code> is returned.
*/
public String getValueOfNode(String path)
throws ProcessingException {
String value = null;
Node node = this.getSingleNode(path);
if (node != null) {
value = DOMUtil.getValueOfNode(node);
}
return value;
}
/**
* Stream the XML directly to the handler. This streams the contents of getXML()
* to the given handler without creating a DocumentFragment containing a copy
* of the data
*/
public boolean streamXML(String path,
ContentHandler contentHandler,
LexicalHandler lexicalHandler)
throws SAXException, ProcessingException {
boolean result = false;
NodeList list;
try {
list = DOMUtil.selectNodeList(this.contextData, this.createPath(path), this.xpathProcessor);
} catch (javax.xml.transform.TransformerException local) {
throw new ProcessingException("TransformerException: " + local, local);
}
if (list != null && list.getLength() > 0) {
result = true;
for(int i = 0; i < list.getLength(); i++) {
// the found node is either an attribute or an element
if (list.item(i).getNodeType() == Node.ATTRIBUTE_NODE) {
// if it is an attribute simple create a new text node with the value of the attribute
String value = list.item(i).getNodeValue();
contentHandler.characters(value.toCharArray(), 0, value.length());
} else {
// now we have an element
// stream all children of this element to the resulting tree
NodeList childs = list.item(i).getChildNodes();
if (childs != null) {
for(int m = 0; m < childs.getLength(); m++) {
IncludeXMLConsumer.includeNode(childs.item(m), contentHandler, lexicalHandler);
}
}
}
}
}
return result;
}
/**
* Get the request parameter as xml
*/
public DocumentFragment getParameterAsXML(final String parameterName)
throws ProcessingException {
return this.getXML("/parameter/"+parameterName);
}
/**
* Get the request parameter as a String
*/
public String getParameter(final String parameterName) {
return this.request.getParameter(parameterName);
}
/**
* Try to load XML into the context.
* If the context does not provide the ability of loading,
* an exception is thrown.
*/
public void loadXML(String path,
SourceParameters parameters)
throws SAXException, ProcessingException, IOException {
throw new ProcessingException("The context " + this.name + " does not support loading.");
}
/**
* Try to save XML from the context.
* If the context does not provide the ability of saving,
* an exception is thrown.
*/
public void saveXML(String path,
SourceParameters parameters)
throws SAXException, ProcessingException, IOException {
throw new ProcessingException("The context " + this.name + " does not support saving.");
}
}