/* * 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."); } }