/* * 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.portal.context; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.cocoon.webapps.portal.PortalConstants; import org.apache.cocoon.webapps.portal.components.PortalManager; import org.apache.cocoon.webapps.portal.components.PortalManagerImpl; import org.apache.cocoon.webapps.session.context.SessionContext; import org.apache.cocoon.xml.IncludeXMLConsumer; import org.apache.cocoon.xml.dom.DOMBuilder; import org.apache.cocoon.xml.dom.DOMUtil; import org.apache.excalibur.source.SourceParameters; import org.apache.excalibur.xml.xpath.XPathProcessor; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.DocumentFragment; import org.w3c.dom.Attr; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * The portal context * * This context allows access to various parts of a portal profile. * The context provides reading of the following xml, if the current * resource is running inside a portal module: * <layout> * <portal> * ... * </portal> * <coplets> * ... * </coplets> * </layout> * <configuration> * ... * </configuration> * * @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a> * @version CVS $Id$ */ public final class SessionContextImpl implements SessionContext { /* This contains all information about the currently processed coplet */ public static ThreadLocal copletInfo = new ThreadLocal(); /** The context name */ private String name; /** The attributes */ private Map attributes = new HashMap(); /** The cached layoutDOM */ private Document layoutDOM; /** The cached configurationDOM */ private Document configurationDOM; /** The current profile */ private Map profile; /** All coplet parameters */ private SourceParameters copletPars; /** The status profile */ private Element statusProfile; /** the coplet id */ private String copletID; /** The number of the coplet */ private String copletNumber; /** The profile ID */ private String profileID; /** The portal URI */ private String portalURI; /** The media type */ private String mediaType; /** The current request */ private Request request; /** The XPath Processor */ private XPathProcessor xpathProcessor; public SessionContextImpl(String name, Map objectModel, PortalManager portal, XPathProcessor xpathProcessor) throws IOException, SAXException, ProcessingException { this.xpathProcessor = xpathProcessor; this.setup(name, null, null); // try to get the resource connector info Map info = (Map)SessionContextImpl.copletInfo.get(); if (info != null) { SessionContextImpl.copletInfo.set(null); this.copletPars = (SourceParameters)info.get(PortalConstants.COPLETINFO_PARAMETERS); this.portalURI = (String)info.get(PortalConstants.COPLETINFO_PORTALURI); if (this.copletPars != null) { this.copletID = this.copletPars.getParameter(PortalConstants.PARAMETER_ID); this.copletNumber = this.copletPars.getParameter(PortalConstants.PARAMETER_NUMBER); if (this.copletID != null && this.copletNumber != null) { this.portalURI = this.portalURI + (this.portalURI.indexOf('?') == -1 ? '?' : '&') + "portalcmd=update_" + this.copletID + "_" + this.copletNumber; } } this.statusProfile = (Element)info.get(PortalConstants.COPLETINFO_STATUSPROFILE); } this.mediaType = (this.copletPars != null ? (String)copletPars.getParameter(PortalConstants.PARAMETER_MEDIA) : portal.getMediaType()); // get the profile SessionContext context = portal.getContext(false); if (context != null) { if (context.getAttribute(PortalManager.ATTRIBUTE_PORTAL_ROLE) != null) { this.profileID = portal.getProfileID(PortalManager.BUILDTYPE_VALUE_ID, (String)context.getAttribute(PortalManager.ATTRIBUTE_PORTAL_ROLE), (String)context.getAttribute(PortalManager.ATTRIBUTE_PORTAL_ID), false); this.profile = portal.retrieveProfile(this.profileID); } } this.getConfigurationDOM(portal); this.request = ObjectModelHelper.getRequest( objectModel ); } /** * Get the name of the context */ public String getName() { return this.name; } public Request getRequest() { return this.request; } /** * Get the layout DOM */ private void getLayoutDOM() throws ProcessingException { if (this.layoutDOM == null && this.profile != null) { try { Map portalLayouts = (Map)this.profile.get(PortalConstants.PROFILE_PORTAL_LAYOUTS); Map copletLayouts = (Map)this.profile.get(PortalConstants.PROFILE_COPLET_LAYOUTS); DOMBuilder builder = new DOMBuilder(); builder.startDocument(); PortalManagerImpl.streamLayoutProfile(builder, portalLayouts, copletLayouts, this.mediaType); builder.endDocument(); this.layoutDOM = builder.getDocument(); } catch (SAXException local) { throw new ProcessingException("Unable to get portal." + local, local); } } } /** * Get the configuration DOM */ private void getConfigurationDOM(PortalManager portal) throws ProcessingException, IOException { if (this.configurationDOM == null && portal != null) { try { String contextID = null; if (this.copletID != null && this.copletNumber != null) { contextID = "coplet_"+copletID+"_"+copletNumber; } DOMBuilder builder = new DOMBuilder(); builder.startDocument(); portal.streamConfiguration(builder, this.portalURI, this.profileID, this.mediaType, contextID); builder.endDocument(); this.configurationDOM = builder.getDocument(); } catch (SAXException local) { throw new ProcessingException("Unable to get portal." + local, local); } } } /* Set the context name */ public void setup(String value, String load, String save) { name = value; } /** * Get the xml fragment */ public synchronized DocumentFragment getXML(String path) throws ProcessingException { DocumentFragment result = null; if (path.startsWith("/")) path = path.substring(1); NodeList list = null; if (path == null || path.length() == 0) { Document doc = DOMUtil.createDocument(); result = doc.createDocumentFragment(); this.getLayoutDOM(); if (this.layoutDOM != null) { result.appendChild(doc.importNode(this.layoutDOM.getDocumentElement(), true)); } if (this.configurationDOM != null) { result.appendChild(doc.importNode(this.configurationDOM.getDocumentElement(), true)); } if (this.statusProfile != null) { if (this.copletID != null && this.copletNumber != null) { String statusPath = "customization/coplet[@id='"+copletID+"' and @number='"+copletNumber+"']"; try { Node node = DOMUtil.getSingleNode(this.statusProfile, statusPath, this.xpathProcessor); if (node != null) { Element copletData = doc.createElementNS(null, "coplet-data"); NodeList childs = node.getChildNodes(); if (childs != null) { for(int l=0; l<childs.getLength(); l++) { copletData.appendChild(doc.importNode(childs.item(l), true)); } } result.appendChild(copletData); } } catch (javax.xml.transform.TransformerException localException) { throw new ProcessingException("TransformerException: " + localException, localException); } } } } if (path.equals("layout") || path.startsWith("layout/") ) { try { this.getLayoutDOM(); if (this.layoutDOM != null) list = DOMUtil.selectNodeList(this.layoutDOM, path, this.xpathProcessor); } catch (javax.xml.transform.TransformerException localException) { throw new ProcessingException("TransformerException: " + localException, localException); } } if (path.equals("configuration") || path.startsWith("configuration/") ) { try { if (this.configurationDOM != null) list = DOMUtil.selectNodeList(this.configurationDOM, path, this.xpathProcessor); } catch (javax.xml.transform.TransformerException localException) { throw new ProcessingException("TransformerException: " + localException, localException); } } if (path.startsWith("coplet-data/") || path.equals("coplet-data") ) { if (this.statusProfile != null) { if (this.copletID != null && this.copletNumber != null) { String statusPath = "customization/coplet[@id='"+copletID+"' and @number='"+copletNumber+"']"; if (path.startsWith("coplet-data/")) { statusPath = statusPath + path.substring(11); } try { list = DOMUtil.selectNodeList(this.statusProfile, statusPath, this.xpathProcessor); } catch (javax.xml.transform.TransformerException localException) { throw new ProcessingException("TransformerException: " + localException, localException); } } } } 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; } /** * Set the xml */ public synchronized void setXML(String path, DocumentFragment fragment) throws ProcessingException { if (path != null) { if (path.startsWith("/") ) path = path.substring(1); if (path.startsWith("coplet-data/") || path.equals("coplet-data") ) { if (this.statusProfile != null) { if (this.copletID != null && this.copletNumber != null) { String statusPath = "customization/coplet[@id='"+copletID+"' and @number='"+copletNumber+"']"; if (path.startsWith("coplet-data/")) { statusPath = statusPath + path.substring(11); } Node node = DOMUtil.selectSingleNode(this.statusProfile, statusPath, 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()) { 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 = this.statusProfile.getOwnerDocument().importNode(childs.item(i), true); node.appendChild(n); } } } if (this.copletPars.getParameter(PortalConstants.PARAMETER_PERSISTENT, "false").equals("true") ) { this.profile.put(PortalConstants.PROFILE_SAVE_STATUS_FLAG, "true"); } } } } } } /** * 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 { throw new ProcessingException("appendXML() not implemented."); } /** * Remove nodes */ public synchronized void removeXML(String path) throws ProcessingException { throw new ProcessingException("removeXML() not implemented."); } /** * Get a copy the first node specified by the path. */ public synchronized Node getSingleNode(String path) throws ProcessingException { // Node result = null; throw new ProcessingException("getSingleNode() not implemented."); // return result; } /** * Get a copy all the nodes specified by the path. */ public synchronized NodeList getNodeList(String path) throws ProcessingException { // NodeList result = null; throw new ProcessingException("getNodeList() not implemented."); // return result; } /** * Set the value of a node. The node is copied before insertion. */ public synchronized void setNode(String path, Node node) throws ProcessingException { throw new ProcessingException("setNode() not implemented."); } /** * 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; throw new ProcessingException("getValueOfNode() not implemented."); // return value; } /** * Set the value of a node. */ public synchronized void setValueOfNode(String path, String value) throws ProcessingException { throw new ProcessingException("setValueOfNode() not implemented."); } /** * 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 { boolean streamed = false; DocumentFragment fragment = this.getXML(path); if (fragment != null) { streamed = true; IncludeXMLConsumer.includeNode(fragment, 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 { 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."); } }