blob: c3bef006060f8649eae22bc7fb6e7e91e92de892 [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.components;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.webapps.session.ContextManager;
import org.apache.cocoon.webapps.session.SessionConstants;
import org.apache.cocoon.webapps.session.SessionManager;
import org.apache.cocoon.webapps.session.context.SessionContext;
import org.apache.cocoon.xml.XMLConsumer;
import org.apache.cocoon.xml.XMLUtils;
import org.apache.cocoon.xml.dom.DOMUtil;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This is the default implementation of the session manager
*
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
* @deprecated This block is deprecated and will be removed in future versions.
* @version CVS $Id$
*/
public final class DefaultSessionManager
extends AbstractLogEnabled
implements Serviceable, Component, ThreadSafe, SessionManager, Disposable, Contextualizable {
/** The context */
private Context context;
/** The <code>ServiceManager</code> */
private ServiceManager manager;
/** The context manager */
private ContextManager contextManager;
/**
* Avalon Serviceable Interface
*/
public void service(ServiceManager manager)
throws ServiceException {
this.manager = manager;
this.contextManager = (ContextManager)this.manager.lookup(ContextManager.ROLE);
}
/**
* Avalon Disposable Interface
*/
public void dispose() {
if (this.manager != null ) {
this.manager.release(this.contextManager);
this.manager = null;
this.contextManager = null;
}
}
/**
* Create a new session for the user.
* A new session is created for this user. If the user has already a session,
* no new session is created and the old one is returned.
*/
public Session createSession() {
// synchronized
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN createSession");
}
Session session = this.getSession(true);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END createSession session=" + session);
}
return session;
}
/**
* Get the session for the current user.
* If the user has no session right now, <CODE>null</CODE> is returned.
* If createFlag is true, the session is created if it does not exist.
*/
public Session getSession(boolean createFlag) {
final Request request = ContextHelper.getRequest(this.context);
// synchronized
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN getSession create=" + createFlag);
}
Session session = request.getSession(createFlag);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END getSession session=" + session);
}
return session;
}
/**
* Terminate the current session.
* If the user has a session, this session is terminated and all of its
* data is deleted.
* @param force If this is set to true the session is terminated, if
* it is set to false, the session is only terminated
* if no session context is available.
*/
public void terminateSession(boolean force)
throws ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN terminateSession force="+force);
}
Session session = this.getSession( false );
if (session != null) {
if (force || this.contextManager.hasSessionContext() ) {
synchronized(session) {
session.invalidate();
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END terminateSession");
}
}
/**
* Get information from the context.
* A document fragment containg the xml data stored in the session context
* with the given name is returned. If the information is not available,
* <CODE>null</CODE> is returned.
* @param contextName The name of the public context.
* @param path XPath expression specifying which data to get.
* @return A DocumentFragment containing the data or <CODE>null</CODE>
*/
public DocumentFragment getContextFragment(String contextName,
String path)
throws ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN getContextFragment name=" + contextName + ", path=" + path);
}
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.getContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.getContextFragment: Path is required");
}
SessionContext context = this.contextManager.getContext( contextName );
if (context == null) {
throw new ProcessingException("SessionManager.getContextFragment: Context '" + contextName + "' not found.");
}
DocumentFragment frag;
frag = context.getXML(path);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END getContextFragment documentFragment=" + (frag == null ? "null" : XMLUtils.serializeNode(frag, XMLUtils.createPropertiesForXML(false))));
}
return frag;
}
/**
* Stream public context data.
* The document fragment containing the data from a path in the
* given context is streamed to the consumer.
*
* @param contextName The name of the public context.
* @param path XPath expression specifying which data to get.
*
* @return If the data is available <code>true</code> is returned,
* otherwise <code>false</code> is returned.
*/
public boolean streamContextFragment(String contextName,
String path,
XMLConsumer consumer)
throws SAXException, ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN streamContextFragment name=" + contextName + ", path=" + path + ", consumer"+consumer);
}
boolean streamed = false;
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.streamContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.streamContextFragment: Path is required");
}
SessionContext context = this.contextManager.getContext( contextName );
if (context == null) {
throw new ProcessingException("SessionManager.streamContextFragment: Context '" + contextName + "' not found.");
}
streamed = context.streamXML(path, consumer, consumer);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END streamContextFragment streamed=" + streamed);
}
return streamed;
}
/**
* Set data in a public context.
* The document fragment containing the data is set at the given path in the
* public session context.
*
* @param contextName The name of the public context.
* @param path XPath expression specifying where to set the data.
* @param fragment The DocumentFragment containing the data.
*
*/
public void setContextFragment(String contextName,
String path,
DocumentFragment fragment)
throws ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN setContextFragment name=" + contextName + ", path=" + path +
", fragment=" + (fragment == null ? "null" : XMLUtils.serializeNode(fragment, XMLUtils.createPropertiesForXML(false))));
}
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.setContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.setContextFragment: Path is required");
}
if (fragment == null) {
throw new ProcessingException("SessionManager.setContextFragment: Fragment is required");
}
// get context
SessionContext context = this.contextManager.getContext( contextName );
// check context
if (context == null) {
throw new ProcessingException("SessionManager.setContextFragment: Context '" + contextName + "' not found.");
}
context.setXML(path, fragment);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END setContextFragment");
}
}
/**
* Append data in a public context.
* The document fragment containing the data is appended at the given
* path in the public session context.
*
* @param contextName The name of the public context.
* @param path XPath expression specifying where to append the data.
* @param fragment The DocumentFragment containing the data.
*
*/
public void appendContextFragment(String contextName,
String path,
DocumentFragment fragment)
throws ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN appendContextFragment name=" + contextName +
", path=" + path +
", fragment=" + (fragment == null ? "null" : XMLUtils.serializeNode(fragment, XMLUtils.createPropertiesForXML(false))));
}
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.appendContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.appendContextFragment: Path is required");
}
if (fragment == null) {
throw new ProcessingException("SessionManager.appendContextFragment: Fragment is required");
}
// get context
SessionContext context = this.contextManager.getContext( contextName );
// check context
if (context == null) {
throw new ProcessingException("SessionManager.appendContextFragment: Context '" + contextName + "' not found.");
}
context.appendXML(path, fragment);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END appendContextFragment");
}
}
/**
* Merge data in a public context.
* The document fragment containing the data is merged at the given
* path in the public session context.
*
* @param contextName The name of the public context.
* @param path XPath expression specifying where to merge the data.
* @param fragment The DocumentFragment containing the data.
*
*/
public void mergeContextFragment(String contextName,
String path,
DocumentFragment fragment)
throws ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN mergeContextFragment name=" + contextName + ", path=" + path +
", fragment=" + (fragment == null ? "null" : XMLUtils.serializeNode(fragment, XMLUtils.createPropertiesForXML(false))));
}
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.mergeContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.mergeContextFragment: Path is required");
}
if (fragment == null) {
throw new ProcessingException("SessionManager.mergeContextFragment: Fragment is required");
}
// get context
SessionContext context = this.contextManager.getContext( contextName );
// check context
if (context == null) {
throw new ProcessingException("SessionManager.mergeContextFragment: Context '" + contextName + "' not found.");
}
Node contextNode = context.getSingleNode(path);
if (contextNode == null) {
// no merge required
context.setXML(path, fragment);
} else {
this.importNode(contextNode, fragment, false);
context.setNode(path, contextNode);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END mergeContextFragment");
}
}
/**
* Remove data in a public context.
* The data specified by the path is removed from the public session context.
*
* @param contextName The name of the public context.
* @param path XPath expression specifying where to merge the data.
*
*/
public void removeContextFragment(String contextName,
String path)
throws ProcessingException {
// synchronized via context
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN removeContextFragment name=" + contextName + ", path=" + path);
}
// test arguments
if (contextName == null) {
throw new ProcessingException("SessionManager.removeContextFragment: Name is required");
}
if (path == null) {
throw new ProcessingException("SessionManager.removeContextFragment: Path is required");
}
// get context
SessionContext context = this.contextManager.getContext( contextName );
// check context
if (context == null) {
throw new ProcessingException("SessionManager.removeContextFragment: Context '" + contextName + "' not found.");
}
context.removeXML(path);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END removeContextFragment");
}
}
/**
* Import nodes. If preserve is set to true, the nodes
* marked with cocoon:preserve are always imported
* overwriting others!
*/
private void importNode(Node profile, Node delta, boolean preserve) {
// no sync req
NodeList profileChilds = null;
NodeList deltaChilds = delta.getChildNodes();
int i, len;
int m, l;
boolean found;
Node currentDelta = null;
Node currentProfile = null;
len = deltaChilds.getLength();
for(i = 0; i < len; i++) {
currentDelta = deltaChilds.item(i);
if (currentDelta.getNodeType() == Node.ELEMENT_NODE) {
// search the delta node in the profile
profileChilds = profile.getChildNodes();
l = profileChilds.getLength();
m = 0;
found = false;
while (found == false && m < l) {
currentProfile = profileChilds.item(m);
if (currentProfile.getNodeType() == Node.ELEMENT_NODE
&& currentProfile.getNodeName().equals(currentDelta.getNodeName()) == true) {
// now we have found a node with the same name
// next: the attributes must match also
found = DOMUtil.compareAttributes((Element)currentProfile, (Element)currentDelta);
}
if (found == false) m++;
}
if (found == true) {
// this is not new
if (preserve == true
&& ((Element)currentDelta).hasAttributeNS(SessionConstants.SESSION_NAMESPACE_URI, "preserve")
&& ((Element)currentDelta).getAttributeNS(SessionConstants.SESSION_NAMESPACE_URI, "preserve").equalsIgnoreCase("true")) {
// replace the original with the delta
profile.replaceChild(profile.getOwnerDocument().importNode(currentDelta, true),
currentProfile);
} else {
// do we have elements as children or text?
if (currentDelta.hasChildNodes() == true) {
currentDelta.normalize();
currentProfile.normalize();
// do a recursive call for sub elements
this.importNode(currentProfile, currentDelta, preserve);
// and now the text nodes: Remove all from the profile and add all
// of the delta
NodeList childs = currentProfile.getChildNodes();
int index, max;
max = childs.getLength();
for(index = max - 1; index >= 0; index--) {
if (childs.item(index).getNodeType() == Node.TEXT_NODE) {
currentProfile.removeChild(childs.item(index));
}
}
childs = currentDelta.getChildNodes();
max = childs.getLength();
for(index = 0; index < max; index++) {
if (childs.item(index).getNodeType() == Node.TEXT_NODE) {
currentProfile.appendChild(currentProfile.getOwnerDocument()
.createTextNode(childs.item(index).getNodeValue()));
}
}
}
}
} else {
profile.appendChild(profile.getOwnerDocument().importNode(currentDelta, true));
}
}
}
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.context = context;
}
}