blob: dd17f8ac4a215ab577e89a441533ac0fe8da0700 [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.portal.components;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.avalon.excalibur.pool.Recyclable;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.Recomposable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
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.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.components.sax.XMLDeserializer;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.environment.CocoonRunnable;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.webapps.authentication.AuthenticationManager;
import org.apache.cocoon.webapps.authentication.user.RequestState;
import org.apache.cocoon.webapps.portal.PortalConstants;
import org.apache.cocoon.webapps.session.ContextManager;
import org.apache.cocoon.webapps.session.MediaManager;
import org.apache.cocoon.webapps.session.SessionManager;
import org.apache.cocoon.webapps.session.TransactionManager;
import org.apache.cocoon.webapps.session.context.SessionContext;
import org.apache.cocoon.webapps.session.xml.XMLUtil;
import org.apache.cocoon.xml.IncludeXMLConsumer;
import org.apache.cocoon.xml.XMLConsumer;
import org.apache.cocoon.xml.XMLUtils;
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.store.Store;
import org.apache.excalibur.xml.xpath.XPathProcessor;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This is the basis portal component
*
* @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
* @version CVS $Id$
*/
public final class PortalManagerImpl
extends AbstractLogEnabled
implements Disposable, Composable, Recomposable, Recyclable, Contextualizable, Component, PortalManager {
/** The cache (store) for the profiles */
private Store profileStore;
/** The authenticationManager */
private AuthenticationManager authenticationManager;
/** The media manager */
private MediaManager mediaManager;
/** The XPath Processor */
private XPathProcessor xpathProcessor;
/** The session manager */
private SessionManager sessionManager;
/** The Context manager */
private ContextManager contextManager;
/** The transaction manager */
private TransactionManager transactionManager;
/** The component manager */
protected ComponentManager manager;
/** The current source resolver */
protected SourceResolver resolver;
/** The context */
protected Context componentContext;
/** Are we already setup for this request? */
protected boolean initialized = false;
/* (non-Javadoc)
* @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
*/
public void recycle() {
if (this.manager != null) {
this.manager.release(this.profileStore);
this.manager.release( (Component)this.authenticationManager);
this.manager.release( (Component)this.mediaManager);
this.manager.release( (Component)this.sessionManager);
this.manager.release( (Component)this.contextManager);
this.manager.release( (Component)this.transactionManager);
this.profileStore = null;
this.authenticationManager = null;
this.mediaManager = null;
this.transactionManager = null;
this.sessionManager = null;
this.contextManager = null;
}
this.initialized = false;
}
/**
* Get the current authentication state
*/
protected RequestState getRequestState() {
AuthenticationManager authManager = null;
try {
authManager = (AuthenticationManager)this.manager.lookup(AuthenticationManager.ROLE);
return authManager.getState();
} catch (ComponentException ce) {
// ignore this here
return null;
} finally {
this.manager.release( (Component)authManager );
}
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.component.Composable#compose(org.apache.avalon.framework.component.ComponentManager)
*/
public void compose(ComponentManager manager)
throws ComponentException {
this.manager = manager;
this.resolver = (SourceResolver)manager.lookup(SourceResolver.ROLE);
this.xpathProcessor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE);
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.component.Recomposable#recompose(org.apache.avalon.framework.component.ComponentManager)
*/
public void recompose(ComponentManager manager) throws ComponentException {
this.manager = manager;
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.activity.Disposable#dispose()
*/
public void dispose() {
if ( this.manager != null ) {
this.manager.release( (Component)this.xpathProcessor );
this.xpathProcessor = null;
this.manager.release( (Component)this.resolver );
this.resolver = null;
}
}
/* (non-Javadoc)
* @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
*/
public void contextualize(Context context) throws ContextException {
this.componentContext = context;
}
/**
* Get the profile store
*/
protected Store getProfileStore()
throws ProcessingException {
if (this.profileStore == null) {
try {
this.profileStore = (Store)this.manager.lookup(Store.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of store component.", ce);
}
}
return this.profileStore;
}
/**
* Get the authentication manager
*/
protected AuthenticationManager getAuthenticationManager()
throws ProcessingException {
if (this.authenticationManager == null) {
try {
this.authenticationManager = (AuthenticationManager)this.manager.lookup(AuthenticationManager.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of AuthenticationManager.", ce);
}
}
return this.authenticationManager;
}
/**
* Get the media manager
*/
protected MediaManager getMediaManager()
throws ProcessingException {
if (this.mediaManager == null) {
try {
this.mediaManager = (MediaManager)this.manager.lookup(MediaManager.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of MediaManager.", ce);
}
}
return this.mediaManager;
}
/**
* Setup this component
*/
protected void setup()
throws ProcessingException {
if ( !this.initialized ) {
final Request request = ContextHelper.getRequest(this.componentContext);
if ( request.getAttribute(PortalManager.ROLE) == null ) {
request.setAttribute(PortalManager.ROLE, Boolean.TRUE);
// Get and ignore the configuration
this.getConfiguration();
try {
this.changeProfile();
} catch (SAXException se) {
throw new ProcessingException(se);
} catch (IOException ioe) {
throw new ProcessingException(ioe);
}
}
this.initialized = true;
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#configurationTest()
*/
public void configurationTest()
throws ProcessingException, IOException, SAXException {
// no sync required
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN configurationTest");
}
this.setup();
// Ignore result
this.getConfiguration();
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END configurationTest");
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#getContext(boolean)
*/
public SessionContext getContext(boolean create)
throws ProcessingException, IOException, SAXException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN getContext create="+create);
}
this.setup();
SessionContext context = null;
final Session session = this.getSessionManager().getSession(false);
if (session != null) {
synchronized(session) {
String appName = this.getRequestState().getApplicationName();
String attrName = PortalConstants.PRIVATE_SESSION_CONTEXT_NAME;
if (appName != null) {
attrName = attrName + ':' + appName;
}
context = this.getContextManager().getContext(attrName);
if (context == null && create) {
// create new context
context = this.getAuthenticationManager().createApplicationContext(attrName, null, null);
}
} // end synchronized
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END getContext context="+context);
}
return context;
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#streamConfiguration(org.apache.cocoon.xml.XMLConsumer, java.lang.String, java.lang.String, java.lang.String, java.lang.String)
*/
public void streamConfiguration(XMLConsumer consumer,
String requestURI,
String profileID,
String media,
String contextID)
throws IOException, SAXException, ProcessingException {
// synchronized not req.
this.setup();
Response response = ContextHelper.getResponse(this.componentContext);
XMLUtils.startElement(consumer, PortalConstants.ELEMENT_CONFIGURATION);
// set the portal-page uri:
StringBuffer buffer = new StringBuffer(requestURI);
buffer.append((requestURI.indexOf('?') == -1 ? '?' : '&'))
.append(PortalManagerImpl.REQ_PARAMETER_PROFILE)
.append('=')
.append(profileID);
String uri = response.encodeURL(buffer.toString());
XMLUtils.startElement(consumer, "uri");
XMLUtils.data(consumer, uri);
XMLUtils.endElement(consumer, "uri");
Map config = this.getConfiguration();
String portalURI = response.encodeURL((String)config.get(PortalConstants.CONF_PORTAL_URI));
XMLUtils.startElement(consumer, "portal");
XMLUtils.data(consumer, portalURI);
XMLUtils.endElement(consumer, "portal");
XMLUtils.startElement(consumer, PortalConstants.ELEMENT_PROFILE);
XMLUtils.data(consumer, profileID);
XMLUtils.endElement(consumer, PortalConstants.ELEMENT_PROFILE);
if (media != null) {
XMLUtils.startElement(consumer, "media");
XMLUtils.data(consumer, media);
XMLUtils.endElement(consumer, "media");
}
if (contextID != null) {
XMLUtils.startElement(consumer, "context");
XMLUtils.data(consumer, contextID);
XMLUtils.endElement(consumer, "context");
}
XMLUtils.endElement(consumer, PortalConstants.ELEMENT_CONFIGURATION);
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#showAdminConf(org.apache.cocoon.xml.XMLConsumer)
*/
public void showAdminConf(XMLConsumer consumer)
throws SAXException, ProcessingException, IOException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN showAdminConf consumer=" + consumer);
}
this.setup();
Request request = ContextHelper.getRequest(this.componentContext);
try {
String profileID = "global";
String copletID = request.getParameter(PortalManagerImpl.REQ_PARAMETER_COPLET);
SessionContext context = this.getContext(true);
Map configuration = this.getConfiguration();
DocumentFragment copletsFragment = (DocumentFragment)context.getAttribute(ATTRIBUTE_ADMIN_COPLETS);
String command = request.getParameter(PortalManagerImpl.REQ_PARAMETER_ADMIN_COPLETS);
if (command != null && copletsFragment != null) {
try {
this.getTransactionManager().startWritingTransaction(context);
// save : save coplets base
// new : new coplet
// delete : use id to delete coplet
// change : change the coplet
// cache : cleans the cache
if (command.equals("delete") && copletID != null) {
Node coplet = DOMUtil.getSingleNode(copletsFragment, "coplets-profile/coplets/coplet[@id='"+copletID+"']", this.xpathProcessor);
if (coplet != null) {
coplet.getParentNode().removeChild(coplet);
}
} else if (command.equals("change") && copletID != null) {
Node coplet = DOMUtil.getSingleNode(copletsFragment, "coplets-profile/coplets/coplet[@id='"+copletID+"']", this.xpathProcessor);
if (coplet != null) {
// now get the information
String value;
value = request.getParameter("portaladmin_title");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.getSingleNode(coplet, "title", this.xpathProcessor), value);
value = request.getParameter("portaladmin_mand");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.getSingleNode(coplet, "configuration/mandatory", this.xpathProcessor), value);
value = request.getParameter("portaladmin_sizable");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.getSingleNode(coplet, "configuration/sizable", this.xpathProcessor), value);
value = request.getParameter("portaladmin_active");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.getSingleNode(coplet, "configuration/active", this.xpathProcessor), value);
value = request.getParameter("portaladmin_handsize");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/handlesSizable", this.xpathProcessor), value);
value = request.getParameter("portaladmin_handpar");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/handlesParameters", this.xpathProcessor), value);
value = request.getParameter("portaladmin_timeout");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/timeout", this.xpathProcessor), value);
value = request.getParameter("portaladmin_customizable");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/customizable", this.xpathProcessor), value);
value = request.getParameter("portaladmin_persistent");
if (value != null) DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/persistent", this.xpathProcessor), value);
String resource = request.getParameter("portaladmin_resource");
if (resource != null) {
Element resourceNode = (Element)DOMUtil.getSingleNode(coplet, "resource", this.xpathProcessor);
resourceNode.getParentNode().removeChild(resourceNode);
resourceNode = coplet.getOwnerDocument().createElementNS(null, "resource");
resourceNode.setAttributeNS(null, "uri", resource);
coplet.appendChild(resourceNode);
}
resource = request.getParameter("portaladmin_cust");
boolean isCustom = DOMUtil.getValueAsBooleanOf(coplet, "configuration/customizable", false, this.xpathProcessor);
if (resource != null && isCustom ) {
Element resourceNode = (Element)DOMUtil.getSingleNode(coplet, "customization", this.xpathProcessor);
if (resourceNode != null) resourceNode.getParentNode().removeChild(resourceNode);
resourceNode = coplet.getOwnerDocument().createElementNS(null, "customization");
resourceNode.setAttributeNS(null, "uri", resource);
coplet.appendChild(resourceNode);
}
if (!isCustom) {
Element resourceNode = (Element)DOMUtil.getSingleNode(coplet, "customization", this.xpathProcessor);
if (resourceNode != null) resourceNode.getParentNode().removeChild(resourceNode);
}
// transformations
value = request.getParameter("portaladmin_newxsl");
if (value != null) {
Element tNode = (Element)DOMUtil.selectSingleNode(coplet, "transformation", this.xpathProcessor);
Element sNode = tNode.getOwnerDocument().createElementNS(null, "stylesheet");
tNode.appendChild(sNode);
sNode.appendChild(sNode.getOwnerDocument().createTextNode(value));
}
// now get all transformation stylesheets, mark
// all stylesheets which should be deleted with
// an attribute delete
Enumeration keys = request.getParameterNames();
Element sNode;
String key;
while (keys.hasMoreElements() ) {
key = (String)keys.nextElement();
if (key.startsWith("portaladmin_xsl_") ) {
value = key.substring(key.lastIndexOf('_')+ 1);
sNode = (Element)DOMUtil.getSingleNode(coplet, "transformation/stylesheet[position()="+value+"]", this.xpathProcessor);
if (sNode != null) {
String xslName = request.getParameter(key);
if (xslName.equals("true") ) xslName = "**STYLESHEET**";
DOMUtil.setValueOfNode(sNode, xslName);
}
} else if (key.startsWith("portaladmin_delxsl_") ) {
value = key.substring(key.lastIndexOf('_')+ 1);
sNode = (Element)DOMUtil.getSingleNode(coplet, "transformation/stylesheet[position()="+value+"]", this.xpathProcessor);
if (sNode != null) {
sNode.setAttributeNS(null, "delete", "true");
}
}
}
NodeList delete = DOMUtil.selectNodeList(coplet, "transformation/stylesheet[@delete]", this.xpathProcessor);
if (delete != null) {
for(int i=0; i < delete.getLength(); i++) {
delete.item(i).getParentNode().removeChild(delete.item(i));
}
}
}
} else if (command.equals("new") ) {
// first we have to invent a new coplet id!
int index = 0;
boolean found = false;
Element coplet;
Element subNode;
while (!found) {
copletID = "S"+index;
coplet = (Element)DOMUtil.getSingleNode(copletsFragment, "coplets-profile/coplets/coplet[@id='"+copletID+"']", this.xpathProcessor);
if (coplet == null) {
found = true;
} else {
index++;
}
}
coplet = copletsFragment.getOwnerDocument().createElementNS(null, "coplet");
coplet.setAttributeNS(null, "id", copletID);
subNode = coplet.getOwnerDocument().createElementNS(null, "resource");
coplet.appendChild(subNode);
subNode.setAttributeNS(null, "uri", "uri_in_sitemap");
String title = request.getParameter("portaladmin_title");
if (title == null || title.trim().length() == 0) title = "**NEW COPLET**";
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/mandatory", this.xpathProcessor), "false");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/sizable", this.xpathProcessor), "true");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/active", this.xpathProcessor), "false");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/handlesParameters", this.xpathProcessor), "true");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "configuration/handlesSizable", this.xpathProcessor), "false");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "title", this.xpathProcessor), title);
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "status/visible", this.xpathProcessor), "true");
DOMUtil.setValueOfNode(DOMUtil.selectSingleNode(coplet, "status/size", this.xpathProcessor), "max");
DOMUtil.getSingleNode(copletsFragment, "coplets-profile/coplets", this.xpathProcessor).appendChild(coplet);
} else if (command.equals("save") ) {
SourceParameters pars = new SourceParameters();
pars.setSingleParameterValue("profile", "coplet-base");
RequestState state = this.getRequestState();
pars.setSingleParameterValue("application", state.getApplicationName());
pars.setSingleParameterValue("handler", state.getHandlerName());
String saveResource = (String)configuration.get(PortalConstants.CONF_COPLETBASE_SAVE_RESOURCE);
if (saveResource == null) {
throw new ProcessingException("portal: No save resource defined for type coplet-base.");
} else {
SourceUtil.writeDOM(saveResource,
null,
pars,
copletsFragment,
this.resolver,
"xml");
// now the hardest part, clean up the whole cache
this.cleanUpCache(null, null, configuration);
}
}
} finally {
this.getTransactionManager().stopWritingTransaction(context);
}
}
// general commands
if (command != null && command.equals("cleancache") ) {
this.cleanUpCache(null, null, configuration);
}
String state = request.getParameter(PortalManagerImpl.REQ_PARAMETER_STATE);
if (state == null) {
state = (String)context.getAttribute(ATTRIBUTE_ADMIN_STATE, PortalConstants.STATE_MAIN);
}
// now start producing xml:
consumer.startElement("", PortalConstants.ELEMENT_ADMINCONF, PortalConstants.ELEMENT_ADMINCONF, XMLUtils.EMPTY_ATTRIBUTES);
context.setAttribute(ATTRIBUTE_ADMIN_STATE, state);
consumer.startElement("", PortalConstants.ELEMENT_STATE, PortalConstants.ELEMENT_STATE, XMLUtils.EMPTY_ATTRIBUTES);
consumer.characters(state.toCharArray(), 0, state.length());
consumer.endElement("", PortalConstants.ELEMENT_STATE, PortalConstants.ELEMENT_STATE);
if (state.equals(PortalConstants.STATE_MAIN) ) {
Document rolesDF = this.getRoles();
Node roles = null;
if (rolesDF != null) roles = DOMUtil.getSingleNode(rolesDF, "roles", this.xpathProcessor);
IncludeXMLConsumer.includeNode(roles, consumer, consumer);
}
if (state.equals(PortalConstants.STATE_MAIN_ROLE) ) {
Document rolesDF = this.getRoles();
Node roles = null;
if (rolesDF != null) roles = DOMUtil.getSingleNode(rolesDF, "roles", this.xpathProcessor);
IncludeXMLConsumer.includeNode(roles, consumer, consumer);
String role = request.getParameter(PortalManagerImpl.REQ_PARAMETER_ROLE);
if (role == null) {
role = (String)context.getAttribute(ATTRIBUTE_ADMIN_ROLE);
}
context.setAttribute(ATTRIBUTE_ADMIN_ROLE, role);
if (role != null) {
XMLUtils.startElement(consumer, "roleusers");
XMLUtils.startElement(consumer, "name");
XMLUtils.data(consumer, role);
XMLUtils.endElement(consumer, "name");
Document userDF = this.getUsers(role, null);
Node users = null;
if (userDF != null) users = DOMUtil.getSingleNode(userDF, "users", this.xpathProcessor);
IncludeXMLConsumer.includeNode(users, consumer, consumer);
XMLUtils.endElement(consumer, "roleusers");
}
}
if (state.equals(PortalConstants.STATE_GLOBAL)) {
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, true);
Map profile = this.retrieveProfile(profileID);
if (profile == null) {
this.createProfile(context, PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, true);
profile = this.retrieveProfile(profileID);
}
this.showPortal(consumer, true, context, profile, profileID);
}
if (state.equals(PortalConstants.STATE_ROLE) ) {
String role = request.getParameter(PortalManagerImpl.REQ_PARAMETER_ROLE);
if (role == null) {
role = (String)context.getAttribute(ATTRIBUTE_ADMIN_ROLE);
}
context.setAttribute(ATTRIBUTE_ADMIN_ROLE, role);
if (role != null) {
consumer.startElement("", PortalConstants.ELEMENT_ROLE, PortalConstants.ELEMENT_ROLE, XMLUtils.EMPTY_ATTRIBUTES);
consumer.characters(role.toCharArray(), 0, role.length());
consumer.endElement("", PortalConstants.ELEMENT_ROLE, PortalConstants.ELEMENT_ROLE);
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ROLE, role, null, true);
Map profile = this.retrieveProfile(profileID);
if (profile == null) {
this.createProfile(context, PortalManagerImpl.BUILDTYPE_VALUE_ROLE, role, null, true);
profile = this.retrieveProfile(profileID);
}
this.showPortal(consumer, true, context, profile, profileID);
}
}
if (state.equals(PortalConstants.STATE_USER) ) {
String role = request.getParameter(PortalManagerImpl.REQ_PARAMETER_ROLE);
String id = request.getParameter(PortalManagerImpl.REQ_PARAMETER_ID);
if (role == null) {
role = (String)context.getAttribute(ATTRIBUTE_ADMIN_ROLE);
}
if (id == null) {
id = (String)context.getAttribute(ATTRIBUTE_ADMIN_ID);
}
context.setAttribute(ATTRIBUTE_ADMIN_ID, id);
context.setAttribute(ATTRIBUTE_ADMIN_ROLE, role);
if (role != null && id != null) {
consumer.startElement("", PortalConstants.ELEMENT_ROLE, PortalConstants.ELEMENT_ROLE, XMLUtils.EMPTY_ATTRIBUTES);
consumer.characters(role.toCharArray(), 0, role.length());
consumer.endElement("", PortalConstants.ELEMENT_ROLE, PortalConstants.ELEMENT_ROLE);
consumer.startElement("", PortalConstants.ELEMENT_ID, PortalConstants.ELEMENT_ID, XMLUtils.EMPTY_ATTRIBUTES);
consumer.characters(id.toCharArray(), 0, id.length());
consumer.endElement("", PortalConstants.ELEMENT_ID, PortalConstants.ELEMENT_ID);
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID, role, id, true);
Map profile = this.retrieveProfile(profileID);
if (profile == null) {
this.createProfile(context, PortalManagerImpl.BUILDTYPE_VALUE_ID, role, id, true);
profile = this.retrieveProfile(profileID);
}
this.showPortal(consumer, true, context, profile, profileID);
}
}
// one coplet
if (state.equals(PortalConstants.STATE_COPLET) ) {
if (copletsFragment != null && copletID != null) {
Node coplet = DOMUtil.getSingleNode(copletsFragment, "coplets-profile/coplets/coplet[@id='"+copletID+"']", this.xpathProcessor);
if (coplet != null) {
IncludeXMLConsumer.includeNode(coplet, consumer, consumer);
}
} else {
state = PortalConstants.STATE_COPLETS;
}
}
if (state.equals(PortalConstants.STATE_COPLETS) ) {
consumer.startElement("", PortalConstants.ELEMENT_COPLETS, PortalConstants.ELEMENT_COPLETS, XMLUtils.EMPTY_ATTRIBUTES);
// load the base coplets profile
if (copletsFragment == null) {
SourceParameters pars = new SourceParameters();
RequestState reqstate = this.getRequestState();
pars.setSingleParameterValue("application", reqstate.getApplicationName());
String res = (String)configuration.get(PortalConstants.CONF_COPLETBASE_RESOURCE);
if (res == null) {
throw new ProcessingException("No configuration for portal-coplet base profile found.");
}
copletsFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
context.setAttribute(ATTRIBUTE_ADMIN_COPLETS, copletsFragment);
}
IncludeXMLConsumer.includeNode(DOMUtil.selectSingleNode(copletsFragment,
"coplets-profile", this.xpathProcessor), consumer, consumer);
consumer.endElement("", PortalConstants.ELEMENT_COPLETS, PortalConstants.ELEMENT_COPLETS);
}
// configuration
this.streamConfiguration(consumer, request.getRequestURI(), profileID, null, null);
consumer.endElement("", PortalConstants.ELEMENT_ADMINCONF, PortalConstants.ELEMENT_ADMINCONF);
} catch (javax.xml.transform.TransformerException local) {
throw new ProcessingException("TransformerException: " + local, local);
}
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END showAdminConf");
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#getStatusProfile()
*/
public Element getStatusProfile()
throws SAXException, IOException, ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN getStatusProfile");
}
this.setup();
SessionContext context = this.getContext(true);
String profileID = null;
Map storedProfile = null;
Element statusProfile = null;
if (context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE) != null) {
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID,
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE),
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ID), false);
storedProfile = this.retrieveProfile(profileID);
}
if (storedProfile != null) {
DocumentFragment profile = (DocumentFragment)storedProfile.get(PortalConstants.PROFILE_PROFILE);
try {
statusProfile = (Element)DOMUtil.getSingleNode(profile, "profile/status-profile", this.xpathProcessor);
} catch (javax.xml.transform.TransformerException ignore) {
}
}
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END getStatusProfile statusProfile="+(statusProfile == null ? "null" : XMLUtils.serializeNode(statusProfile, XMLUtils.createPropertiesForXML(false))));
}
return statusProfile;
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#showPortal(org.apache.cocoon.xml.XMLConsumer, boolean, boolean)
*/
public void showPortal(XMLConsumer consumer,
boolean configMode,
boolean adminProfile)
throws SAXException, ProcessingException, IOException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN showPortal consumer=" + consumer+", configMode="+
configMode+", adminProfile="+adminProfile);
}
this.setup();
SessionContext context = this.getContext(true);
String profileID = null;
Map storedProfile = null;
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("start portal generation");
}
if (context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE) != null) {
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID,
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE),
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ID), adminProfile);
storedProfile = this.retrieveProfile(profileID);
}
if (storedProfile == null) {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("start building profile");
}
this.createProfile(context, PortalManagerImpl.BUILDTYPE_VALUE_ID, null, null, adminProfile);
// get the profileID
profileID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID,
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE),
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ID), adminProfile);
storedProfile = this.retrieveProfile(profileID);
if (storedProfile == null) {
throw new ProcessingException("portal: No portal profile found.");
}
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("end building profile");
}
}
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("start showing profile");
}
this.showPortal(consumer,
configMode,
context,
storedProfile,
profileID);
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("end showing profile");
this.getLogger().debug("end portal generation");
}
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("END showPortal");
}
}
/**
* Stream all layout information for the current portal
* to the consumer.
* The resulting XML:
* <layout>
* <portal>
* ...
* </portal>
* <coplets>
* ...
* </coplets>
* </layout>
*/
public static void streamLayoutProfile(XMLConsumer consumer,
Map portalLayouts,
Map copletLayouts,
String mediaType)
throws SAXException {
Element element;
NodeList childs;
Attributes attr = new AttributesImpl();
consumer.startElement("", PortalConstants.ELEMENT_LAYOUT, PortalConstants.ELEMENT_LAYOUT, attr);
// first: layout of portal
consumer.startElement("", PortalConstants.ELEMENT_PORTAL, PortalConstants.ELEMENT_PORTAL, attr);
element = (Element)portalLayouts.get(mediaType);
childs = element.getChildNodes();
for(int ci = 0; ci < childs.getLength(); ci++) {
IncludeXMLConsumer.includeNode(childs.item(ci),
consumer,
consumer);
}
consumer.endElement("", PortalConstants.ELEMENT_PORTAL, PortalConstants.ELEMENT_PORTAL);
// second: layout of coplets
consumer.startElement("", PortalConstants.ELEMENT_COPLETS, PortalConstants.ELEMENT_COPLETS, attr);
element = (Element)copletLayouts.get(mediaType);
childs = element.getChildNodes();
for(int ci = 0; ci < childs.getLength(); ci++) {
IncludeXMLConsumer.includeNode(childs.item(ci),
consumer,
consumer);
}
consumer.endElement("", PortalConstants.ELEMENT_COPLETS, PortalConstants.ELEMENT_COPLETS);
consumer.endElement("", PortalConstants.ELEMENT_LAYOUT, PortalConstants.ELEMENT_LAYOUT);
}
/**
* Show the portal.
* The portal is included in the current stream.
*/
private void showPortal(XMLConsumer consumer,
boolean configMode,
SessionContext context,
Map storedProfile,
String profileID)
throws SAXException, ProcessingException, IOException {
// synchronized
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN showPortal consumer=" + consumer+", configMode="+configMode+", context="+context+
", profile="+storedProfile);
}
Request request = ContextHelper.getRequest(this.componentContext);
try {
this.getTransactionManager().startReadingTransaction(context);
DocumentFragment profile;
Map defaultCoplets;
Map mediaCoplets;
Map portalLayouts;
Map copleyLayouts;
Node[] miscNodes;
String mediaType = this.getMediaManager().getMediaType();
profile = (DocumentFragment)storedProfile.get(PortalConstants.PROFILE_PROFILE);
portalLayouts = (Map)storedProfile.get(PortalConstants.PROFILE_PORTAL_LAYOUTS);
copleyLayouts = (Map)storedProfile.get(PortalConstants.PROFILE_COPLET_LAYOUTS);
miscNodes = (Node[])storedProfile.get(PortalConstants.PROFILE_MISC_POINTER);
defaultCoplets = (Map)storedProfile.get(PortalConstants.PROFILE_DEFAULT_COPLETS);
mediaCoplets = (Map)storedProfile.get(PortalConstants.PROFILE_MEDIA_COPLETS);
if (profile == null ||
defaultCoplets == null ||
mediaCoplets == null ||
portalLayouts == null ||
copleyLayouts == null ||
miscNodes == null) {
throw new ProcessingException("portal: No portal profile found.");
}
// get the configuration
Map config = this.getConfiguration();
if (config == null) {
throw new ProcessingException("No configuration for portal found.");
}
boolean processCopletsParallel = false;
long defaultCopletTimeout = 600000;
Boolean boolValue = (Boolean)config.get(PortalConstants.CONF_PARALLEL_COPLETS);
if (boolValue != null) processCopletsParallel = boolValue.booleanValue();
Long longValue = (Long)config.get(PortalConstants.CONF_COPLET_TIMEOUT);
if (longValue != null) defaultCopletTimeout = longValue.longValue();
Element element;
// now start producing xml:
AttributesImpl attr = new AttributesImpl();
if (configMode) {
XMLUtils.startElement(consumer, PortalConstants.ELEMENT_PORTALCONF);
} else {
XMLUtils.startElement(consumer, PortalConstants.ELEMENT_PORTAL);
}
// configuration
this.streamConfiguration(consumer, request.getRequestURI(), profileID, mediaType, null);
// LAYOUT:
if (configMode) {
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","layout-profile"}, false),
consumer, consumer);
// copletsConfiguration (only for configMode)
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","coplets-profile"}, false),
consumer, consumer);
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","type-profile","typedefs"}, false),
consumer, consumer);
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","portal-profile"}, false),
consumer, consumer);
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","personal-profile"}, false),
consumer, consumer);
IncludeXMLConsumer.includeNode(DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","status-profile"}, false),
consumer, consumer);
} else {
PortalManagerImpl.streamLayoutProfile(consumer, portalLayouts, copleyLayouts, mediaType);
}
// END LAYOUT
if (!configMode) {
Element statusProfile = (Element)DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","status-profile"}, false);
String copletNotAvailableMessage = "The coplet is currently not available.";
Node messages = miscNodes[PortalConstants.PROFILE_MISC_MESSAGES_NODE];
if (messages != null) {
messages = DOMUtil.getFirstNodeFromPath(messages, new String[] {"coplet_not_available"}, false);
if (messages != null) copletNotAvailableMessage = DOMUtil.getValueOfNode(messages,
copletNotAvailableMessage);
}
// LOAD COPLETS
List[] copletContents;
List[] temp = (List[])context.getAttribute(PortalConstants.ATTRIBUTE_COPLET_REPOSITORY);
if (temp != null) {
copletContents = new List[temp.length];
for (int i = 0; i < temp.length; i++) {
if (temp[i] == null) {
copletContents[i] = null;
} else {
copletContents[i] = new ArrayList(temp[i]);
}
}
} else {
copletContents = new List[PortalConstants.MAX_COLUMNS+2];
context.setAttribute(PortalConstants.ATTRIBUTE_COPLET_REPOSITORY, copletContents);
}
if (copletContents[0] == null) {
copletContents[0] = new ArrayList(1);
} else {
copletContents[0].clear();
}
if (copletContents[1] == null) {
copletContents[1] = new ArrayList(1);
} else {
copletContents[1].clear();
}
// test for header
String value;
value = DOMUtil.getValueOfNode(miscNodes[PortalConstants.PROFILE_MISC_HEADER_NODE]);
if (value != null && new Boolean(value).booleanValue()) {
element = (Element)miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE];
if (element != null) {
this.loadCoplets(element,
defaultCoplets,
mediaCoplets,
copletContents[0],
processCopletsParallel,
defaultCopletTimeout,
statusProfile);
}
}
// content
value = DOMUtil.getValueOfNode(miscNodes[PortalConstants.PROFILE_MISC_COLUMNS_NODE]);
// for a simpler XSL-Stylesheet: The columns must be inserted in the
// correct order!!!
if (value != null && new Integer(value).intValue() > 0) {
Element columnElement;
int columns = new Integer(value).intValue();
if (columns > PortalConstants.MAX_COLUMNS) {
throw new ProcessingException("portal: Maximum number of columns supported is: "+PortalConstants.MAX_COLUMNS);
}
for(int colindex = 1; colindex <= columns; colindex++) {
if (copletContents[colindex+1] == null) {
copletContents[colindex+1] = new ArrayList(10);
} else {
copletContents[colindex+1].clear();
}
columnElement = (Element)miscNodes[7 + colindex];
element = (Element)DOMUtil.getFirstNodeFromPath(columnElement, new String[] {"coplets"}, false);
if (element != null) {
this.loadCoplets(element,
defaultCoplets,
mediaCoplets,
copletContents[colindex+1],
processCopletsParallel,
defaultCopletTimeout,
statusProfile);
}
}
for(int colindex = columns+2; colindex <= PortalConstants.MAX_COLUMNS+1; colindex++) {
if (copletContents[colindex] != null) {
copletContents[colindex] = null;
}
}
} else {
for(int colindex = 1; colindex <= PortalConstants.MAX_COLUMNS; colindex++) {
if (copletContents[colindex+1] != null) {
copletContents[colindex+1] = null;
}
}
}
// test for footer
value = DOMUtil.getValueOfNode(miscNodes[PortalConstants.PROFILE_MISC_FOOTER_NODE]);
if (value != null && new Boolean(value).booleanValue()) {
element = (Element)miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE];
if (element != null) {
this.loadCoplets(element,
defaultCoplets,
mediaCoplets,
copletContents[1],
processCopletsParallel,
defaultCopletTimeout,
statusProfile);
}
}
// END LOAD COPLETS
// DESIGN
// test for header
if (copletContents[0].size() > 0) {
consumer.startElement("", "header", "header", attr);
this.processCopletList(copletContents[0], consumer, copletNotAvailableMessage, defaultCopletTimeout);
consumer.endElement("", "header", "header");
}
// content
value = DOMUtil.getValueOfNode(miscNodes[PortalConstants.PROFILE_MISC_COLUMNS_NODE]);
// for a simpler XSL-Stylesheet: The columns must be inserted in the
// correct order!!!
if (value != null && new Integer(value).intValue() > 0) {
attr.addAttribute("", "number", "number", "CDATA", value);
XMLUtils.startElement(consumer, "columns", attr);
attr.clear();
int columns = new Integer(value).intValue();
if (columns > PortalConstants.MAX_COLUMNS) {
throw new ProcessingException("portal: Maximum number of columns supported is: "+PortalConstants.MAX_COLUMNS);
}
// determine the width of the columns
String[] width = new String[columns];
int normalWidth = 100 / columns;
Element columnElement;
for(int colindex = 1; colindex <= columns; colindex++) {
columnElement = (Element)miscNodes[7 + colindex];
value = DOMUtil.getValueOf(columnElement, "width", this.xpathProcessor);
if (value == null) {
width[colindex-1] = "" + normalWidth + "%";
} else {
width[colindex-1] = value;
}
}
for(int colindex = 1; colindex <= columns; colindex++) {
attr.addAttribute("", "position", "position", "CDATA", "" + colindex);
attr.addAttribute("", "width", "width", "CDATA", width[colindex-1]);
XMLUtils.startElement(consumer, "column", attr);
attr.clear();
this.processCopletList(copletContents[colindex+1], consumer, copletNotAvailableMessage, defaultCopletTimeout);
XMLUtils.endElement(consumer, "column");
}
XMLUtils.endElement(consumer, "columns");
} else {
attr.addAttribute("", "number", "number", "CDATA", "0");
XMLUtils.startElement(consumer, "columns", attr);
XMLUtils.endElement(consumer, "columns");
attr.clear();
}
// test for footer
if (copletContents[1].size() > 0) {
XMLUtils.startElement(consumer, "footer");
this.processCopletList(copletContents[1], consumer, copletNotAvailableMessage, defaultCopletTimeout);
XMLUtils.endElement(consumer, "footer");
}
// END DESIGN
for(int i=0; i<copletContents.length;i++) {
if (copletContents[i]!=null) copletContents[i].clear();
}
// Personal information and status information
this.sendEvents(consumer, DOMUtil.getFirstNodeFromPath(profile, new String[] {"profile","personal-profile"}, false));
this.sendEvents(consumer, statusProfile);
}
if (configMode) {
XMLUtils.endElement(consumer, PortalConstants.ELEMENT_PORTALCONF);
} else {
XMLUtils.endElement(consumer, PortalConstants.ELEMENT_PORTAL);
}
} catch (javax.xml.transform.TransformerException local) { // end synchronized
throw new ProcessingException("TransformerException: " + local, local);
} finally {
this.getTransactionManager().stopReadingTransaction(context);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END showPortal");
}
}
/**
* Building the profile.
* This includes several steps which are declared in detail inside this method...
*/
protected void buildProfile(String type,
String role,
String id,
boolean adminProfile)
throws ProcessingException, IOException, SAXException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildProfile type=" + type + ", role=" + role + ", id=" +id+", adminProfile="+adminProfile);
}
try {
// check parameter
if (type == null) {
throw new ProcessingException("buildProfile: Type is required");
}
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL) ||
type.equals(PortalManagerImpl.BUILDTYPE_VALUE_BASIC)) {
// nothing to do here
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ROLE)) {
if (role == null) {
throw new ProcessingException("buildProfile: Role is required");
}
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
if (role == null) {
throw new ProcessingException("buildProfile: Role is required");
}
if (id == null) {
throw new ProcessingException("buildProfile: ID is required");
}
} else {
throw new ProcessingException("buildProfile: Type unknown: " + type);
}
SessionContext context = this.getContext(true);
try {
this.getTransactionManager().startWritingTransaction(context);
String profileID = this.getProfileID(type, role, id, adminProfile);
Map theProfile = null;
// get the configuration
Map config = this.getConfiguration();
if (config == null) {
throw new ProcessingException("No configuration for portal found.");
}
// is the ID profile cached?
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID) ) {
theProfile = this.getCachedProfile(profileID, config);
}
if (theProfile == null) {
boolean doBase = false;
boolean doGlobal = false;
boolean doRole = false;
boolean doID = false;
String previousID;
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
doID = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ROLE, role, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
if (theProfile == null) {
doRole = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
if (theProfile == null) {
doGlobal = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_BASIC, null, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
}
}
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ROLE)) {
theProfile = this.getCachedProfile(profileID, config);
if (theProfile == null) {
doRole = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
if (theProfile == null) {
doGlobal = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_BASIC, null, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
}
}
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL)) {
theProfile = this.getCachedProfile(profileID, config);
if (theProfile == null) {
doGlobal = true;
previousID = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_BASIC, null, null, adminProfile);
theProfile = this.getCachedProfile(previousID, config);
}
} else { // basic profile
theProfile = this.getCachedProfile(profileID, config);
}
// build the profile
if (theProfile == null) {
theProfile = new HashMap(8,2);
doBase = true;
}
Element profileRoot;
DocumentFragment profile;
if (doBase) {
// build the base level
profile = this.buildBaseProfile(config, adminProfile);
profileRoot = (Element)profile.getFirstChild();
theProfile.put(PortalConstants.PROFILE_PROFILE, profile);
this.cacheProfile(this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_BASIC, null, null, adminProfile), theProfile, config);
} else {
profile = (DocumentFragment)theProfile.get(PortalConstants.PROFILE_PROFILE);
profileRoot = (Element)profile.getFirstChild();
}
// load the global delta if type is global, role or user (but not basic!)
if (doGlobal) {
this.buildGlobalProfile(profileRoot, config, adminProfile);
this.cacheProfile(this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, adminProfile), theProfile, config);
}
// load the role delta if type is role or user
if (doRole) {
this.buildRoleProfile(profileRoot, config, role, adminProfile);
this.cacheProfile(this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ROLE, role, null, adminProfile), theProfile, config);
}
// load the user delta if type is user
if (doID) {
this.buildUserProfile(profileRoot, config, role, id, adminProfile);
}
// load the status profile when type is user
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
this.buildUserStatusProfile(profileRoot, config, role, id);
}
if (!type.equals(PortalManagerImpl.BUILDTYPE_VALUE_BASIC)) {
this.buildRunProfile(theProfile, context, profile);
theProfile.put(PortalConstants.PROFILE_PORTAL_LAYOUTS,
this.buildPortalLayouts(context, profile));
theProfile.put(PortalConstants.PROFILE_COPLET_LAYOUTS,
this.buildcopleyLayouts(context, profile));
this.buildTypeProfile(theProfile, context, profile);
}
// cache the profile, if user
if (doID) {
this.cacheProfile(profileID, theProfile, config);
}
} else {
// load the status profile when type is user
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
DocumentFragment profile = (DocumentFragment)theProfile.get(PortalConstants.PROFILE_PROFILE);
Element profileRoot = (Element)profile.getFirstChild();
this.buildUserStatusProfile(profileRoot, config, role, id);
}
}
// store the whole profile
this.storeProfile(profileID, theProfile);
// now put role and id into the context if type is ID
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)
&& !adminProfile) {
context.setAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE, role);
context.setAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ID, id);
}
} finally {
this.getTransactionManager().stopWritingTransaction(context);
}// end synchronized
} catch (javax.xml.transform.TransformerException local) {
throw new ProcessingException("TransformerException: " + local, local);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildProfile");
}
}
/**
* Build the profile delta
*/
private DocumentFragment buildProfileDelta(String type,
String role,
String id,
boolean adminProfile)
throws SAXException, ProcessingException, IOException, javax.xml.transform.TransformerException {
// calling method must be synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildProfileDeltaN type="+type+", role="+role+", id="+id);
}
Map originalProfile;
Map baseProfile;
String baseType, baseRole, baseID, rootElementName;
DocumentFragment originalFragment;
DocumentFragment delta;
SessionContext context = this.getContext(true);
originalProfile = this.retrieveProfile(this.getProfileID(type, role, id, adminProfile));
if (originalProfile == null) {
throw new ProcessingException("buildProfileDelta: no profile found for " +
type + " - " + role + " - " + id + ".");
}
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
baseType = PortalManagerImpl.BUILDTYPE_VALUE_ROLE;
baseRole = role;
baseID = null;
rootElementName = "user-delta";
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ROLE)) {
baseType = PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL;
baseRole = null;
baseID = null;
rootElementName = "role-delta";
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL)) {
baseType = PortalManagerImpl.BUILDTYPE_VALUE_BASIC;
baseRole = null;
baseID = null;
rootElementName = "global-delta";
} else {
throw new ProcessingException("buildProfileDelta: type '"+type+"' not allowed.");
}
// the profile is created as we dont want to use any memory representation!
this.createProfile(context, baseType, baseRole, baseID, adminProfile);
baseProfile = this.retrieveProfile(this.getProfileID(baseType, baseRole, baseID, adminProfile));
if (baseProfile == null) {
throw new ProcessingException("buildProfileDelta: no baseProfile found.");
}
originalFragment = (DocumentFragment)originalProfile.get(PortalConstants.PROFILE_PROFILE);
delta = originalFragment.getOwnerDocument().createDocumentFragment();
delta.appendChild(delta.getOwnerDocument().createElementNS(null, rootElementName));
// Copy portal content
Node profileDelta = DOMUtil.getFirstNodeFromPath(originalFragment, new String[] {"profile","portal-profile"}, false).cloneNode(true);
delta.getFirstChild().appendChild(profileDelta);
// Diff layout profile, coplet profile, personal profile but not status profile!
this.diff(originalFragment,
(DocumentFragment)baseProfile.get(PortalConstants.PROFILE_PROFILE),
"profile/layout-profile",
(Element)delta.getFirstChild());
this.diff(originalFragment,
(DocumentFragment)baseProfile.get(PortalConstants.PROFILE_PROFILE),
"profile/coplets-profile",
(Element)delta.getFirstChild());
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL)) {
profileDelta = DOMUtil.getFirstNodeFromPath(originalFragment, new String[] {"profile","personal-profile"}, false).cloneNode(true);
delta.getFirstChild().appendChild(profileDelta);
} else {
this.diff(originalFragment,
(DocumentFragment)baseProfile.get(PortalConstants.PROFILE_PROFILE),
"profile/personal-profile",
(Element)delta.getFirstChild());
}
// check for the highes coplet number
Node[] miscNodes = (Node[])originalProfile.get(PortalConstants.PROFILE_MISC_POINTER);
Element lastCoplet = (Element)miscNodes[PortalConstants.PROFILE_MISC_LAST_COPLET_NODE];
if (lastCoplet != null) {
String lastNumber = lastCoplet.getAttributeNS(null, "number");
if (lastNumber != null) {
int value = new Integer(lastNumber).intValue();
if (value > 1000000) {
NodeList coplets = DOMUtil.selectNodeList(delta, "profile/portal-profile/descendant::coplet[@id and @number]", this.xpathProcessor);
if (coplets != null) {
Element copletNode;
String oldNumber;
String copletId;
Element statusNode;
boolean copletsChanged = false;
for(int i=0; i <coplets.getLength(); i++) {
copletNode = (Element)coplets.item(i);
oldNumber = copletNode.getAttributeNS(null, "number");
copletId = copletNode.getAttributeNS(null, "id");
statusNode = (Element)DOMUtil.getSingleNode(delta, "status-profile/customization/coplet[@id='"+copletId+"' and @number='"+oldNumber+"']", this.xpathProcessor);
copletNode.setAttributeNS(null, "number", ""+(i+1));
if (statusNode != null) {
statusNode.setAttributeNS(null, "number", ""+(i+1));
copletsChanged = true;
}
}
if (copletsChanged) {
this.saveUserStatusProfile(originalProfile,
this.getConfiguration(), role, id);
}
}
}
}
}
// Last part: strip type information
NodeList typeElements = DOMUtil.selectNodeList(delta, "descendant::*[@formpath and @formdescription and @formtype]", this.xpathProcessor);
if (typeElements != null) {
for(int i = 0; i < typeElements.getLength(); i++) {
((Element)typeElements.item(i)).removeAttributeNS(null, "formpath");
((Element)typeElements.item(i)).removeAttributeNS(null, "formdescription");
((Element)typeElements.item(i)).removeAttributeNS(null, "formtype");
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildProfileDelta delta="+delta);
}
return delta;
}
/**
* Make the difference :-)
*/
private void diff(DocumentFragment original,
DocumentFragment base,
String path,
Element deltaElement)
throws SAXException, javax.xml.transform.TransformerException {
// calling method is already synchronized
Element originalRoot = (Element)DOMUtil.getSingleNode(original, path, this.xpathProcessor);
Element baseRoot = (Element)DOMUtil.getSingleNode(base, path, this.xpathProcessor);
if (originalRoot != null && baseRoot != null) {
List nodeStack = new ArrayList();
String name = baseRoot.getNodeName();
name = name.substring(0, name.indexOf("-profile")) + "-delta";
nodeStack.add(originalRoot.getOwnerDocument().createElementNS(null, name));
this.diffNode(baseRoot, originalRoot, nodeStack, deltaElement);
}
}
/**
* Diff one node
*/
private void diffNode(Element baseNode,
Element originalNode,
List nodeStack,
Element deltaElement)
throws SAXException, javax.xml.transform.TransformerException {
// calling method is already synchronized
NodeList baseChilds;
NodeList originalChilds;
int i, len;
int m, l;
boolean found;
Node currentOrigNode = null;
Node currentBaseNode = null;
originalChilds = originalNode.getChildNodes();
len = originalChilds.getLength();
baseChilds = baseNode.getChildNodes();
l = baseChilds.getLength();
for(i = 0; i < len; i++) {
currentOrigNode = originalChilds.item(i);
if (currentOrigNode.getNodeType() == Node.ELEMENT_NODE) {
// search the delta node in the profile
m = 0;
found = false;
while (!found && m < l) {
currentBaseNode = baseChilds.item(m);
if (currentBaseNode.getNodeType() == Node.ELEMENT_NODE
&& currentBaseNode.getNodeName().equals(currentOrigNode.getNodeName()) ) {
// now we have found a node with the same name
// next: the attributes must match also
found = this.compareAttributes(currentBaseNode, currentOrigNode);
}
if (!found) m++;
}
if (found) {
// do we have elements as children or text?
currentOrigNode.normalize();
if (currentOrigNode.hasChildNodes()) {
// do a recursive call for sub elements
nodeStack.add(currentOrigNode);
this.diffNode((Element)currentBaseNode,
(Element)currentOrigNode,
nodeStack,
deltaElement);
// and now compare the text nodes
String baseString = DOMUtil.getValueOfNode(currentBaseNode, "").trim();
String originalString = DOMUtil.getValueOfNode(currentOrigNode, "").trim();
if (!baseString.equals(originalString)) {
// this is the tricky part:
// we have to process all nodes on the stack
// and insert them in the deltaElement
Element currentElement;
Element contextElement = deltaElement;
NodeList possibleChilds;
boolean foundChild;
int cIndex;
for(int p = 0; p < nodeStack.size(); p++) {
currentElement = (Element)nodeStack.get(p);
possibleChilds = DOMUtil.getNodeListFromPath(contextElement, new String[] {currentElement.getNodeName()});
foundChild = false;
cIndex = 0;
if (possibleChilds != null) {
while (!foundChild && cIndex < possibleChilds.getLength()) {
foundChild = this.compareAttributes(currentElement, possibleChilds.item(cIndex));
if (!foundChild) cIndex++;
}
}
if (foundChild) {
contextElement = (Element)possibleChilds.item(cIndex);
} else {
currentElement = (Element)currentElement.cloneNode(false);
contextElement.appendChild(currentElement);
contextElement = currentElement;
}
}
// now add the text
contextElement.appendChild(contextElement.getOwnerDocument().createTextNode(originalString));
}
nodeStack.remove(nodeStack.size()-1);
}
}
}
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#getProfileID(java.lang.String, java.lang.String, java.lang.String, boolean)
*/
public String getProfileID(String type,
String role,
String id,
boolean adminProfile)
throws ProcessingException {
// No sync required
this.setup();
StringBuffer key = new StringBuffer((adminProfile ? "aprofile:" : "uprofile:"));
RequestState reqstate = this.getRequestState();
key.append(reqstate.getHandlerName())
.append('|')
.append(reqstate.getApplicationName())
.append(':')
.append(type);
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ROLE)
|| type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
role = XMLUtil.encode(role);
key.append('_').append(role.length()).append('_').append(role);
}
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
id = XMLUtil.encode(id);
key.append('_').append(id);
}
return key.toString();
}
/**
* Get the profile role from the key
*/
private boolean getIsAdminProfile(String profileID) {
// No sync required
return profileID.startsWith("a");
}
/**
* Get the profile role from the key
*/
private String getRole(String profileID) {
// No sync required
profileID = XMLUtil.decode(profileID);
int pos = profileID.indexOf('_');
if (pos == -1) {
return null;
} else {
String lastPart = profileID.substring(pos+1);
pos = lastPart.indexOf('_');
if (pos == -1) return null;
int len = new Integer(lastPart.substring(0, pos)).intValue();
lastPart = lastPart.substring(pos+1, pos+1+len);
return lastPart;
}
}
/**
* Get the profile ID from the key
*/
private String getID(String profileID) {
// No sync required
profileID = XMLUtil.decode(profileID);
int pos = profileID.indexOf('_');
if (pos == -1) {
return null;
} else {
String lastPart = profileID.substring(pos+1);
pos = lastPart.indexOf('_');
if (pos == -1) {
return null;
} else {
lastPart = lastPart.substring(pos+1);
pos = lastPart.indexOf('_');
if (pos == -1) {
return null;
} else {
return lastPart.substring(pos+1);
}
}
}
}
/**
* Get the profile type from the key
*/
private String getType(String profileID) {
// No sync required
profileID = XMLUtil.decode(profileID);
int endPos = profileID.indexOf('_');
if (endPos == -1) {
int startPos = profileID.lastIndexOf(':');
return profileID.substring(startPos+1);
} else {
int startPos = profileID.lastIndexOf(':', endPos);
return profileID.substring(startPos+1, endPos);
}
}
/**
* Store the profil
*/
private void storeProfile(String profileID,
Map profile)
throws ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN storeProfile id="+profileID+", profile="+profile);
}
Session session = this.getSessionManager().getSession(true);
synchronized(session) {
session.setAttribute(profileID, profile);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END storeProfile");
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#retrieveProfile(java.lang.String)
*/
public Map retrieveProfile(String profileID)
throws ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN retrieveProfile id="+profileID);
}
this.setup();
Session session = this.getSessionManager().getSession(true);
Map result;
synchronized(session) {
result = (Map)session.getAttribute(profileID);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END retrieveProfile profile="+(result != null ? "**PROFILE**" : "null"));
}
return result;
}
/**
* Cache the profile (if cache is turned on)
*/
private void cacheProfile(String profileID,
Map profile,
Map configuration) {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN cacheProfile id="+profileID+", profile="+profile);
}
try {
if (configuration != null && !this.getIsAdminProfile(profileID)) {
String storePrefix = (String)configuration.get(PortalConstants.CONF_PROFILE_CACHE);
if (storePrefix != null) {
String key = profileID.substring(1);
this.getProfileStore().store(key, profile);
}
}
} catch (Exception local) {
this.getLogger().warn("Caching Profile failed.", local);
// local exceptions are ignored
// we dont want to get an exception response due to cache problems
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END cacheProfile");
}
}
/**
* Retrieve the cached profil if available
*/
private Map getCachedProfile(String profileID, Map configuration) {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN getCachedProfile id="+profileID);
}
Map result = null;
try {
if (configuration != null && !this.getIsAdminProfile(profileID)) {
final String storePrefix = (String)configuration.get(PortalConstants.CONF_PROFILE_CACHE);
if (storePrefix != null) {
final String key = profileID.substring(1);
final Store store = this.getProfileStore();
if (store.containsKey(key)) {
result = (Map)store.get(key);
}
}
}
} catch (Exception local) {
// local exceptions are ignored
// we dont want to get an exception response due to cache problems
this.getLogger().warn("Getting cached Profile failed.", local);
result = null;
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END getCachedProfile profile="+(result != null ? "**PROFILE**" : "null"));
}
return result;
}
/**
* Clean up the cache, if the global profile was saved, delete all role and user profiles.
* If a role profile was saved delete all user profiles. If the basic profile was
* saved delete all profiles.
*/
private void cleanUpCache(String type, String role, Map configuration)
throws ProcessingException {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN cleanUpCache type="+type+", role="+role+", config="+configuration);
}
if (configuration != null
&& type != null
&& !type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
String storePrefix = (String)configuration.get(PortalConstants.CONF_PROFILE_CACHE);
if (storePrefix != null) {
Store store = this.getProfileStore();
Enumeration keys = store.keys();
String currentKey;
String deleteGlobal = null;
String deleteRole = null;
String deleteUser = null;
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_BASIC) ||
type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL)) {
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_BASIC)) {
deleteGlobal = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, false).substring(1);
}
deleteRole = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, false);
deleteRole = deleteRole.substring(1, deleteRole.lastIndexOf(':')+1) + PortalManagerImpl.BUILDTYPE_VALUE_ROLE;
deleteUser = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, false);
deleteUser = deleteUser.substring(1, deleteUser.lastIndexOf(':')+1) + PortalManagerImpl.BUILDTYPE_VALUE_ID;
} else { // role
deleteGlobal = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ROLE, role, null, false).substring(1);
deleteUser = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID, role, "a", false);
deleteUser = deleteUser.substring(1, deleteUser.length()-1);
}
while (keys.hasMoreElements()) {
Object k = keys.nextElement();
if ( k instanceof String ) {
currentKey = (String)k;
if (deleteGlobal != null && currentKey.equals(deleteGlobal)) {
store.remove(currentKey);
} else if (deleteRole != null && currentKey.startsWith(deleteRole)) {
store.remove(currentKey);
} else if (deleteUser != null && currentKey.startsWith(deleteUser)) {
store.remove(currentKey);
}
}
}
}
} else if (configuration != null && type == null) {
// clean whole cache
String storePrefix = (String)configuration.get(PortalConstants.CONF_PROFILE_CACHE);
if (storePrefix != null) {
Store store = this.getProfileStore();
Enumeration keys = store.keys();
String currentKey;
String delete;
delete = this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL, null, null, false);
delete = delete.substring(1, delete.lastIndexOf(':') + 1);
while (keys.hasMoreElements()) {
Object k = keys.nextElement();
if ( k instanceof String ) {
currentKey = (String)k;
if (currentKey.startsWith(delete)) {
store.remove(currentKey);
}
}
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END cleanUpCache");
}
}
/**
* Build the run profil and store it in the <code>profileMap</code>.
*/
private void buildRunProfile(Map profileMap,
SessionContext context,
DocumentFragment baseProfile)
throws ProcessingException, javax.xml.transform.TransformerException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildRunProfile context="+context+", profile="+baseProfile);
}
// The map containing the coplets which appear on each medium
Map defaultCoplets = new HashMap(20, 5);
// The map containing for each media type a map with coplets which
// appear only for the given media
Map mediaCoplets = new HashMap(5, 2);
profileMap.put(PortalConstants.PROFILE_DEFAULT_COPLETS, defaultCoplets);
profileMap.put(PortalConstants.PROFILE_MEDIA_COPLETS, mediaCoplets);
// get AuthenticationManager instance
String[] types = this.getMediaManager().getMediaTypes();
Map mediaMap;
for(int i = 0; i < types.length; i++) {
mediaCoplets.put(types[i], new HashMap(5, 3));
}
// build misc nodes
Node[] miscNodes = new Node[13];
miscNodes[PortalConstants.PROFILE_MISC_HEADER_NODE] = DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","layout-profile","portal","header","exists"}, false);
miscNodes[PortalConstants.PROFILE_MISC_FOOTER_NODE] = DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","layout-profile","portal","footer","exists"}, false);
miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE] = DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","portal-profile","content","header"}, false);
miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE] = DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","portal-profile","content","footer"}, false);
miscNodes[PortalConstants.PROFILE_MISC_COLUMNS_NODE]= DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","layout-profile","portal","columns","number"}, false);
miscNodes[PortalConstants.PROFILE_MISC_MESSAGES_NODE]= DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","personal-profile","messages"}, false);
for(int i = 1; i <= PortalConstants.MAX_COLUMNS; i++) {
miscNodes[7 + i] = DOMUtil.getSingleNode(baseProfile,
"profile/portal-profile/content/column[@position='"+i+"']", this.xpathProcessor);
}
profileMap.put(PortalConstants.PROFILE_MISC_POINTER, miscNodes);
// build coplet configs
NodeList coplets;
int i, l;
Element configElement;
String copletID;
String copletMedia;
coplets = DOMUtil.getNodeListFromPath(baseProfile, new String[] {"profile","coplets-profile","coplets","coplet"});
if (coplets != null) {
l = coplets.getLength();
for(i = 0; i < l; i++) {
configElement = (Element)coplets.item(i);
if (DOMUtil.getValueAsBooleanOf(configElement, "configuration/active", this.xpathProcessor)) {
copletID = configElement.getAttributeNS(null, "id");
if (configElement.hasAttributeNS(null, "media")) {
copletMedia = configElement.getAttributeNS(null, "media");
mediaMap = (Map)mediaCoplets.get(copletMedia);
if (mediaMap != null) {
mediaMap.put(copletID, configElement);
}
} else {
copletMedia = null;
defaultCoplets.put(copletID, configElement);
}
// Now: add the coplet if mandatory and missing
if (DOMUtil.getValueAsBooleanOf(configElement, "configuration/mandatory", this.xpathProcessor)) {
// get all coplet instances
NodeList copletElements;
// the next is crap, but it works....
// search all coplets (columns, header, footer)
if (copletMedia == null) {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/column/coplets/coplet[@id='"+copletID+"' and not(@media)]", this.xpathProcessor);
} else {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/column/coplets/coplet[@id='"+copletID+"' and media='"+copletMedia+"']", this.xpathProcessor);
}
if (copletElements == null || copletElements.getLength() == 0) {
if (copletMedia == null) {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/header/coplet[@id='"+copletID+"' and not(@media)]", this.xpathProcessor);
} else {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/header/coplet[@id='"+copletID+"' and media='"+copletMedia+"']", this.xpathProcessor);
}
}
if (copletElements == null || copletElements.getLength() == 0) {
if (copletMedia == null) {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/footer/coplet[@id='"+copletID+"' and not(@media)]", this.xpathProcessor);
} else {
copletElements = DOMUtil.selectNodeList(baseProfile,
"profile/portal-profile/content/footer/coplet[@id='"+copletID+"' and media='"+copletMedia+"']", this.xpathProcessor);
}
}
if (copletElements == null || copletElements.getLength() == 0) {
// mandatory coplet is not configured, so add it to the first column
Node content = DOMUtil.getSingleNode(baseProfile,
"profile/portal-profile/content/column[@position='1']/coplets", this.xpathProcessor);
if (content == null)
throw new ProcessingException("Element not found: portal-profile/content/column/coplets");
Element el = content.getOwnerDocument().createElementNS(null, "coplet");
el.setAttributeNS(null, "id", copletID);
if (copletMedia != null) {
el.setAttributeNS(null, "media", copletMedia);
}
// Set position attribute
NodeList childs = DOMUtil.getNodeListFromPath(content, new String[] {"coplet"});
int childsCount = (childs == null ? 0 : childs.getLength());
el.setAttributeNS(null, "position", ""+(childsCount+1));
Text t;
content.appendChild(el);
content = el;
el = content.getOwnerDocument().createElementNS(null, "status");
content.appendChild(el);
content = el;
el = content.getOwnerDocument().createElementNS(null, "visible");
content.appendChild(el);
content = el;
t = content.getOwnerDocument().createTextNode("true");
content.appendChild(t);
} else {
// is any of them visible?
boolean found;
boolean origVisible = DOMUtil.getValueAsBooleanOf(configElement, "status/visible", this.xpathProcessor);
int si, sl;
sl = copletElements.getLength();
si = 0;
found = false;
while (si < sl && !found) {
found = DOMUtil.getValueAsBooleanOf(copletElements.item(si),
"status/visible", origVisible, this.xpathProcessor);
si++;
}
if (!found) {
// set first to visible
// first: is status node available
Node statusElem = DOMUtil.getFirstNodeFromPath(copletElements.item(0), new String[] {"status"}, false);
if (statusElem == null) {
statusElem = copletElements.item(0).getOwnerDocument().createElementNS(null, "status");
copletElements.item(0).appendChild(statusElem);
}
// second: is visible node available
Node visibleElem = DOMUtil.getFirstNodeFromPath(statusElem, new String[] {"visible"}, false);
if (visibleElem == null) {
visibleElem = statusElem.getOwnerDocument().createElementNS(null, "visible");
statusElem.appendChild(visibleElem);
}
// remove old childs
while (visibleElem.hasChildNodes()) {
visibleElem.removeChild(visibleElem.getFirstChild());
}
visibleElem.appendChild(statusElem.getOwnerDocument().createTextNode("true"));
}
}
}
}
}
}
// Numerate all coplets by adding an attribute number with a unique value
// and put them into the corresponding maps.
// update the status section of the coplet: Only the values of the coplet
// configuration are allowed. Not less and not more!
// All coplets are required to have
// the number attribute! So this is only a compatibility function
// which adds the first time the number to the coplets
// If the number attribute is available, the node with the highest
// number is searched
NodeList copletElements;
int number = 0;
Element content = (Element)DOMUtil.getFirstNodeFromPath(baseProfile,
new String[] {"profile","portal-profile","content"}, false);
Element currentCoplet;
NodeList statusConfigList;
NodeList statusCopletList;
Element statusCopletElement;
int list_index, list_length;
Node currentStatus;
int highestCopletNumber = -1;
for(i = 0; i < 7; i++) {
if (i == 0) {
copletElements = DOMUtil.getNodeListFromPath(content,
new String[] {"header","coplet"});
} else if (i == 1) {
copletElements = DOMUtil.getNodeListFromPath(content,
new String[] {"footer","coplet"});
} else {
copletElements = DOMUtil.selectNodeList(content,
"column[@position='"+(i-1)+"']/coplets/coplet", this.xpathProcessor);
}
if (copletElements != null && copletElements.getLength() > 0) {
Element[] list = new Element[copletElements.getLength()];
for(int index = 0; index < copletElements.getLength(); index++) {
list[index] = (Element)copletElements.item(index);
}
for(int index = 0; index < list.length; index++) {
// get coplet element
currentCoplet = list[index];
String numberValue = currentCoplet.getAttributeNS(null, "number");
if (numberValue == null || numberValue.length() == 0) {
// create unique number attribute
currentCoplet.setAttributeNS(null, "number", ""+number);
miscNodes[PortalConstants.PROFILE_MISC_LAST_COPLET_NODE] = currentCoplet;
number++;
} else {
int currentNumber = new Integer(numberValue).intValue();
if (currentNumber > highestCopletNumber) {
highestCopletNumber = currentNumber;
number = highestCopletNumber+1;
miscNodes[PortalConstants.PROFILE_MISC_LAST_COPLET_NODE] = currentCoplet;
}
}
// update status
configElement = this.getCopletConfiguration(currentCoplet.getAttributeNS(null, "id"),
defaultCoplets,
mediaCoplets);
if (configElement != null) {
statusCopletElement = (Element)DOMUtil.selectSingleNode(configElement, "status", this.xpathProcessor);
statusConfigList = DOMUtil.selectNodeList(statusCopletElement, "*", this.xpathProcessor);
statusCopletList = DOMUtil.selectNodeList(currentCoplet, "status/*", this.xpathProcessor);
// first test if each status is included in the config
if (statusCopletList != null) {
list_length = statusCopletList.getLength();
for(list_index = list_length-1; list_index >= 0; list_index--) {
currentStatus = statusCopletList.item(list_index);
if (currentStatus.getNodeType() == Node.ELEMENT_NODE) {
if (DOMUtil.getFirstNodeFromPath(configElement, new String[] {"status", currentStatus.getNodeName()}, false) == null) {
currentStatus.getParentNode().removeChild(currentStatus);
}
}
}
}
// second, test if each status attribute of the config is included
if (statusConfigList != null) {
list_length = statusConfigList.getLength();
for(list_index = 0; list_index < list_length; list_index++) {
currentStatus = statusConfigList.item(list_index);
if (currentStatus.getNodeType() == Node.ELEMENT_NODE) {
if (DOMUtil.getFirstNodeFromPath(statusCopletElement, new String[] {currentStatus.getNodeName()}, false) == null) {
// create a new element
statusCopletElement.appendChild(statusCopletElement.getOwnerDocument().importNode(currentStatus, true));
}
}
}
}
} else {
// coplet not in configuration
// adopt position of following coplets and then remove
String posAttr = currentCoplet.getAttributeNS(null, "position");
NodeList followUps = DOMUtil.selectNodeList(currentCoplet.getParentNode(), "coplet[@position > '"+posAttr+"']", this.xpathProcessor);
if (followUps != null) {
int value;
for(int iq = 0; iq < followUps.getLength(); iq++) {
value = new Integer(((Element)followUps.item(iq)).getAttributeNS(null, "position")).intValue();
value -= 1;
((Element)followUps.item(iq)).setAttributeNS(null, "position", "" + value);
}
}
currentCoplet.getParentNode().removeChild(currentCoplet);
}
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildRunProfile");
}
}
/**
* Add the type information to the profile and do some type checkings
*/
private void buildTypeProfile(Map theProfile,
SessionContext context,
DocumentFragment baseProfile)
throws javax.xml.transform.TransformerException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildTypeProfile context="+context+", profile="+baseProfile);
}
List list = new ArrayList(25);
List confList = new ArrayList(25);
theProfile.put(PortalConstants.PROFILE_TYPE_PATHS, list);
theProfile.put(PortalConstants.PROFILE_TYPE_CONF_PATHS, confList);
Element typeElement;
typeElement = (Element)DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","type-profile","elements"}, false);
if (typeElement != null) {
if (typeElement.hasChildNodes())
this.addTypePath(list, typeElement.getChildNodes(), "profile");
// now we have the list with the xpaths
this.setTypeInfo(baseProfile, list, null);
// build the conf paths
int i, l, pos;
String current;
l = list.size();
for(i = 0; i < l; i++) {
current = (String)list.get(i);
// now the path has to be changed: the new attributes must be included
pos = current.lastIndexOf('/');
current = current.substring(0, pos);
pos = current.lastIndexOf('[');
if (current.substring(pos+1).equals("not(@*)]")) {
current = current.substring(0, pos+1);
} else {
current = current.substring(0, current.length()-1) + " and ";
}
current += "@formtype and @formpath and @formdescription]";
confList.add(current);
}
}
// and now the type checking part:
//
// If the default layout has changed the number of columns and the current
// user (or role) is not allowed to change this, we have to adjust the
// profile. Otherwise the current number of columns has to be stored
// into the profile layout part.
Element layoutColumnsNode = (Element)DOMUtil.getFirstNodeFromPath(baseProfile, new String[] {"profile","layout-profile","portal","columns","number"}, false);
String layoutValue = DOMUtil.getValueOfNode(layoutColumnsNode);
int layoutColumns = 0;
if (layoutValue != null && new Integer(layoutValue).intValue() > 0) {
layoutColumns = new Integer(layoutValue).intValue();
}
NodeList columnNodes = DOMUtil.selectNodeList(baseProfile, "profile/portal-profile/content/column[@position]", this.xpathProcessor);
int columns = columnNodes.getLength();
if (columns != layoutColumns) {
if (layoutColumnsNode.hasAttributeNS(null, "formtype")) {
DOMUtil.setValueOfNode(layoutColumnsNode, ""+columns);
} else {
this.changeColumns(baseProfile,
columns,
layoutColumns,
(Node[])theProfile.get(PortalConstants.PROFILE_MISC_POINTER));
this.setTypeInfo(baseProfile,
(List)theProfile.get(PortalConstants.PROFILE_TYPE_PATHS),
(List)theProfile.get(PortalConstants.PROFILE_TYPE_CONF_PATHS));
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildTypeProfile");
}
}
/**
* Set the tpe information
*/
private void setTypeInfo(DocumentFragment baseProfile, List paths, List confPaths)
throws javax.xml.transform.TransformerException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN setTypeInfo profile="+baseProfile+", paths="+paths);
}
if (baseProfile != null && paths != null) {
int pos;
String currentPath;
String value;
String description;
NodeList nodes;
int nodes_count;
int path_count = paths.size();
Node currentNode;
for(int i = 0; i < path_count; i++) {
currentPath = (String)paths.get(i);
pos = currentPath.lastIndexOf('/');
value = currentPath.substring(pos + 1);
currentPath = currentPath.substring(0, pos);
pos = value.indexOf("|");
if (pos != -1) {
description = value.substring(pos + 1);
value = value.substring(0, pos);
} else {
description = "UNKNOWN";
}
// get all nodes
boolean changed = false;
nodes = DOMUtil.selectNodeList(baseProfile, currentPath, this.xpathProcessor);
if (nodes != null) {
nodes_count = nodes.getLength();
for(int m = 0; m < nodes_count; m++) {
currentNode = nodes.item(m);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
((Element)currentNode).setAttributeNS(null, "formtype", value);
((Element)currentNode).setAttributeNS(null, "formpath",
PortalManagerImpl.REQ_PARAMETER_CONF + '.' + i + '.' + m);
((Element)currentNode).setAttributeNS(null, "formdescription", description);
changed = true;
}
}
}
if (changed && confPaths != null) {
currentPath = (String)confPaths.get(i);
nodes = DOMUtil.selectNodeList(baseProfile, currentPath, this.xpathProcessor);
if (nodes != null) {
nodes_count = nodes.getLength();
for(int m = 0; m < nodes_count; m++) {
currentNode = nodes.item(m);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
((Element)currentNode).setAttributeNS(null, "formpath",
PortalManagerImpl.REQ_PARAMETER_CONF + '.' + i + '.' + m);
}
}
}
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END setTypeInfo");
}
}
/**
* Add the type info to the xpath. This is done recursevly
*/
private void addTypePath(List list, NodeList childs, String path) {
// calling method is synced
int i, l;
Element current;
StringBuffer newPath;
l = childs.getLength();
for(i = 0; i < l; i++) {
if (childs.item(i).getNodeType() == Node.ELEMENT_NODE) {
current = (Element)childs.item(i);
newPath = new StringBuffer(path);
newPath.append('/').append(current.getNodeName());
if (current.hasAttributes()) {
NamedNodeMap nnm = current.getAttributes();
int ia, la;
boolean first = true;
StringBuffer expression = new StringBuffer();
la = nnm.getLength();
newPath.append('[');
for(ia = 0; ia < la; ia++) {
if (!nnm.item(ia).getNodeName().equals("type")
&& !nnm.item(ia).getNodeName().equals("description")) {
if (!first) expression.append(" and ");
if (!nnm.item(ia).getNodeValue().equals("*")) {
expression.append('@')
.append(nnm.item(ia).getNodeName())
.append("='")
.append(nnm.item(ia).getNodeValue())
.append("'");
} else {
expression.append('@').append(nnm.item(ia).getNodeName());
}
first = false;
}
}
if (first) {
newPath.append("not(@*)");
} else {
newPath.append(expression);
}
newPath.append(']');
} else {
newPath.append("[not(@*)]");
}
if (current.getAttributeNS(null, "type").length() > 0) {
list.add(newPath.toString() + '/' + current.getAttributeNS(null, "type") + '|' + current.getAttributeNS(null, "description"));
} else {
if (current.hasChildNodes()) {
this.addTypePath(list, current.getChildNodes(), newPath.toString());
}
}
}
}
}
/**
* Build the Map with the portal layouts
*/
private Map buildPortalLayouts(SessionContext context,
DocumentFragment baseProfile)
throws ProcessingException, javax.xml.transform.TransformerException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildPortalLayouts context="+context+", profile="+baseProfile);
}
Map layouts = new HashMap(5, 2);
Element defLayout = (Element)DOMUtil.getSingleNode(baseProfile,
"profile/layout-profile/portal/layouts/layout[not(@*)]", this.xpathProcessor);
Node currentLayout;
String[] types = this.getMediaManager().getMediaTypes();
for(int i = 0; i < types.length; i++) {
currentLayout = DOMUtil.getSingleNode(baseProfile,
"profile/layout-profile/portal/layouts/layout[media='"+types[i]+"']", this.xpathProcessor);
layouts.put(types[i], (currentLayout == null ? defLayout : currentLayout));
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildPortalLayouts layouts="+layouts);
}
return layouts;
}
/**
* Build the Map with the coplet layouts
*/
private Map buildcopleyLayouts(SessionContext context,
DocumentFragment baseProfile)
throws ProcessingException, javax.xml.transform.TransformerException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildcopleyLayouts context="+context+", profile="+baseProfile);
}
Map layouts = new HashMap(5, 2);
Element defLayout = (Element)DOMUtil.getSingleNode(baseProfile,
"profile/layout-profile/coplets/layouts/layout[not(@*)]", this.xpathProcessor);
Node currentLayout;
String[] types = this.getMediaManager().getMediaTypes();
for(int i = 0; i < types.length; i++) {
currentLayout = DOMUtil.getSingleNode(baseProfile,
"profile/layout-profile/coplets/layouts/layout[media='"+types[i]+"']", this.xpathProcessor);
layouts.put(types[i], (currentLayout == null ? defLayout : currentLayout));
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildcopleyLayouts layouts="+layouts);
}
return layouts;
}
/**
* Import a delta into the profile
*/
private void importProfileDelta(Element profileRoot,
DocumentFragment delta,
String deltaRootTagName,
String deltaTag)
throws ProcessingException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN importProfileDelta root=" + profileRoot + ", delta=" + delta + ", deltaRoot:" + deltaRootTagName + ", delta: " + deltaTag);
}
Node deltaRoot = null;
deltaRoot = DOMUtil.getFirstNodeFromPath(delta, new String[] {deltaRootTagName, deltaTag}, false);
if (deltaRoot != null) {
// root tag found in delta , now search root tag in profile
String searchName = deltaRoot.getNodeName().substring(0, deltaRoot.getNodeName().lastIndexOf("-delta"));
searchName = searchName + "-profile";
profileRoot = (Element)DOMUtil.getFirstNodeFromPath(profileRoot, new String[] {searchName}, false);
if (profileRoot == null) {
throw new ProcessingException("Importing Delta: Tag " + searchName + " not found in profile.");
}
// now import it
this.importNode(profileRoot, (Element)deltaRoot);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END importProfileDelta");
}
}
/**
* Add the node to the profile (replace an existing one)
*/
private void addProfilePart(Element profileRoot,
DocumentFragment delta,
String deltaRootTagName,
String deltaTag)
{
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN addProfilePart root=" + profileRoot + ", delta=" + delta + ", deltaRoot:" + deltaRootTagName + ", delta: " + deltaTag);
}
Node deltaRoot = null;
Node oldNode = null;
if (deltaRootTagName != null) {
deltaRoot = DOMUtil.getFirstNodeFromPath(delta, new String[] {deltaRootTagName, deltaTag}, false);
} else {
deltaRoot = DOMUtil.getFirstNodeFromPath(delta, new String[] {deltaTag}, false);
}
if (deltaRoot != null) {
// root tag found in delta found, now search root tag in profile
oldNode = DOMUtil.getFirstNodeFromPath(profileRoot, new String[] {deltaTag}, false);
if (oldNode == null) {
profileRoot.appendChild(profileRoot.getOwnerDocument().importNode(deltaRoot, true));
} else {
profileRoot.replaceChild(profileRoot.getOwnerDocument().importNode(deltaRoot, true), oldNode);
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END addProfilePart");
}
}
/**
* This is the hardest part. Incorporting a node into the profile.
* For performance reasons there is now tracing here.
*/
private void importNode(Element profile, Element delta) {
// calling method is synced
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 && m < l) {
currentProfile = profileChilds.item(m);
if (currentProfile.getNodeType() == Node.ELEMENT_NODE
&& currentProfile.getNodeName().equals(currentDelta.getNodeName())) {
// now we have found a node with the same name
// next: the attributes must match also
found = this.compareAttributes(currentProfile, currentDelta);
}
if (!found) m++;
}
if (found) {
// this is not new
// do we have elements as children or text?
if (currentDelta.hasChildNodes()) {
currentDelta.normalize();
currentProfile.normalize();
// do a recursive call for sub elements
this.importNode((Element)currentProfile, (Element)currentDelta);
// 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 {
// this is a new node, so it is considered as an old information
// No inserting: profile.appendChild(profile.getOwnerDocument().importNode(currentDelta, true));
}
}
}
}
/**
* Compare Attributes of two nodes. This method returns true only if both
* nodes have the same number of attributes and the same attributes with equal
* values.
* Namespacedefinition nodes are ignored
* BUT: For type handling the attributes <code>formtype</code>,
* <code>formdescription</code> and <code>formpath</code> are ignored!
*/
private boolean compareAttributes(Node first, Node second) {
// calling method is synced
NamedNodeMap attr1 = first.getAttributes();
NamedNodeMap attr2 = second.getAttributes();
String value;
if (attr1 == null && attr2 == null) return true;
if (attr1 == null || attr2 == null) return false;
int attr1Len = (attr1 == null ? 0 : attr1.getLength());
int attr2Len = (attr2 == null ? 0 : attr2.getLength());
if (attr1Len > 0) {
if (attr1.getNamedItemNS(null, "formtype") != null) attr1Len--;
if (attr1.getNamedItemNS(null, "formpath") != null) attr1Len--;
if (attr1.getNamedItemNS(null, "formdescription") != null) attr1Len--;
int l = attr1.getLength();
for(int i=0;i<l;i++) {
if (attr1.item(i).getNodeName().startsWith("xmlns:"))
attr1Len--;
}
}
if (attr2Len > 0) {
if (attr2.getNamedItemNS(null, "formtype") != null) attr2Len--;
if (attr2.getNamedItemNS(null, "formpath") != null) attr2Len--;
if (attr2.getNamedItemNS(null, "formdescription") != null) attr2Len--;
int l = attr2.getLength();
for(int i=0;i<l;i++) {
if (attr2.item(i).getNodeName().startsWith("xmlns:"))
attr2Len--;
}
}
if (attr1Len != attr2Len) return false;
int i, l;
int m, l2;
i = 0;
l = attr1.getLength();
l2 = attr2.getLength();
boolean ok = true;
// each attribute of first must be in second with the same value
while (i < l && ok) {
value = attr1.item(i).getNodeName();
if (!value.equals("formtype")
&& !value.equals("formpath")
&& !value.equals("formdescription")
&& !value.startsWith("xmlns:")) {
ok = false;
m = 0;
while (m < l2 && !ok) {
if (attr2.item(m).getNodeName().equals(value)) {
// same name, same value?
ok = attr1.item(i).getNodeValue().equals(attr2.item(m).getNodeValue());
}
m++;
}
}
i++;
}
return ok;
}
/**
* Parse the fragment(tree denoted by the element)
* and include the processed xml in the output
*/
private void processCopletList(List copletList,
XMLConsumer consumer,
String copletNotAvailableMessage,
long defaultCopletTimeout)
throws ProcessingException, SAXException, javax.xml.transform.TransformerException {
// calling method is synced
for(int i = 0; i < copletList.size(); i++) {
this.processCoplet((Object[])copletList.get(i),
consumer, copletNotAvailableMessage, defaultCopletTimeout);
}
}
/**
* Parse the fragment(tree denoted by the element)
* and include the processed xml in the output
*/
private void loadCoplets(Element element,
Map defaultCoplets,
Map mediaCoplets,
List copletList,
boolean parallelCoplets,
long defaultCopletTimeout,
Element statusProfile)
throws ProcessingException, javax.xml.transform.TransformerException {
// calling method is synced
// All children, which are coplets are processed, all other tags
// are ignored
if (element.hasChildNodes()) {
NodeList childs = element.getChildNodes();
Node current = null;
int i, l;
l = childs.getLength();
for(i = 0; i < l; i++) {
current = childs.item(i);
if (current.getNodeType() == Node.ELEMENT_NODE
&& current.getNodeName().equals("coplet")) {
// now we have a coplet
this.loadCoplet((Element)current,
defaultCoplets,
mediaCoplets,
copletList,
parallelCoplets,
defaultCopletTimeout,
statusProfile);
}
}
}
}
/**
* Load a coplet and store the binary output in the list
*/
private void loadCoplet(Element element,
Map defaultCoplets,
Map mediaCoplets,
List copletList,
boolean parallelCoplets,
long defaultCopletTimeout,
Element statusProfile)
throws ProcessingException, javax.xml.transform.TransformerException {
// calling method is synced
String copletID = element.getAttributeNS(null, "id");
Element copletConf = this.getCopletConfiguration(copletID, defaultCoplets, mediaCoplets);
if (copletConf != null) {
// first: check visibility
boolean visible = DOMUtil.getValueAsBooleanOf(element,
"status/visible", this.xpathProcessor);
// second: check media
String media = this.getMediaManager().getMediaType();
if (visible && copletConf.hasAttributeNS(null, "media")) {
String copletMedia = copletConf.getAttributeNS(null, "media");
visible = media.equals(copletMedia);
}
if (visible) {
Object[] loadedCoplet = new Object[8];
copletList.add(loadedCoplet);
boolean isCustomizable = DOMUtil.getValueAsBooleanOf(copletConf, "configuration/customizable", false, this.xpathProcessor);
if (isCustomizable) {
boolean showCustomizePage = DOMUtil.getValueAsBooleanOf(element, "status/customize", false, this.xpathProcessor);
boolean hasConfig = false;
if (statusProfile != null) {
Element customInfo = (Element)DOMUtil.getSingleNode(statusProfile,
"customization/coplet[@id='"+copletID+"' and @number='"+element.getAttributeNS(null, "number")+"']", this.xpathProcessor);
hasConfig = (customInfo != null);
}
if (showCustomizePage || !hasConfig ) {
Node node = DOMUtil.selectSingleNode(element, "status/customize", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "true");
} else {
Node node = DOMUtil.selectSingleNode(element, "status/customize", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "false");
}
} else {
Node node = DOMUtil.selectSingleNode(element, "status/customize", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "false");
}
// Create the parameters for the coplet:
// The <status> part is mapped to parameters
// id, number and media are added
SourceParameters p = DOMUtil.createParameters(DOMUtil.getFirstNodeFromPath(element, new String[] {"status"}, false), null);
p.setSingleParameterValue(PortalConstants.PARAMETER_ID, copletID);
p.setSingleParameterValue(PortalConstants.PARAMETER_NUMBER, element.getAttributeNS(null, "number"));
p.setSingleParameterValue(PortalConstants.PARAMETER_MEDIA, media);
String isPersistent = DOMUtil.getValueOf(copletConf, "configuration/persistent", "false", this.xpathProcessor);
p.setSingleParameterValue(PortalConstants.PARAMETER_PERSISTENT, isPersistent);
// the coplet loading is a tricky part:
// we create an object array containing all information
// for later processing of the coplet
// so the processCoplet() method needs no lookup for information
// again
loadedCoplet[0] = null;
loadedCoplet[1] = copletConf;
loadedCoplet[2] = p;
loadedCoplet[3] = element;
loadedCoplet[4] = new Long(System.currentTimeMillis());
loadedCoplet[5] = new Long(DOMUtil.getValueOf(copletConf, "configuration/timeout", "-1", this.xpathProcessor));
loadedCoplet[7] = statusProfile;
CopletThread copletThread = new CopletThread();
Thread theThread = new Thread(new CocoonRunnable(copletThread));
loadedCoplet[6] = copletThread;
copletThread.init(copletID,
ContextHelper.getObjectModel(this.componentContext),
this.getLogger(),
loadedCoplet,
this.manager,
this.resolver,
this.xpathProcessor);
theThread.start();
Thread.yield();
if (!parallelCoplets) {
copletThread = (CopletThread)loadedCoplet[6];
if (copletThread != null) {
long startTime = System.currentTimeMillis() - ((Long)loadedCoplet[4]).longValue();
long timeout = ((Long)loadedCoplet[5]).longValue();
long waitTime;
if (timeout == -1) {
waitTime = defaultCopletTimeout;
} else {
waitTime = timeout - startTime;
}
while (copletThread != null && waitTime > 2) {
try {
Thread.sleep(15);
waitTime -= 15;
} catch(InterruptedException local) {
// ignore
}
copletThread = (CopletThread)loadedCoplet[6];
}
loadedCoplet[6] = null; // mark as loaded
}
}
}
}
}
/**
* Process a coplet which is previously loaded
*/
private void processCoplet(Object[] loadedCoplet,
XMLConsumer consumer,
String notAvailableMessage,
long defaultCopletTimeout)
throws ProcessingException,
SAXException,
javax.xml.transform.TransformerException {
// calling method is synced
Element copletConf = (Element)loadedCoplet[1];
Element element = (Element)loadedCoplet[3];
String copletID = element.getAttributeNS(null, "id");
if (copletConf != null) {
AttributesImpl attr = new AttributesImpl();
attr.addAttribute("", "id", "id", "CDATA", copletID);
attr.addAttribute("", "number", "number", "CDATA", element.getAttributeNS(null, "number"));
attr.addAttribute("", "position", "position", "CDATA", element.getAttributeNS(null, "position"));
consumer.startElement("", "coplet", "coplet", attr);
attr.clear();
// now include all children of the coplet element except status
NodeList children = copletConf.getChildNodes();
if (children != null && children.getLength() > 0) {
int l = children.getLength();
for(int i = 0; i < l; i++) {
if (!children.item(i).getNodeName().equals("status")
&& children.item(i).getNodeType() == Node.ELEMENT_NODE) {
IncludeXMLConsumer.includeNode(children.item(i), consumer, consumer);
}
}
}
// now the status parameter
// SourceParameters p = DOMUtil.createParameters(DOMUtil.getFirstNodeFromPath(element, new String[] {"status"}, false), null);
consumer.startElement("", "status", "status", attr);
children = DOMUtil.selectNodeList(element, "status/*", this.xpathProcessor);
if (children != null && children.getLength() > 0) {
int l = children.getLength();
for(int i = 0; i < l; i++) {
if (children.item(i).getNodeType() == Node.ELEMENT_NODE) {
IncludeXMLConsumer.includeNode(children.item(i), consumer, consumer);
}
}
}
consumer.endElement("", "status", "status");
// now the content:
consumer.startElement("", "content", "content", attr);
CopletThread thread = (CopletThread)loadedCoplet[6];
if (thread != null) {
long startTime = System.currentTimeMillis() - ((Long)loadedCoplet[4]).longValue();
long timeout = ((Long)loadedCoplet[5]).longValue();
long waitTime;
if (timeout == -1) {
waitTime = defaultCopletTimeout;
} else {
waitTime = timeout - startTime;
}
while (thread != null && waitTime > 2) {
try {
Thread.sleep(15);
waitTime -= 15;
} catch(InterruptedException local) {
// ignore
}
thread = (CopletThread)loadedCoplet[6];
}
}
byte[] content = (byte[])loadedCoplet[0];
if (content != null) {
if (content.length > 0) {
XMLDeserializer interpreter = null;
try {
interpreter = (XMLDeserializer)this.manager.lookup(XMLDeserializer.ROLE);
interpreter.setConsumer(new IncludeXMLConsumer(consumer, consumer));
interpreter.deserialize(content);
} catch (ComponentException e) {
throw new ProcessingException("Component for XMLDeserializer not found." + e, e);
} finally {
if (interpreter != null) this.manager.release(interpreter);
}
}
} else {
notAvailableMessage = DOMUtil.getValueOf(copletConf,
"configuration/messages/coplet_not_available", notAvailableMessage, this.xpathProcessor);
consumer.characters(notAvailableMessage.toCharArray(), 0, notAvailableMessage.length());
}
consumer.endElement("", "content", "content");
consumer.endElement("", "coplet", "coplet");
}
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#getMediaType()
*/
public String getMediaType()
throws ProcessingException {
this.setup();
return this.getMediaManager().getMediaType();
}
/**
* Get the coplet with the id
*/
private Element getCopletConfiguration(String copletID,
Map defaultCoplets,
Map mediaCoplets)
throws ProcessingException {
// calling method is synced
String media = this.getMediaManager().getMediaType();
Map coplets = (Map)mediaCoplets.get(media);
Element coplet = null;
if (coplets != null) coplet = (Element)coplets.get(copletID);
if (coplet == null) coplet = (Element)defaultCoplets.get(copletID);
return coplet;
}
/**
* Get the coplet Element
*/
private Element getCopletElement(String copletID,
String copletNr,
Node[] miscNodes)
throws javax.xml.transform.TransformerException {
// calling method is synced
Element node = null;
// first test content, then header and then footer
int colindex = 8;
while (node == null && colindex < 13) {
if (miscNodes[colindex] != null) {
node = (Element)DOMUtil.getSingleNode(miscNodes[colindex],
"coplets/coplet[@id='"+copletID+"' and @number='"+copletNr+"']", this.xpathProcessor);
colindex++;
} else {
colindex = 13;
}
}
if (node == null && miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE] != null) {
node = (Element)DOMUtil.getSingleNode(miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE],
"coplet[@id='"+copletID+"' and @number='"+copletNr+"']", this.xpathProcessor);
}
if (node == null && miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE] != null) {
node = (Element)DOMUtil.getSingleNode(miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE],
"coplet[@id='"+copletID+"' and @number='"+copletNr+"']", this.xpathProcessor);
}
return node;
}
/**
* Modify the coplet.
* This method returns true if the type informations must be recalculated
*/
private boolean modifyCoplet(String requestString,
SessionContext context,
Map theProfile,
DocumentFragment profile)
throws ProcessingException, javax.xml.transform.TransformerException {
// synchronized as the caller is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN modifyCoplet request=" + requestString);
}
boolean result = false;
int pos, pos2;
pos = requestString.indexOf('_');
pos2 = requestString.indexOf('_', pos+1);
if (pos != -1 && pos2 != -1) {
Element coplet = null;
String copletID;
String copletNr;
String argument = null;
copletID = requestString.substring(pos+1,pos2);
copletNr = requestString.substring(pos2+1);
pos = copletNr.indexOf('_');
if (pos != -1) {
argument = copletNr.substring(pos+1);
copletNr = copletNr.substring(0, pos);
}
// create a new coplet: in the given column, header or footer
if (requestString.startsWith(PortalManagerImpl.REQ_CMD_NEW)
&& this.isCopletAvailable(context, copletID,
(Map)theProfile.get(PortalConstants.PROFILE_DEFAULT_COPLETS),
(Map)theProfile.get(PortalConstants.PROFILE_MEDIA_COPLETS))) {
Node[] miscNodes = (Node[])theProfile.get(PortalConstants.PROFILE_MISC_POINTER);
// determine the coplet number
Node lastCoplet = miscNodes[PortalConstants.PROFILE_MISC_LAST_COPLET_NODE];
String lastNumber = null;
if (lastCoplet != null) {
lastNumber = ((Element)lastCoplet).getAttributeNS(null, "number");
if (lastNumber != null) {
int value = new Integer(lastNumber).intValue();
value++;
lastNumber = ""+value;
}
}
if (lastNumber == null) lastNumber = "0";
Node copletsNode;
if (copletNr.equals("header")) {
copletsNode = miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE];
if (copletsNode == null) {
copletsNode = DOMUtil.selectSingleNode(profile, "profile/portal-profile/content/header", this.xpathProcessor);
miscNodes[PortalConstants.PROFILE_MISC_HEADER_CONTENT_NODE] = copletsNode;
} else { // remove old coplet
Node oldCoplet = DOMUtil.getFirstNodeFromPath(copletsNode, new String[] {"coplet"}, false);
if (oldCoplet != null) copletsNode.removeChild(oldCoplet);
}
} else if (copletNr.equals("footer")) {
copletsNode = miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE];
if (copletsNode == null) {
copletsNode = DOMUtil.selectSingleNode(profile, "profile/portal-profile/content/footer", this.xpathProcessor);
miscNodes[PortalConstants.PROFILE_MISC_FOOTER_CONTENT_NODE] = copletsNode;
} else { // remove old coplet
Node oldCoplet = DOMUtil.getFirstNodeFromPath(copletsNode, new String[] {"coplet"}, false);
if (oldCoplet != null) copletsNode.removeChild(oldCoplet);
}
} else {
Node columnNode = miscNodes[7+new Integer(copletNr).intValue()];
copletsNode = DOMUtil.getFirstNodeFromPath(columnNode, new String[] {"coplets"}, false);
}
Element copletNode;
Document doc = copletsNode.getOwnerDocument();
copletNode = doc.createElementNS(null, "coplet");
copletsNode.appendChild(copletNode);
copletNode.setAttributeNS(null, "id", copletID);
copletNode.setAttributeNS(null, "number", lastNumber);
// set position
NodeList childs = DOMUtil.getNodeListFromPath(copletsNode, new String[] {"coplet"});
int childsCount = (childs == null ? 0 : childs.getLength());
copletNode.setAttributeNS(null, "position", ""+(childsCount));
miscNodes[PortalConstants.PROFILE_MISC_LAST_COPLET_NODE] = copletNode;
// copy status
Element configElement = this.getCopletConfiguration(copletID,
(Map)theProfile.get(PortalConstants.PROFILE_DEFAULT_COPLETS),
(Map)theProfile.get(PortalConstants.PROFILE_MEDIA_COPLETS));
Element configStatus = (Element)DOMUtil.getFirstNodeFromPath(configElement, new String[] {"status"}, false);
copletNode.appendChild(configStatus.cloneNode(true));
// clear type information for each status
Element status = (Element)copletNode.getElementsByTagName("status").item(0);
NodeList parameters = status.getChildNodes();
Node current;
Element statusNode;
if (parameters != null) {
for(int i = 0; i < parameters.getLength(); i++) {
current = parameters.item(i);
if (current.getNodeType() == Node.ELEMENT_NODE) {
statusNode = (Element)current;
if (statusNode.hasAttributeNS(null, "formpath"))
statusNode.removeAttributeNS(null, "formpath");
if (statusNode.hasAttributeNS(null, "formtype"))
statusNode.removeAttributeNS(null, "formtype");
if (statusNode.hasAttributeNS(null, "formdescription"))
statusNode.removeAttributeNS(null, "formdescription");
}
}
}
result = true;
} else {
coplet = this.getCopletElement(copletID,
copletNr,
(Node[])theProfile.get(PortalConstants.PROFILE_MISC_POINTER));
if (coplet != null) {
if (requestString.startsWith(PortalManagerImpl.REQ_CMD_CLOSE) ||
requestString.startsWith(PortalManagerImpl.REQ_CMD_HIDE)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/visible", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "false");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_OPEN) ||
requestString.startsWith(PortalManagerImpl.REQ_CMD_SHOW)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/visible", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "true");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_MINIMIZE)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/size", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "min");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_MAXIMIZE)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/size", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "max");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_CUSTOMIZE)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/customize", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "true");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_UPDATE)) {
Node node = DOMUtil.selectSingleNode(coplet, "status/customize", this.xpathProcessor);
DOMUtil.setValueOfNode(node, "false");
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_DELETE)) {
// delete the status of the coplet
Node statusNode = DOMUtil.getSingleNode(profile,
"profile/status-profile/customization/coplet[@id='"+copletID+"' and @number='"+copletNr+"']", this.xpathProcessor);
if (statusNode != null) {
statusNode.getParentNode().removeChild(statusNode);
Element configElement = this.getCopletConfiguration(copletID,
(Map)theProfile.get(PortalConstants.PROFILE_DEFAULT_COPLETS),
(Map)theProfile.get(PortalConstants.PROFILE_MEDIA_COPLETS));
boolean isPersistent = DOMUtil.getValueAsBooleanOf(configElement, "configuration/persistent", false, this.xpathProcessor);
if (isPersistent) {
// mark the status profile to be saved
theProfile.put(PortalConstants.PROFILE_SAVE_STATUS_FLAG, "true");
}
}
String posAttr = coplet.getAttributeNS(null, "position");
NodeList followUps = DOMUtil.selectNodeList(coplet.getParentNode(), "coplet[@position > '"+posAttr+"']", this.xpathProcessor);
coplet.getParentNode().removeChild(coplet);
coplet = null;
if (followUps != null) {
int value;
for(int i = 0; i < followUps.getLength(); i++) {
value = new Integer(((Element)followUps.item(i)).getAttributeNS(null, "position")).intValue();
value -= 1;
((Element)followUps.item(i)).setAttributeNS(null, "position", "" + value);
}
}
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_MOVE)) {
if (argument != null) {
Element copletsElement = (Element)DOMUtil.getSingleNode(profile,
"profile/portal-profile/content/column[@position='"+argument+"']/coplets", this.xpathProcessor);
if (copletsElement != null) {
if (!coplet.getParentNode().equals(copletsElement)) {
String posAttr = coplet.getAttributeNS(null, "position");
NodeList followUps = DOMUtil.selectNodeList(coplet.getParentNode(), "coplet[@position > '"+posAttr+"']", this.xpathProcessor);
coplet.getParentNode().removeChild(coplet);
// set position attribute
NodeList childs = DOMUtil.getNodeListFromPath(copletsElement, new String[] {"coplet"});
int childsCount = (childs == null ? 0 : childs.getLength());
coplet.setAttributeNS(null, "position", "" + (childsCount + 1));
copletsElement.appendChild(coplet);
if (followUps != null) {
int value;
for(int i = 0; i < followUps.getLength(); i++) {
value = new Integer(((Element)followUps.item(i)).getAttributeNS(null, "position")).intValue();
value -= 1;
((Element)followUps.item(i)).setAttributeNS(null, "position", "" + value);
}
}
}
}
}
} else if (requestString.startsWith(PortalManagerImpl.REQ_CMD_MOVEROW)) {
if (argument != null) {
Element newCoplet = (Element)DOMUtil.getSingleNode(coplet.getParentNode(),
"coplet[@position='"+argument+"']", this.xpathProcessor);
if (newCoplet != null) {
String position = coplet.getAttributeNS(null, "position");
coplet.removeAttributeNS(null, "position");
coplet.setAttributeNS(null, "position", argument);
newCoplet.removeAttributeNS(null, "position");
newCoplet.setAttributeNS(null, "position", position);
}
}
}
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END modifyCoplet calculate="+result);
}
return result;
}
/**
* Check if the coplet is available for the current logged in user
* If the user is not logged in, this returns false.
* First the default coplets are searched. If none is found then
* the coplets for each media are searched.
*/
private boolean isCopletAvailable(SessionContext context,
String copletID,
Map defaultCoplets,
Map mediaCoplets)
{
// no sync required
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN isCopletAvailable coplet="+copletID);
}
boolean result = false;
if (context != null) {
result = defaultCoplets.containsKey(copletID);
if (!result) {
Iterator iter = mediaCoplets.values().iterator();
while (!result && iter.hasNext()) {
result = ((Map)iter.next()).containsKey(copletID);
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END isCopletAvailable result=" + result);
}
return result;
}
/* (non-Javadoc)
* @see org.apache.cocoon.webapps.portal.components.PortalManager#checkAuthentication(org.apache.cocoon.environment.Redirector, java.lang.String)
*/
public boolean checkAuthentication(Redirector redirector, String copletID)
throws SAXException, IOException, ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN checkAuthentication coplet="+copletID);
}
this.setup();
boolean result = false;
SessionContext context = this.getContext(false);
if (context != null
&& context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE) != null) {
try {
this.getTransactionManager().startReadingTransaction(context);
Map theProfile = this.retrieveProfile(this.getProfileID(PortalManagerImpl.BUILDTYPE_VALUE_ID,
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ROLE),
(String)context.getAttribute(PortalManagerImpl.ATTRIBUTE_PORTAL_ID), false));
if (theProfile != null) {
if (copletID == null || copletID.trim().length() == 0) {
result = true;
} else {
result = this.isCopletAvailable(context,
copletID,
(Map)theProfile.get(PortalConstants.PROFILE_DEFAULT_COPLETS),
(Map)theProfile.get(PortalConstants.PROFILE_MEDIA_COPLETS));
}
}
} finally {
this.getTransactionManager().stopReadingTransaction(context);
} // end synced
}
if (!result) {
Map config = this.getConfiguration();
if (config != null) {
String redirectURI = (String)config.get(PortalConstants.CONF_AUTH_REDIRECT);
if (redirectURI == null) {
redirectURI = (String)config.get(PortalConstants.CONF_PORTAL_URI);
}
if (redirectURI != null) {
redirector.globalRedirect( false, redirectURI );
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END checkAuthentication result=" + result);
}
return result;
}
/**
* Get the configuration. This configuration is an authentication application configuration
* for the current application with the name "portal".
* The first time this configuration is build it is stored in the session
* so later requests get the cached result.
*/
private Map getConfiguration()
throws ProcessingException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN getConfiguration");
}
Map result = null;
RequestState reqstate = this.getRequestState();
String appName = reqstate.getApplicationName();
String handlerName = reqstate.getHandlerName();
Session session = this.getSessionManager().getSession(false);
if (session != null && appName != null && handlerName != null) {
synchronized (session) {
result = (Map)session.getAttribute(PortalConstants.ATTRIBUTE_CONFIGURATION + handlerName + ':' + appName);
if (result == null) {
try {
Configuration config;
Configuration conf = reqstate.getModuleConfiguration(PortalConstants.AUTHENTICATION_MODULE_NAME);
if (conf == null) {
throw new ProcessingException("portal: Configuration for application '" + appName + "' not found.");
}
result = new HashMap(10, 2);
// auth-redirect (optional)
config = conf.getChild("auth-redirect", false);
if (config != null) {
result.put(PortalConstants.CONF_AUTH_REDIRECT, config.getValue());
}
// portal-uri (required)
config = conf.getChild("portal-uri", false);
if (config == null) {
throw new ProcessingException("portal: portal-uri required for application '"+appName+"'");
}
result.put(PortalConstants.CONF_PORTAL_URI, config.getValue());
// profile-cache (optional)
config = conf.getChild("profile-cache", false);
if (config != null && config.getValueAsBoolean()) {
result.put(PortalConstants.CONF_PROFILE_CACHE, appName);
}
// parallel coplets
config = conf.getChild("process-coplets-parallel", false);
if (config != null) {
result.put(PortalConstants.CONF_PARALLEL_COPLETS, new Boolean(config.getValueAsBoolean(false)));
} else {
result.put(PortalConstants.CONF_PARALLEL_COPLETS, Boolean.FALSE);
}
// timeout
config = conf.getChild("default-coplet-timeout", false);
if (config != null) {
result.put(PortalConstants.CONF_COPLET_TIMEOUT, new Long(config.getValueAsLong(600000)));
} else {
result.put(PortalConstants.CONF_COPLET_TIMEOUT, new Long(600000));
}
// and now the profile
config = conf.getChild("profile", false);
if (config == null) throw new ProcessingException("portal: profile configuration required for application '" + appName + "'");
Configuration child;
// build resource (optional)
child = config.getChild("buildprofile", false);
if (child != null) {
result.put(PortalConstants.CONF_BUILD_RESOURCE, child.getAttribute("uri"));
}
// base resource, type is optional
child = config.getChild("layout-base", false);
if (child == null) {
throw new ProcessingException("portal: layout-base required for application '" + appName + "'");
}
result.put(PortalConstants.CONF_LAYOUTBASE_RESOURCE, child.getAttribute("uri"));
child = config.getChild("coplet-base", false);
if (child == null) {
throw new ProcessingException("portal: coplet-base required for application '" + appName + "'");
}
result.put(PortalConstants.CONF_COPLETBASE_RESOURCE, child.getAttribute("uri"));
child = config.getChild("type-base", false);
if (child != null) {
result.put(PortalConstants.CONF_TYPEBASE_RESOURCE, child.getAttribute("uri"));
}
// coplet base save (is optional)
child = config.getChild("coplet-base-save", false);
if (child != null) {
result.put(PortalConstants.CONF_COPLETBASE_SAVE_RESOURCE, child.getAttribute("uri"));
}
// global delta (load required)
child = config.getChild("global-delta-load", false);
if (child == null) {
throw new ProcessingException("portal: global-delta-load required for application '" + appName + "'");
}
result.put(PortalConstants.CONF_GLOBALDELTA_LOADRESOURCE, child.getAttribute("uri"));
child = config.getChild("global-delta-save", false);
if (child != null) {
result.put(PortalConstants.CONF_GLOBALDELTA_SAVERESOURCE, child.getAttribute("uri"));
}
child = config.getChild("global-type-delta", false);
if (child != null) {
result.put(PortalConstants.CONF_GLOBALDELTA_TYPERESOURCE, child.getAttribute("uri"));
}
// role delta (optional)
child = config.getChild("role-delta-load", false);
if (child != null) {
result.put(PortalConstants.CONF_ROLEDELTA_LOADRESOURCE, child.getAttribute("uri"));
}
child = config.getChild("role-delta-save", false);
if (child != null) {
result.put(PortalConstants.CONF_ROLEDELTA_SAVERESOURCE, child.getAttribute("uri"));
}
child = config.getChild("role-type-delta", false);
if (child != null) {
result.put(PortalConstants.CONF_ROLEDELTA_TYPERESOURCE, child.getAttribute("uri"));
}
// User delta
child = config.getChild("user-delta-load", false);
if (child != null) {
result.put(PortalConstants.CONF_USERDELTA_LOADRESOURCE, child.getAttribute("uri"));
}
child = config.getChild("user-delta-save", false);
if (child != null) {
result.put(PortalConstants.CONF_USERDELTA_SAVERESOURCE, child.getAttribute("uri"));
}
child = config.getChild("user-type-delta", false);
if (child != null) {
result.put(PortalConstants.CONF_USERDELTA_TYPERESOURCE, child.getAttribute("uri"));
}
// Personal information
child = config.getChild("user-status-load", false);
if (child != null) {
result.put(PortalConstants.CONF_STATUS_LOADRESOURCE, child.getAttribute("uri"));
}
child = config.getChild("user-status-save", false);
if (child != null) {
result.put(PortalConstants.CONF_STATUS_SAVERESOURCE, child.getAttribute("uri"));
}
// Admin Type profil
child = config.getChild("admin-type-base", false);
if (child != null) {
result.put(PortalConstants.CONF_ADMIN_TYPE_BASE, child.getAttribute("uri"));
}
// store the config in the session
session.setAttribute(PortalConstants.ATTRIBUTE_CONFIGURATION + handlerName + ':' + appName, result);
} catch (ConfigurationException conf) {
throw new ProcessingException("ConfigurationException: " + conf, conf);
}
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END getConfiguration conf="+result);
}
return result;
}
/**
* Build the profile for the required level if not already done
*/
private void createProfile(SessionContext context,
String type,
String role,
String id,
boolean adminProfile)
throws SAXException, IOException, ProcessingException {
// no sync required
if (this.getLogger().isDebugEnabled() ) {
this.getLogger().debug("BEGIN createProfile context="+context+
", type="+type+
", role="+role+
", id="+id);
}
RequestState reqstate = this.getRequestState();
SourceParameters pars = reqstate.getHandler().getContext().getContextInfoAsParameters();
pars.setSingleParameterValue("type", type);
pars.setSingleParameterValue("admin", (adminProfile ? "true" : "false"));
if (!type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID) || role != null) {
pars.setSingleParameterValue("ID", id);
pars.setSingleParameterValue("role", role);
} else {
id = pars.getParameter("ID", null);
role = pars.getParameter("role", null);
}
Map map = this.getConfiguration();
if (map == null) {
throw new ProcessingException("portal Configuration not found.");
}
// is the configuration build by using a own resource?
String resource = (String)map.get(PortalConstants.CONF_BUILD_RESOURCE);
if (resource != null) {
if (this.getLogger().isInfoEnabled()) {
this.getLogger().info("Building portal profile: " + resource);
}
SourceUtil.readDOM(resource,
null,
pars,
this.resolver);
} else {
this.buildProfile(type, role, id, adminProfile);
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END createProfile");
}
}
/**
* Get the base profile for the current application.
* The base profile consists of the layout and the coplet profile
* and optional the type profile
*/
private DocumentFragment buildBaseProfile(Map config, boolean adminProfile)
throws ProcessingException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildBaseProfile config="+config+", adminProfile="+adminProfile);
}
DocumentFragment copletsFragment;
DocumentFragment layoutFragment;
DocumentFragment typeFragment;
DocumentFragment profile;
Document profileDoc;
Element profileRoot;
String res;
SourceParameters pars = new SourceParameters();
RequestState reqstate = this.getRequestState();
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "coplet-base");
// First load the base profiles: copletProfile + layoutProfile
res = (String)config.get(PortalConstants.CONF_COPLETBASE_RESOURCE);
if (res == null) {
throw new ProcessingException("No configuration for portal-coplet base profile found.");
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("Loading coplet base profile");
}
copletsFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("coplet base profile loaded");
}
res = (String)config.get(PortalConstants.CONF_LAYOUTBASE_RESOURCE);
if (res == null) {
throw new ProcessingException("No configuration for portal-layout base profile found.");
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading layout base profile");
}
pars.setSingleParameterValue("profile", "layout-base");
layoutFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("layout base profile loaded");
}
// now create the base profile containing the above profiles
profileDoc = DOMUtil.createDocument();
profile = profileDoc.createDocumentFragment();
profileRoot = profileDoc.createElementNS(null, "profile");
profile.appendChild(profileRoot);
profileRoot.appendChild(profileDoc.importNode(DOMUtil.selectSingleNode(layoutFragment,
"layout-profile", this.xpathProcessor), true));
profileRoot.appendChild(profileDoc.importNode(DOMUtil.selectSingleNode(copletsFragment,
"coplets-profile", this.xpathProcessor), true));
// if avalailable append the type profile
if (adminProfile) {
res = (String)config.get(PortalConstants.CONF_ADMIN_TYPE_BASE);
pars.setSingleParameterValue("profile", "admin-type-base");
} else {
res = (String)config.get(PortalConstants.CONF_TYPEBASE_RESOURCE);
pars.setSingleParameterValue("profile", "type-base");
}
if (res != null) {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading type base profile");
}
typeFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
profileRoot.appendChild(profileDoc.importNode(DOMUtil.selectSingleNode(typeFragment,
"type-profile", this.xpathProcessor), true));
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("type base profile loaded");
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildBaseProfile profile=" + profile);
}
return profile;
}
/**
* Build the global profile.
*/
private void buildGlobalProfile(Element profileRoot,
Map config,
boolean adminProfile)
throws ProcessingException {
// calling method is synced
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN buildGlobalProfile profileRoot="+profileRoot+", config="+config+", adminProfile="+adminProfile);
}
DocumentFragment globalFragment;
String res = (String)config.get(PortalConstants.CONF_GLOBALDELTA_LOADRESOURCE);
if (res == null) {
throw new ProcessingException("No configuration for portal-role delta profile found.");
}
SourceParameters pars = new SourceParameters();
RequestState reqstate = this.getRequestState();
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "global-delta");
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading global profile");
}
globalFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("global profile loaded");
}
this.importProfileDelta(profileRoot, globalFragment, "global-delta", "layout-delta");
this.importProfileDelta(profileRoot, globalFragment, "global-delta", "coplets-delta");
this.addProfilePart(profileRoot, globalFragment, "global-delta", "portal-profile");
this.addProfilePart(profileRoot, globalFragment, "global-delta", "personal-profile");
// types
res = (String)config.get(PortalConstants.CONF_GLOBALDELTA_TYPERESOURCE);
if (!adminProfile && res != null) {
pars.setSingleParameterValue("profile", "global-type-delta");
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading global type profile");
}
globalFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("global type profile loaded");
}
this.addProfilePart(profileRoot, globalFragment, "global-delta", "type-profile");
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END buildGlobalProfile");
}
}
/**
* Build the role profile
*/
private void buildRoleProfile(Element profileRoot,
Map config,
String role,
boolean adminProfile)
throws ProcessingException {
// calling method is synced
DocumentFragment roleFragment;
RequestState reqstate = this.getRequestState();
SourceParameters pars;
pars = new SourceParameters();
pars.setSingleParameterValue("role", role);
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "role-delta");
String res = (String)config.get(PortalConstants.CONF_ROLEDELTA_LOADRESOURCE);
if (res != null) {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading role profile");
}
roleFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("role profile loaded");
}
this.importProfileDelta(profileRoot, roleFragment, "role-delta", "layout-delta");
this.importProfileDelta(profileRoot, roleFragment, "role-delta", "coplets-delta");
this.addProfilePart(profileRoot, roleFragment, "role-delta", "portal-profile");
this.importProfileDelta(profileRoot, roleFragment, "role-delta", "personal-delta");
}
// types
res = (String)config.get(PortalConstants.CONF_ROLEDELTA_TYPERESOURCE);
if (!adminProfile && res != null) {
pars.setSingleParameterValue("profile", "role-type-delta");
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading role type profile");
}
roleFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("role type profile loaded");
}
this.addProfilePart(profileRoot, roleFragment, "role-delta", "type-profile");
}
}
/**
* Build the user profile
*/
private void buildUserProfile(Element profileRoot,
Map config,
String role,
String id,
boolean adminProfile)
throws ProcessingException {
// calling method is synced
DocumentFragment userFragment;
RequestState reqstate = this.getRequestState();
SourceParameters pars;
pars = new SourceParameters();
pars.setSingleParameterValue("ID", id);
pars.setSingleParameterValue("role", role);
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "user-delta");
String res = (String)config.get(PortalConstants.CONF_USERDELTA_LOADRESOURCE);
if (res != null) {
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading user profile");
}
userFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("user profile loaded");
}
this.importProfileDelta(profileRoot, userFragment, "user-delta", "layout-delta");
this.importProfileDelta(profileRoot, userFragment, "user-delta", "coplets-delta");
this.addProfilePart(profileRoot, userFragment, "user-delta", "portal-profile");
this.importProfileDelta(profileRoot, userFragment, "user-delta", "personal-delta");
}
// types
res = (String)config.get(PortalConstants.CONF_USERDELTA_TYPERESOURCE);
if (!adminProfile && res != null) {
pars.setSingleParameterValue("profile", "user-type-delta");
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading user type profile");
}
userFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("user type profile loaded");
}
this.addProfilePart(profileRoot, userFragment, "user-delta", "type-profile");
}
}
/**
* Load the user status profile (if available)
*/
private void buildUserStatusProfile(Element profileRoot,
Map config,
String role,
String id)
throws ProcessingException {
// calling method is synced
String res = (String)config.get(PortalConstants.CONF_STATUS_LOADRESOURCE);
// remove the old status profile
Node statusProfile = DOMUtil.getFirstNodeFromPath(profileRoot, new String[] {"status-profile"}, false);
if (statusProfile != null) {
profileRoot.removeChild(statusProfile);
}
if (res != null) {
DocumentFragment userFragment;
SourceParameters pars;
RequestState reqstate = this.getRequestState();
pars = new SourceParameters();
pars.setSingleParameterValue("ID", id);
pars.setSingleParameterValue("role", role);
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "user-status");
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("loading user status profile");
}
userFragment = SourceUtil.readDOM(res,
null,
pars,
this.resolver);
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("user status profile loaded");
}
this.addProfilePart(profileRoot, userFragment, null, "status-profile");
}
// test if the status-profile node is available
// if not create one
if (DOMUtil.getFirstNodeFromPath(profileRoot, new String[] {"status-profile"}, false) == null) {
statusProfile = profileRoot.getOwnerDocument().createElementNS(null, "status-profile");
profileRoot.appendChild(statusProfile);
}
}
/**
* Save the user status profile (if available)
*/
private void saveUserStatusProfile(Map profile,
Map config,
String role,
String id)
throws ProcessingException {
// calling method is synced
String res = (String)config.get(PortalConstants.CONF_STATUS_SAVERESOURCE);
Element statusProfile = (Element)DOMUtil.getFirstNodeFromPath((DocumentFragment)profile.get(PortalConstants.PROFILE_PROFILE),
new String[] {"profile","status-profile"}, false);
if (res != null && statusProfile != null) {
DocumentFragment userFragment = statusProfile.getOwnerDocument().createDocumentFragment();
Element saveStatus = (Element)statusProfile.cloneNode(true);
userFragment.appendChild(saveStatus);
// now filter all not persistent coplets!
NodeList list = DOMUtil.getNodeListFromPath(saveStatus, new String[] {"customization","coplet"});
String copletID;
Element coplet;
Element copletConfig;
Map copletConfigs = (Map)profile.get(PortalConstants.PROFILE_DEFAULT_COPLETS);
Map mediaCopletConfigs = (Map)profile.get(PortalConstants.PROFILE_MEDIA_COPLETS);
boolean isPersistent;
for(int i = 0; i < list.getLength(); i++) {
coplet = (Element)list.item(i);
copletID = coplet.getAttributeNS(null, "id");
copletConfig = this.getCopletConfiguration(copletID, copletConfigs, mediaCopletConfigs);
isPersistent = DOMUtil.getValueAsBooleanOf(copletConfig, "configuration/persistent", false, this.xpathProcessor);
if (!isPersistent) {
coplet.getParentNode().removeChild(coplet);
}
}
try {
RequestState reqstate = this.getRequestState();
SourceParameters pars;
pars = new SourceParameters();
pars.setSingleParameterValue("ID", id);
pars.setSingleParameterValue("role", role);
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
pars.setSingleParameterValue("profile", "user-status");
SourceUtil.writeDOM(res,
null,
pars,
userFragment,
this.resolver,
"xml");
} finally {
userFragment.removeChild(saveStatus);
}
}
}
/**
* Change the profile according to the request parameter
*/
private void changeProfile()
throws ProcessingException, SAXException, IOException {
// synchronized
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN changeProfile");
}
Request request = ContextHelper.getRequest(this.componentContext);
SessionContext context = this.getContext(false);
if (context != null) {
try {
Map theProfile = null;
String profileID = request.getParameter(PortalManagerImpl.REQ_PARAMETER_PROFILE);
if (profileID != null) {
theProfile = this.retrieveProfile(profileID);
}
if (theProfile != null) {
synchronized (context) {
DocumentFragment profile = (DocumentFragment)theProfile.get(PortalConstants.PROFILE_PROFILE);
Node[] miscNodes = (Node[])theProfile.get(PortalConstants.PROFILE_MISC_POINTER);
Element columns = (Element)miscNodes[PortalConstants.PROFILE_MISC_COLUMNS_NODE];
Enumeration enumeration = request.getParameterNames();
String current;
boolean saveProfile = false;
// first iteration: all changing commands
while (enumeration.hasMoreElements()) {
current = (String)enumeration.nextElement();
if (current.startsWith(PortalManagerImpl.REQ_PARAMETER_CONF)) {
int pos1, pos2;
pos1 = current.indexOf('.');
pos2 = current.indexOf('.', pos1+1);
if (pos1 != -1 && pos2 != -1) {
int pathIndex = new Integer(current.substring(pos1+1, pos2)).intValue();
int place= new Integer(current.substring(pos2+1)).intValue();
List typePaths = (List)theProfile.get(PortalConstants.PROFILE_TYPE_CONF_PATHS);
String path = (String)typePaths.get(pathIndex);
if (path != null) {
NodeList nodes = DOMUtil.selectNodeList(profile, path, this.xpathProcessor);
if (nodes != null) {
Node node = nodes.item(place);
if (node != null) {
if (!node.equals(columns)) {
DOMUtil.setValueOfNode(node, request.getParameter(current));
}
}
}
}
}
}
}
// second: all new
boolean calculate = false;
enumeration = request.getParameterNames();
while (enumeration.hasMoreElements()) {
current = (String)enumeration.nextElement();
if (current.startsWith(PortalManagerImpl.REQ_PARAMETER_CONF)) {
int pos1, pos2;
pos1 = current.indexOf('.');
pos2 = current.indexOf('.', pos1+1);
if (pos1 != -1 && pos2 != -1) {
int pathIndex = new Integer(current.substring(pos1+1, pos2)).intValue();
int place= new Integer(current.substring(pos2+1)).intValue();
List typePaths = (List)theProfile.get(PortalConstants.PROFILE_TYPE_CONF_PATHS);
String path = (String)typePaths.get(pathIndex);
if (path != null) {
NodeList nodes = DOMUtil.selectNodeList(profile, path, this.xpathProcessor);
if (nodes != null) {
Node node = nodes.item(place);
if (node != null) {
if (node.equals(columns)) {
int columnNumber = new Integer(request.getParameter(current)).intValue();
int oldNumber = new Integer(DOMUtil.getValueOfNode(columns)).intValue();
if (columnNumber > 0 && columnNumber != oldNumber && columnNumber <= PortalConstants.MAX_COLUMNS) {
this.changeColumns(profile,
oldNumber,
columnNumber,
miscNodes);
calculate = true;
DOMUtil.setValueOfNode(node, request.getParameter(current));
}
}
}
}
}
}
} else if (current.equals(PortalManagerImpl.REQ_PARAMETER_CMD)) {
String[] cmds = request.getParameterValues(current);
if (cmds != null && cmds.length > 0) {
for(int i = 0; i < cmds.length; i++) {
if (cmds[i].equals(PortalManagerImpl.REQ_CMD_SAVEPROFILE)) {
saveProfile = true;
} else {
if (this.modifyCoplet(cmds[i], context, theProfile, profile)) {
calculate = true;
}
}
}
}
}
}
// set type infos
if (calculate) {
this.setTypeInfo(profile,
(List)theProfile.get(PortalConstants.PROFILE_TYPE_PATHS),
(List)theProfile.get(PortalConstants.PROFILE_TYPE_CONF_PATHS));
}
// test if the status profile changed
Object statusChanged = theProfile.get(PortalConstants.PROFILE_SAVE_STATUS_FLAG);
if (statusChanged != null) {
theProfile.remove(PortalConstants.PROFILE_SAVE_STATUS_FLAG);
this.saveUserStatusProfile(theProfile,
this.getConfiguration(),
this.getRole(profileID),
this.getID(profileID));
}
// save the profile
if (saveProfile) {
Map conf = this.getConfiguration();
String role = this.getRole(profileID);
String id = this.getID(profileID);
String type = this.getType(profileID);
String saveResource;
String profileType;
if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_GLOBAL)) {
saveResource = (String)conf.get(PortalConstants.CONF_GLOBALDELTA_SAVERESOURCE);
profileType = "global-delta";
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ROLE)) {
saveResource = (String)conf.get(PortalConstants.CONF_ROLEDELTA_SAVERESOURCE);
profileType = "role-delta";
} else if (type.equals(PortalManagerImpl.BUILDTYPE_VALUE_ID)) {
saveResource = (String)conf.get(PortalConstants.CONF_USERDELTA_SAVERESOURCE);
profileType = "user-delta";
} else {
throw new ProcessingException("portal: No save resource defined for type '"+type+"'.");
}
// patch
// search for all "status/customize" nodes and set them
// to false
NodeList statusNodes = DOMUtil.selectNodeList(profile,
"profile/portal-profile/content/descendant::status/customize", this.xpathProcessor);
if (statusNodes != null) {
String value;
for(int l=0; l < statusNodes.getLength(); l++) {
value = DOMUtil.getValueOfNode(statusNodes.item(l));
if (value.equals("true")) {
DOMUtil.setValueOfNode(statusNodes.item(l), "false");
}
}
}
// build delta
RequestState reqstate = this.getRequestState();
DocumentFragment delta;
delta = this.buildProfileDelta(type, role, id, this.getIsAdminProfile(profileID));
SourceParameters pars = new SourceParameters();
pars.setSingleParameterValue("type", profileType);
if (id != null) pars.setSingleParameterValue("ID", id);
if (role != null) pars.setSingleParameterValue("role", role);
pars.setSingleParameterValue("application", reqstate.getApplicationName());
pars.setSingleParameterValue("handler", reqstate.getHandlerName());
SourceUtil.writeDOM(saveResource,
null,
pars,
delta,
this.resolver,
"xml");
if (delta.getParentNode() != null) delta.getParentNode().removeChild(delta);
delta = null;
// cache the profile
// The profile is only cached if it is already in the cache!
// Why? During login the profile is build and cached, so it is in the cache.
// But: If a user logs in, the profile is cached.
// Now the admin logs in, changes the global profile and saves it.
// The cache is invalidated, including the user profile.
// Now the user changes his profile and saves it.
// If it now would be cached, it would be invalid as it would
// not reflect the changes by the admin.
// But if the old profile is still in the cache, nobody
// has changed a profile above.
// Note CZ: The above is correct, but for building the delta
// the "previous" profile is build and cached ! Thus we can
// easily cache the new profile.
// if (this.isProfileCached(profileID, conf)) {
this.cacheProfile(profileID, theProfile, conf); // cache it
// now the hardest part, clean up the cache
this.cleanUpCache(type, role, conf);
// }
}
} // end synchronized
}
} catch (javax.xml.transform.TransformerException local) {
throw new ProcessingException("TransformerException: " + local, local);
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END changeProfile");
}
}
/**
* Change the number of the columns
*/
private void changeColumns(DocumentFragment profile,
int oldNumber,
int columnNumber,
Node[] miscNodes)
throws javax.xml.transform.TransformerException {
// calling method is (hopefully) synced
if (columnNumber < oldNumber) {
// remove columns and all coplets to the first one
Node columnNode;
Node firstColumn = DOMUtil.getSingleNode(profile,
"profile/portal-profile/content/column[@position='1']/coplets", this.xpathProcessor);
NodeList firstColumnCoplets = DOMUtil.getNodeListFromPath(firstColumn, new String[] {"coplet"});
int copletsCount = (firstColumnCoplets == null ? 0 : firstColumnCoplets.getLength());
for(int i = columnNumber + 1; i <= oldNumber; i++) {
columnNode = miscNodes[7+i];
if (columnNode != null) {
NodeList coplets = DOMUtil.getNodeListFromPath(columnNode, new String[] {"coplets","coplet"});
Node coplet;
if (coplets != null && coplets.getLength() > 0) {
for(int m = 0; m < coplets.getLength(); m++) {
coplet = coplets.item(m);
coplet.getParentNode().removeChild(coplet);
copletsCount++;
((Element)coplet).setAttributeNS(null, "position", "" + copletsCount);
firstColumn.appendChild(coplet);
}
}
columnNode.getParentNode().removeChild(columnNode);
miscNodes[7+i] = null;
}
}
} else if (columnNumber <= PortalConstants.MAX_COLUMNS) {
// add new columns
Node contentNode = DOMUtil.getFirstNodeFromPath(profile,
new String[] {"profile","portal-profile","content"}, false);
Document doc = contentNode.getOwnerDocument();
Element newColumn;
Element el;
for(int i = oldNumber + 1; i <= columnNumber; i++) {
newColumn = doc.createElementNS(null, "column");
newColumn.setAttributeNS(null, "position", ""+i);
miscNodes[7+i] = newColumn;
contentNode.appendChild(newColumn);
el = doc.createElementNS(null, "width");
el.appendChild(doc.createTextNode("5%"));
newColumn.appendChild(el);
el = doc.createElementNS(null, "coplets");
newColumn.appendChild(el);
}
}
}
/**
* Send SAX events to the next pipeline component.
* The node is parsed and the events are send to
* the next component in the pipeline.
* @param node The tree to be included.
*/
protected void sendEvents(XMLConsumer consumer, Node node)
throws SAXException {
IncludeXMLConsumer.includeNode(node, consumer, consumer);
}
/**
* Get all users in a document fragment with the following children:
* <users>
* <user>
* <ID>...</ID>
* <role>...</role> <!-- optional -->
* <data>
* ...
* </data>
* </user>
* ....
* </users>
* The document fragment might contain further nodes at the root!
* If <code>role</code> is <code>null</code> all users are fetched,
* otherwise only the users for this role.
* If also ID is not null only the single user is fetched.
*/
private Document getUsers(String role, String ID)
throws IOException, ProcessingException, SAXException {
// calling method is syned
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN getUsers role="+role+", ID="+ID);
}
RequestState reqstate = this.getRequestState();
Document frag = null;
Configuration conf = reqstate.getModuleConfiguration("single-role-user-management");
if (conf != null) {
// get load-users resource (optional)
Configuration child = conf.getChild("load-users", false);
if (child != null) {
String loadUsersResource = child.getAttribute("uri", null);
SourceParameters loadUsersResourceParameters = SourceParameters.create(child);
if (loadUsersResource != null) {
SourceParameters parameters = (loadUsersResourceParameters == null) ? new SourceParameters()
: loadUsersResourceParameters;
if (reqstate.getApplicationName() != null)
parameters.setSingleParameterValue("application", reqstate.getApplicationName());
if (ID != null) {
parameters.setSingleParameterValue("type", "user");
parameters.setSingleParameterValue("ID", ID);
} else {
parameters.setSingleParameterValue("type", "users");
}
if (role != null) parameters.setSingleParameterValue("role", role);
frag = this.loadResource(loadUsersResource, parameters);
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END getUsers fragment="+(frag == null ? "null" : XMLUtils.serializeNode(frag, XMLUtils.createPropertiesForXML(false))));
}
return frag;
}
/**
* Get all roles in a document fragment with the following children:
* <roles>
* <role>...</role>
* ....
* </roles>
* The document fragment might contain further nodes at the root!
*/
private Document getRoles()
throws IOException, ProcessingException, SAXException {
// calling method is syned
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("BEGIN getRoles");
}
Document frag = null;
RequestState reqstate = this.getRequestState();
Configuration conf = reqstate.getModuleConfiguration("single-role-user-management");
if (conf != null) {
// get load-roles resource (optional)
Configuration child = conf.getChild("load-roles", false);
if (child != null) {
String loadRolesResource = child.getAttribute("uri", null);
SourceParameters loadRolesResourceParameters = SourceParameters.create(child);
if (loadRolesResource != null) {
SourceParameters parameters = (loadRolesResourceParameters == null) ? new SourceParameters()
: loadRolesResourceParameters;
if (reqstate.getApplicationName() != null)
parameters.setSingleParameterValue("application", reqstate.getApplicationName());
parameters.setSingleParameterValue("type", "roles");
frag = this.loadResource(loadRolesResource, parameters);
}
}
}
if (this.getLogger().isDebugEnabled()) {
this.getLogger().debug("END getRoles fragment="+frag);
}
return frag;
}
/**
* Load XML resource
*/
private Document loadResource(String resource,
SourceParameters parameters)
throws IOException, ProcessingException, SAXException {
Source source = null;
try {
source = SourceUtil.getSource(resource,
null,
parameters,
this.resolver);
return SourceUtil.toDOM(source);
} catch (SourceException se) {
throw SourceUtil.handle(se);
} finally {
this.resolver.release(source);
}
}
/**
* Get the SessionManager component
*/
protected SessionManager getSessionManager()
throws ProcessingException {
if (this.sessionManager == null) {
try {
this.sessionManager = (SessionManager)this.manager.lookup(SessionManager.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of SessionManager component.", ce);
}
}
return this.sessionManager;
}
/**
* Get the ContextManager component
*/
protected ContextManager getContextManager()
throws ProcessingException {
if (this.contextManager == null) {
try {
this.contextManager = (ContextManager)this.manager.lookup(ContextManager.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of ContextManager component.", ce);
}
}
return this.contextManager;
}
/**
* Get the ContextManager component
*/
protected TransactionManager getTransactionManager()
throws ProcessingException {
if (this.transactionManager == null) {
try {
this.transactionManager = (TransactionManager)this.manager.lookup(TransactionManager.ROLE);
} catch (ComponentException ce) {
throw new ProcessingException("Error during lookup of TransactionManager component.", ce);
}
}
return this.transactionManager;
}
}