/* * 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.util.HashMap; import java.util.Map; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.webapps.session.xml.XMLUtil; import org.apache.cocoon.xml.IncludeXMLConsumer; import org.apache.cocoon.xml.dom.DOMUtil; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.excalibur.source.SourceParameters; import org.apache.excalibur.source.SourceResolver; import org.apache.excalibur.xml.xpath.NodeListImpl; import org.apache.excalibur.xml.xpath.XPathProcessor; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.DocumentFragment; 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; /** * This is a simple implementation of the session context. * * @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 SimpleSessionContext implements SessionContext { /** Context name */ private String name; /** The content of the context */ private Document data; /** The attributes */ private Map attributes = new HashMap(); /** load resource */ private String loadResource; /** save resource */ private String saveResource; /** The XPath Processor */ private XPathProcessor xpathProcessor; /** The source resolver */ private SourceResolver resolver; /** * Constructor */ public SimpleSessionContext(XPathProcessor xPathProcessor, SourceResolver resolver) throws ProcessingException { this.data = DOMUtil.createDocument(); this.data.appendChild(data.createElementNS(null, "context")); this.xpathProcessor = xPathProcessor; this.resolver = resolver; } /** * Get the name of the context */ public String getName() { return this.name; } /* (non-Javadoc) * @see org.apache.cocoon.webapps.session.context.SessionContext#setup(java.lang.String, java.lang.String, java.lang.String) */ public void setup(String value, String loadResource, String saveResource) { this.name = value; this.loadResource = loadResource; this.saveResource = saveResource; } public synchronized DocumentFragment getXML(String path) throws ProcessingException { DocumentFragment result = null; NodeList list; path = this.createPath(path); String[] pathComponents = DOMUtil.buildPathArray(path); if (pathComponents == null) { list = this.xpathProcessor.selectNodeList(this.data, path); } else { list = DOMUtil.getNodeListFromPath(data, pathComponents); } if (list != null && list.getLength() > 0) { Document doc = DOMUtil.createDocument(); result = doc.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(doc.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(doc.importNode(childs.item(m), true)); } } } } } return result; } public synchronized void setXML(String path, DocumentFragment fragment) throws ProcessingException { path = this.createPath(path); Node node = DOMUtil.selectSingleNode(data, path, this.xpathProcessor); if (node.getNodeType() == Node.ATTRIBUTE_NODE) { // now we have to serialize the fragment to a string and insert this Attr attr = (Attr)node; attr.setNodeValue(DOMUtil.getValueOfNode(fragment)); } else { // remove old childs while (node.hasChildNodes() == true) { node.removeChild(node.getFirstChild()); } // Insert new childs NodeList childs = fragment.getChildNodes(); if (childs != null && childs.getLength() > 0) { for(int i = 0; i < childs.getLength(); i++) { Node n = data.importNode(childs.item(i), true); node.appendChild(n); } } } } /** * Append a document fragment at the given path. The implementation of this * method is context specific. * Usually the children of the fragment are appended as new children of the * node specified by the path. * If the path is not existent it is created. */ public synchronized void appendXML(String path, DocumentFragment fragment) throws ProcessingException { path = this.createPath(path); Node node = DOMUtil.selectSingleNode(data, path, this.xpathProcessor); if (node.getNodeType() == Node.ATTRIBUTE_NODE) { Attr attr; if (node.getNodeValue() != null || node.getNodeValue().trim().length() > 0) { // this is an existing attr, create a new one attr = node.getOwnerDocument().createAttributeNS(null, node.getNodeName()); node.getParentNode().appendChild(attr); } else { attr = (Attr)node; } // now we have to serialize the fragment to a string and insert this attr.setNodeValue(DOMUtil.getValueOfNode(fragment)); } else { // Insert new childs NodeList childs = fragment.getChildNodes(); if (childs != null && childs.getLength() > 0) { for(int i = 0; i < childs.getLength(); i++) { Node n = data.importNode(childs.item(i), true); node.appendChild(n); } } } } /** * Build path */ private String createPath(String path) { if (path == null) path ="/"; if (!path.startsWith("/") ) path = "/" + path; path = "context" + path; if (path.endsWith("/")) path = path.substring(0, path.length() - 1); return path; } /** * Remove nodes */ public synchronized void removeXML(String path) throws ProcessingException { NodeList list; path = this.createPath(path); String[] pathComponents = DOMUtil.buildPathArray(path); if (pathComponents == null) { list = this.xpathProcessor.selectNodeList(this.data, path); } else { list = DOMUtil.getNodeListFromPath(data, pathComponents); } if (list != null && list.getLength() > 0) { int len = list.getLength(); Node child; for(int i = 0; i < len; i++) { child = list.item(len - 1 -i); child.getParentNode().removeChild(child); } } } /** * Get a copy the first node specified by the path. */ public synchronized Node getSingleNode(String path) throws ProcessingException { Node result = null; path = this.createPath(path); try { result = DOMUtil.getSingleNode(data, path, this.xpathProcessor); if (result != null) result = result.cloneNode(true); } catch (javax.xml.transform.TransformerException localException) { throw new ProcessingException("TransformerException: " + localException, localException); } return result; } /** * Get a copy all the nodes specified by the path. */ public synchronized NodeList getNodeList(String path) throws ProcessingException { NodeList result = null; path = this.createPath(path); String[] pathComponents = DOMUtil.buildPathArray(path); if (pathComponents == null) { result = this.xpathProcessor.selectNodeList(this.data, path); } else { result = DOMUtil.getNodeListFromPath(data, pathComponents); } // clone list if (result != null) { result = new NodeListImpl(result); } return result; } /** * Set the value of a node. The node is copied before insertion. */ public synchronized void setNode(String path, Node node) throws ProcessingException { if ( path == null || path.equals("/")) { data = DOMUtil.createDocument(); data.appendChild(data.createElementNS(null, "context")); data.getFirstChild().appendChild(data.importNode(node, true)); } else { path = this.createPath(path); Node removeNode = DOMUtil.selectSingleNode(data, path, this.xpathProcessor); removeNode.getParentNode().replaceChild(data.importNode(node, true), removeNode); } } /** * Set a context attribute. If value is null the attribute is removed. */ public synchronized void setAttribute(String key, Object value) { if (value == null) { attributes.remove(key); } else { attributes.put(key, value); } } /** * Get a context attribute. If the attribute is not available return null */ public synchronized Object getAttribute(String key) { return attributes.get(key); } /** * Get a context attribute. If the attribute is not available the defaultObject is returned */ public synchronized Object getAttribute(String key, Object defaultObject) { Object value = attributes.get(key); if (value == null) value = defaultObject; return value; } /** * 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 synchronized String getValueOfNode(String path) throws ProcessingException { String value = null; path = this.createPath(path); // correct path value = DOMUtil.getValueOf(data, path, this.xpathProcessor); return value; } /** * Set the value of a node. */ public synchronized void setValueOfNode(String path, String value) throws ProcessingException { path = this.createPath(path); // correct path Node node = DOMUtil.selectSingleNode(data, path, this.xpathProcessor); if (node.getNodeType() == Node.ATTRIBUTE_NODE) { Attr attr = (Attr)node; attr.setNodeValue(value); } else { // remove old childs while (node.hasChildNodes() == true) { node.removeChild(node.getFirstChild()); } node.appendChild(node.getOwnerDocument().createTextNode(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 synchronized boolean streamXML(String path, ContentHandler contentHandler, LexicalHandler lexicalHandler) throws SAXException, ProcessingException { NodeList list; boolean streamed = false; path = this.createPath(path); String[] pathComponents = DOMUtil.buildPathArray(path); if (pathComponents == null) { list = this.xpathProcessor.selectNodeList(this.data, path); } else { list = DOMUtil.getNodeListFromPath(data, pathComponents); } if (list != null && list.getLength() > 0) { streamed = 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 streamed; } /** * 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 { if (this.loadResource == null) { throw new ProcessingException("The context " + this.name + " does not support loading."); } Source source = null; try { source = SourceUtil.getSource(this.loadResource, null, parameters, this.resolver); Document doc = SourceUtil.toDOM(source); DocumentFragment df = doc.createDocumentFragment(); df.appendChild(doc.getDocumentElement()); this.setXML(path, df); } catch (SourceException se) { throw SourceUtil.handle(se); } finally { resolver.release(source); } } /** * 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 { if (this.saveResource == null) { throw new ProcessingException("The context " + this.name + " does not support saving."); } DocumentFragment frag = this.getXML(path); if (frag == null) { // create empty fake document frag = DOMUtil.createDocument().createDocumentFragment(); } XMLUtil.writeDOM(this.saveResource, null, parameters, frag, this.resolver, "xml"); } }