blob: 62d4e78be235042d8fc4d4f5904b799f53e8982d [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed 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.avalon.framework.service.ServiceManager;
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.source.SourceResolver;
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: SessionContextImpl.java,v 1.8 2004/03/05 13:02:18 bdelacretaz Exp $
*/
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.equals("")) {
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,
Map objectModel,
SourceResolver resolver,
ServiceManager manager)
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,
Map objectModel,
SourceResolver resolver,
ServiceManager manager)
throws SAXException, ProcessingException, IOException {
throw new ProcessingException("The context " + this.name + " does not support saving.");
}
}