Package org.apache.slide.webdav.util

Source Code of org.apache.slide.webdav.util.PropertyHelper

/*
* $Header: /home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/util/PropertyHelper.java,v 1.80.2.3 2004/12/02 15:46:32 ozeigermann Exp $
* $Revision: 1.80.2.3 $
* $Date: 2004/12/02 15:46:32 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.slide.webdav.util;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.common.Domain;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.Uri;
import org.apache.slide.common.UriPath;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.NodeProperty.NamespaceCache;
import org.apache.slide.event.VetoException;
import org.apache.slide.lock.Lock;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.search.RequestedResource;
import org.apache.slide.search.Search;
import org.apache.slide.search.SearchQuery;
import org.apache.slide.search.SearchQueryResult;
import org.apache.slide.security.ACLSecurityImpl;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.security.NodePermission;
import org.apache.slide.security.Security;
import org.apache.slide.security.SecurityImpl;
import org.apache.slide.structure.ActionNode;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.structure.SubjectNode;
import org.apache.slide.util.Configuration;
import org.apache.slide.util.XMLValue;
import org.apache.slide.webdav.WebdavServletConfig;
import org.apache.slide.webdav.method.LockMethod;
import org.apache.slide.webdav.util.resourcekind.AbstractResourceKind;
import org.apache.slide.webdav.util.resourcekind.Activity;
import org.apache.slide.webdav.util.resourcekind.CheckedInVersionControlled;
import org.apache.slide.webdav.util.resourcekind.CheckedOutVersionControlled;
import org.apache.slide.webdav.util.resourcekind.DeltavCompliantCollection;
import org.apache.slide.webdav.util.resourcekind.ResourceKind;
import org.apache.slide.webdav.util.resourcekind.Version;
import org.apache.slide.webdav.util.resourcekind.VersionHistory;
import org.apache.slide.webdav.util.resourcekind.Workspace;
import org.jdom.Attribute;
import org.jdom.CDATA;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.Text;
import org.jdom.input.SAXBuilder;



/**
* Helper class for handling WebDAV properties.
*
*/

public class PropertyHelper extends AbstractWebdavHelper implements WebdavConstants, DeltavConstants, AclConstants, DaslConstants, BindConstants {
   
    public final static String LOCKDISCOVERY_INCL_PRINCIPAL =
        "lockdiscoveryIncludesPrincipalURL";
   
    public final static String PRIVILEGE_NAMESPACE = "privilege-namespace";
   
    private boolean lockdiscoveryIncludesPrincipalURL = true;
   
    /**
     * The Element returned by {@link #getCheckoutSetQueryElement
     * getCheckoutSetQueryElement()}.
     */
    protected Element checkoutSetQueryElement = null;
   
    /**
     * The <literal> Element used in the basic search query returned by
     * {@link #getCheckoutSetQueryElement getCheckoutSetQueryElement()}.
     */
    protected Element checkoutSetQueryLiteralElement = null;
   
    /**
     * The Element returned by {@link #getWorkspaceCheckoutSetQueryElement
     * getWorkspaceCheckoutSetQueryElement()}.
     */
    protected Element workspaceCheckoutSetQueryElement = null;
   
    /**
     * The <href> Element used in the basic search query returned by
     * {@link #getWorkspaceCheckoutSetQueryElement getWorkspaceCheckoutSetQueryElement()}.
     */
    protected Element workspaceCheckoutSetQueryHrefElement = null;
   
    private WebdavServletConfig sConf = null;
   
   
   
    /**
     * Factory method.
     * @deprecated
     */
//    public static PropertyHelper
//        getPropertyHelper( SlideToken sToken, NamespaceAccessToken nsaToken) {
//        return new PropertyHelper( sToken, nsaToken, null );
//    }
   
    /**
     * Factory method.
     */
    public static PropertyHelper
        getPropertyHelper( SlideToken sToken, NamespaceAccessToken nsaToken, WebdavServletConfig sConf ) {
        return new PropertyHelper( sToken, nsaToken, sConf );
    }
   
   
    /**
     * Protected contructor
     */
    protected PropertyHelper( SlideToken sToken, NamespaceAccessToken nsaToken, WebdavServletConfig sConf ) {
        super( sToken, nsaToken );
        this.sConf = sConf;
        if( sConf != null )
            lockdiscoveryIncludesPrincipalURL =
                !("false".equalsIgnoreCase(sConf.getInitParameter(LOCKDISCOVERY_INCL_PRINCIPAL)));
    }
   
    /**
     * Create initial default properties to be stored for the specified
     * resource kind.
     * The result set does not contain transient properties.
     * @post result != null
     * @return a list of initial non-transient properties (empty list if none)
     */
    public List createInitialProperties( ResourceKind resourceKind, String resourcePath ) {
       
        Set sp = resourceKind.getSupportedLiveProperties();
        List result = null;
       
        if( sp == null )
            result = Collections.EMPTY_LIST;
        else {
            result = new ArrayList();
            Iterator i = sp.iterator();
            while( i.hasNext() ) {
                String propName = (String)i.next();
                if( AbstractResourceKind.isComputedProperty(propName) )
                    continue;
                Object pvalue = createDefaultValue( propName, resourceKind, resourcePath );
                if (pvalue != null) {
                    result.add( new NodeProperty(propName, pvalue) );
                }
            }
        }
        return result;
    }
   
    /**
     * Create a default value for the specified property name and resource
     * kind
     */
    Object createDefaultValue( String propName, ResourceKind resourceKind, String resourcePath ) {
       
        String autoVersion =
            Domain.getParameter(I_AUTO_VERSION,
                                I_AUTO_VERSION_DEFAULT,
                                nsaToken.getUri(sToken, resourcePath).getStore());
       
        String checkoutFork =
            Domain.getParameter(I_CHECKOUT_FORK,
                                I_CHECKOUT_FORK_DEFAULT,
                                nsaToken.getUri(sToken, resourcePath).getStore());
       
        String checkinFork =
            Domain.getParameter(I_CHECKIN_FORK,
                                I_CHECKIN_FORK_DEFAULT,
                                nsaToken.getUri(sToken, resourcePath).getStore());
       
        String result = null;
       
        if( P_RESOURCETYPE.equals(propName) ) {
            StringBuffer rtvv = new StringBuffer();
            try {
                if( resourceKind instanceof VersionHistory ) {
                    rtvv.append(
                        xmlOut.outputString(new Element(E_VERSION_HISTORY, DNSP)) );
                    rtvv.append(
                        xmlOut.outputString(new Element(E_COLLECTION, DNSP)) );
                }
                if( resourceKind instanceof DeltavCompliantCollection ) {
                    rtvv.append(
                        xmlOut.outputString(new Element(E_COLLECTION, DNSP)) );
                }
                if( resourceKind instanceof Activity ) {
                    rtvv.append(
                        xmlOut.outputString(new Element(E_ACTIVITY, DNSP)) );
                }
            }
            catch( Exception x ) {
                x.printStackTrace();
            }
            result = rtvv.toString();
        }
        else if( P_SUPPORTED_METHOD_SET.equals(propName) ) {
            Iterator i = resourceKind.getSupportedMethods().iterator();
            StringBuffer smsv = new StringBuffer();
            while( i.hasNext() ) {
                String m = (String) i.next();
                Element sm = new Element( E_SUPPORTED_METHOD, DNSP );
                Attribute na = new Attribute( A_NAME, m, DNSP );
                sm.setAttribute( na );
                try {
                    smsv.append( xmlOut.outputString(sm) );
                }
                catch( Exception x ) { x.printStackTrace(); }
            }
            result = smsv.toString();
        }
        else if( P_SUPPORTED_LIVE_PROPERTY_SET.equals(propName) ) {
            Iterator i = resourceKind.getSupportedLiveProperties().iterator();
            StringBuffer spsv = new StringBuffer();
            while( i.hasNext() ) {
                String p = (String) i.next();
                Element sp = new Element( E_SUPPORTED_LIVE_PROPERTY, DNSP );
                Element na = new Element( E_NAME, DNSP );
                na.addContent( p );
                sp.addContent( na );
                try {
                    spsv.append( xmlOut.outputString(sp) );
                }
                catch( Exception x ) { x.printStackTrace(); }
            }
            result = spsv.toString();
        }
        else if( P_SUPPORTED_REPORT_SET.equals(propName) ) {
            Iterator i = resourceKind.getSupportedReports().iterator();
            StringBuffer srsv = new StringBuffer();
            while( i.hasNext() ) {
                String r = (String) i.next();
                Element sr = new Element( E_SUPPORTED_REPORT, DNSP );
                Element na = new Element( E_NAME, DNSP );
                na.addContent( r );
                sr.addContent( na );
                try {
                    srsv.append( xmlOut.outputString(sr) );
                }
                catch( Exception x ) { x.printStackTrace(); }
            }
            result = srsv.toString();
        }
        else if( P_AUTO_VERSION.equals(propName) ) {
           
            XMLValue xmlValue = new XMLValue();
           
            if (autoVersion.length() > 0) {
                xmlValue.add(new Element(autoVersion, DNSP));
            }
           
            if( ! resourceKind.isSupportedPropertyValue(P_AUTO_VERSION, xmlValue) ) {
                Domain.warn( "Auto-version not configured properly; using "
                                +E_CHECKOUT_CHECKIN );
                xmlValue = new XMLValue(new Element(E_CHECKOUT_CHECKIN, DNSP));
            }
           
            result = xmlValue.toString();
        }
        else if( P_CHECKOUT_FORK.equals(propName) ) {
           
            XMLValue xmlValue = new XMLValue();
           
            if (checkoutFork.length() > 0) {
                xmlValue.add(new Element(checkoutFork, DNSP));
            }
           
            if( ! resourceKind.isSupportedPropertyValue(P_CHECKOUT_FORK, xmlValue) ) {
                Domain.warn( "Checkout-fork not configured properly; using "
                                +E_FORBIDDEN );
                xmlValue = new XMLValue(new Element(E_FORBIDDEN, DNSP));
            }
           
            result = xmlValue.toString();
        }
        else if( P_CHECKIN_FORK.equals(propName) ) {
           
            XMLValue xmlValue = new XMLValue();
           
            if (checkinFork.length() > 0) {
                xmlValue.add(new Element(checkinFork, DNSP));
            }
           
            if( ! resourceKind.isSupportedPropertyValue(P_CHECKIN_FORK, xmlValue) ) {
                Domain.warn( "Checkin-fork not configured properly; using "
                                +E_FORBIDDEN );
                xmlValue = new XMLValue(new Element(E_FORBIDDEN, DNSP));
            }
           
            result = xmlValue.toString();
        }
        else if( P_GETCONTENTLANGUAGE.equals(propName) ) {
            result = "en";
        }
        else if( P_CREATOR_DISPLAYNAME.equals(propName) ) {
            if( sToken != null ) {
                CredentialsToken credToken = sToken.getCredentialsToken();
                if( credToken != null ) {
                    result = credToken.getPublicCredentials();
                    if (result == null || result.equals("") || result.equals("/")) {
                        result = SubjectNode.UNAUTHENTICATED_URI;
                    }
                }
            }
        }
        // REQUIRED properties
        else if( P_PREDECESSOR_SET.equals(propName) ) {
            result = "";
        }
        else if( P_CHECKOUT_SET.equals(propName) ) {
            result = "";
        }
        else if( P_COMMENT.equals(propName) ) {
            result = "";
        }
        else if( P_LABEL_NAME_SET.equals(propName) ) {
            result = "";
        }
        return result;
    }
   
    /**
     * Create CDATA value.
     */
    public Object createCdataValue( String text ) {
        StringBuffer b = new StringBuffer();
        if( text == null )
            text = "";
        b.append( "![CDATA[" ).append( text ).append( "]]" );
        return b.toString();
    }
   
    /**
     * Create href value.
     */
    public Object createHrefValue( String uri ) {
        String result = "";
       
        Element href = new Element( E_HREF, DNSP );
        href.addContent( uri );
        try {
            result = xmlOut.outputString( href );
        }
        catch( Exception x ) {
            x.printStackTrace();
        }
       
        return result;
    }
   
    /**
     * Create href set value.
     */
    public Object createHrefSetValue( List uriList ) {
        StringBuffer b = new StringBuffer();
        Iterator i = uriList.iterator();
        while( i.hasNext() )
            b.append( createHrefValue((String)i.next()) );
        return b.toString();
    }
   
    /**
     * Create href set value.
     */
    public Object createHrefSetValue( String rootElement, List uriList ) {
        String result = "";
       
        Element root = new Element( rootElement, DNSP );
        Iterator i = uriList.iterator();
       
        while( i.hasNext() ) {
            Element href = new Element( E_HREF, DNSP );
            href.addContent( (String)i.next() );
            root.addContent( href );
        }
        try {
            result = xmlOut.outputString( root );
        }
        catch( Exception x ) {
            x.printStackTrace();
        }
       
        return result;
    }
   
    /**
     * Parse an XML-Valued property value.
     */
    public Element parsePropertyValue( String propValue ) throws JDOMException, IOException {
        Document d = xmlBuilder.build( new StringReader(propValue) );
        return d.getRootElement();
    }
   
    /**
     * Returns the property of the resource described by
     * the resourcePath.
     *
     * @param    propertyName        the name of the property.
     * @param    resourcePath        the path that identifies the resource.
     *
     * @return   the property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     * @deprecated use {@link #getProperty(String, String, String)}
     */
    public NodeProperty getProperty(String propertyName, String resourcePath) throws SlideException, JDOMException {
        return getProperty(propertyName, resourcePath, null);
    }
   
    /**
     * Returns the property of the resource described by
     * the resourcePath.
     *
     * @param    propertyName        the name of the property.
     * @param    resourcePath        the path that identifies the resource.
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public NodeProperty getProperty(String propertyName, String resourcePath, String slideContextPath) throws SlideException, JDOMException {
       
        UriHandler uriHandler = UriHandler.getUriHandler(resourcePath);
        String uri = null;
        NodeRevisionDescriptors revisionDescriptors = null;
        NodeRevisionDescriptor revisionDescriptor = null;
        Content contentHelper = nsaToken.getContentHelper();
       
        if (uriHandler.isVersionUri()) {
            uri = uriHandler.getAssociatedHistoryUri();
            NodeRevisionNumber revisionNumber = new NodeRevisionNumber(uriHandler.getVersionName());
            revisionDescriptors = contentHelper.retrieve(sToken, uri);
            revisionDescriptor = contentHelper.retrieve(sToken, revisionDescriptors, revisionNumber);
        }
        else if (uriHandler.isHistoryUri()) {
            uri = uriHandler.getAssociatedHistoryUri();
            NodeRevisionNumber revisionNumber = new NodeRevisionNumber("0.0");
            revisionDescriptors = contentHelper.retrieve(sToken, uri);
            revisionDescriptor = contentHelper.retrieve(sToken, revisionDescriptors, revisionNumber);
        }
        else {
            uri = resourcePath;
            revisionDescriptors = contentHelper.retrieve(sToken, uri);
            revisionDescriptor = contentHelper.retrieve(sToken, revisionDescriptors);
        }
        return getProperty(propertyName, revisionDescriptors, revisionDescriptor, slideContextPath);
    }
   
    /**
     * Returns the property of the resource described by
     * the resourcePath.
     *
     * @param    propertyName         the name of the property.
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     *
     * @return   the property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     * @deprecated use {@link #getProperty(String, NodeRevisionDescriptors, NodeRevisionDescriptor, String)}
     */
    public NodeProperty getProperty(String propertyName, NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor) throws SlideException, JDOMException {
        return getProperty(propertyName, revisionDescriptors, revisionDescriptor, null);
    }
   
    /**
     * Returns the property of the resource described by
     * the resourcePath.
     *
     * @param    propertyName         the name of the property.
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public NodeProperty getProperty(String propertyName, NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
       
        NodeProperty property = revisionDescriptor.getProperty( propertyName );
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        if (resourceKind.isSupportedLiveProperty(propertyName)) {
            if (AbstractResourceKind.isComputedProperty(propertyName)) {
                property = computeProperty(propertyName, revisionDescriptors, revisionDescriptor, slideContextPath);
            }
        }
       
        return property;
    }
   
    /**
     * Returns the computed property of the resource.
     *
     * @param    propertyName         the name of the property.
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public NodeProperty computeProperty(String propertyName, NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
       
        NodeProperty property = null;
        if (P_SUCCESSOR_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSuccessorSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_VERSION_HISTORY.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeVersionHistory(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_ROOT_VERSION.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeRootVersion(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_SUPPORTED_METHOD_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSupportedMethodSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_SUPPORTED_LIVE_PROPERTY_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSupportedLivePropertySet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_SUPPORTED_REPORT_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSupportedReportSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_CHECKOUT_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeCheckoutSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_WORKSPACE_CHECKOUT_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeWorkspaceCheckoutSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_WORKSPACE.equals(propertyName)) {
            XMLValue ws = null;
            if (Configuration.useBinding(nsaToken.getUri(sToken, revisionDescriptors.getUri()).getStore())) {
                ws = computeWorkspace(revisionDescriptors, revisionDescriptor, slideContextPath);
            }
            else {
                ws = computeWorkspaceNoBinding(revisionDescriptors, revisionDescriptor, slideContextPath);
            }
            if (ws != null) {
                property = new NodeProperty(propertyName, ws);
            }
        }
           
        else if (P_LOCKDISCOVERY.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeLockDiscovery(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_SUPPORTEDLOCK.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSupportedlock(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_SUPPORTED_PRIVILEGE_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeSupportedPrivilegeSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_CURRENT_USER_PRIVILEGE_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeCurrentuserPrivilegeSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_ACL.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeAcl(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_PRINCIPAL_COLLECTION_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computePrincipalCollectionSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_PRIVILEGE_COLLECTION_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computePrivilegeCollectionSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_OWNER.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeOwner(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_CREATIONUSER.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeCreationUser(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_MODIFICATIONUSER.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeModificationUser(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_INHERITED_ACL_SET.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeInheritedAclSet(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_ACL_RESTRICTIONS.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeAclRestrictions(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
        else if (P_GROUP_MEMBERSHIP.equals(propertyName)) {
            property = new NodeProperty(propertyName, computeGroupMembership(revisionDescriptors, revisionDescriptor, slideContextPath));
        }
       
        return property;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;href&gt;</code> elements
     * describing the successors of the resource.
     *
     * The concatenation of <code>contextPath</code>,<code>servletPath</code> and
     * <code>revisionDescriptor.getUri()</code> gives the absolute URL of the resource
     * on this server.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     *
     * @return   the successor list.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     */
    public XMLValue computeSuccessorSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
        Element hrefElement = new Element(E_HREF, DNSP);
        //NodeRevisionDescriptor successorRevisionDescriptor = null;
        NodeRevisionNumber successorRevisionNumber = null;
        Enumeration successorEnum = revisionDescriptors.getSuccessors(revisionDescriptor.getRevisionNumber());
       
        if (successorEnum != null) {
            while (successorEnum.hasMoreElements()) {
                successorRevisionNumber = (NodeRevisionNumber)successorEnum.nextElement();
                hrefElement = (Element)hrefElement.clone();
                StringBuffer buffer = new StringBuffer(revisionDescriptors.getUri());
                if ( ! revisionDescriptors.getUri().endsWith("/") ) {
                    buffer.append("/");
                }
                buffer.append(successorRevisionNumber.toString());
               
                hrefElement.setText(WebdavUtils.getAbsolutePath (
                                        buffer.toString(),
                                        slideContextPath, sConf));
               
                xmlValue.add(hrefElement);
            }
        }
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;href&gt;</code> element
     * with the history URI of the resource. If the resource is neither a
     * VR, checked-in VCR or checked-out VCR, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the version history <code>&lt;href&gt;</code>.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computeVersionHistory(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, JDOMException {
       
        XMLValue xmlValue = new XMLValue();
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        if (resourceKind instanceof Version) {
            Element element = new Element(E_HREF, DNSP);
           
            element.setText(WebdavUtils.getAbsolutePath (
                                revisionDescriptors.getUri(), slideContextPath,
                                sConf));
           
            xmlValue.add(element);
        }
        else if (resourceKind instanceof CheckedInVersionControlled) {
            Element element = new Element(E_HREF, DNSP);
            String checkedInHref = revisionDescriptor.getProperty(P_CHECKED_IN).getValue().toString();
            String checkedInUri = ((Element)new XMLValue(checkedInHref).iterator().next()).getText();
            UriHandler uriHandler = UriHandler.getUriHandler(checkedInUri);
           
            element.setText (WebdavUtils.getAbsolutePath (
                                 uriHandler.getAssociatedHistoryUri(),
                                 slideContextPath, sConf));
           
            xmlValue.add(element);
        }
        else if (resourceKind instanceof CheckedOutVersionControlled) {
            Element element = new Element(E_HREF, DNSP);
            String checkedOutHref = revisionDescriptor.getProperty(P_CHECKED_OUT).getValue().toString();
            String checkedOutUri = ((Element)new XMLValue(checkedOutHref).iterator().next()).getText();
            UriHandler uriHandler = UriHandler.getUriHandler(checkedOutUri);
           
            element.setText(WebdavUtils.getAbsolutePath (
                                uriHandler.getAssociatedHistoryUri(),
                                slideContextPath, sConf));
           
            xmlValue.add(element);
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;href&gt;</code> element
     * with the URI of the root version of the history.
     * If the resource is not a history, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     *
     * @return   the root version URI.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     */
    public XMLValue computeRootVersion(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        if (resourceKind instanceof VersionHistory) {
            Element element = new Element(E_HREF, DNSP);
            StringBuffer buffer = new StringBuffer(revisionDescriptors.getUri());
            if ( ! revisionDescriptors.getUri().endsWith("/") ) {
                buffer.append("/");
            }
            buffer.append(revisionDescriptors.getInitialRevision().toString());
           
            element.setText(WebdavUtils.getAbsolutePath (
                                buffer.toString(),
                                slideContextPath, sConf));
           
            xmlValue.add(element);
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;supported-method&gt;</code>
     * elements with the name (attribute) of the supported methods.
     * <br></br>
     * <i>Note:</i>
     * <br></br>
     * <i>
     * Due to the specification this is <b>not</b> a computed property, but because
     * of implementation problems it is not stored.
     * </i>
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     *
     * @return   the supported methods.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     */
    public XMLValue computeSupportedMethodSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        Set supportedMethodNames = resourceKind.getSupportedMethods();
        Iterator iterator = supportedMethodNames.iterator();
        Element supportedMethod = null;
        while (iterator.hasNext()) {
            supportedMethod = new Element(E_SUPPORTED_METHOD, DNSP);
            supportedMethod.setAttribute(new Attribute(E_NAME, (String)iterator.next()));
            xmlValue.add(supportedMethod);
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;supported-live-property&gt;</code>
     * elements containing <code>&lt;prop&gt;</code> which are containing
     * elements with the name of the property.
     * <br></br>
     * <i>Note:</i>
     * <br></br>
     * <i>
     * Due to the specification this is <b>not</b> a computed property, but because
     * of implementation problems it is not stored.
     * </i>
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the supported live properties.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     */
    public XMLValue computeSupportedLivePropertySet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        Set supportedLivePropertyNames = resourceKind.getSupportedLiveProperties();
        Iterator iterator = supportedLivePropertyNames.iterator();
        Element supportedLivePropertyElement = null;
        Element propElement = null;
        Element propertyElement = null;
        while (iterator.hasNext()) {
           
            supportedLivePropertyElement = new Element(E_SUPPORTED_LIVE_PROPERTY, DNSP);
            propElement = new Element(E_PROP, DNSP);
            supportedLivePropertyElement.addContent(propElement);
            propertyElement = new Element((String)iterator.next(), DNSP);
            propElement.addContent(propertyElement);
            xmlValue.add(supportedLivePropertyElement);
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the <code>&lt;supported-report&gt;</code>
     * elements containing <code>&lt;report&gt;</code> which are containing
     * elements with the name of the report.
     * <br></br>
     * <i>Note:</i>
     * <br></br>
     * <i>
     * Due to the specification this is <b>not</b> a computed property, but because
     * of implementation problems it is not stored.
     * </i>
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the supported reports.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     */
    public XMLValue computeSupportedReportSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        Set supportedReportNames = resourceKind.getSupportedReports();
        Iterator iterator = supportedReportNames.iterator();
        Element supportedReportElement = null;
        Element reportElement = null;
        Element propertyElement = null;
        while (iterator.hasNext()) {
           
            supportedReportElement = new Element(E_SUPPORTED_REPORT, DNSP);
            reportElement = new Element(E_REPORT, DNSP);
            supportedReportElement.addContent(reportElement);
            propertyElement = new Element((String)iterator.next(), DNSP);
            reportElement.addContent(propertyElement);
            xmlValue.add(supportedReportElement);
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing <code>&lt;href&gt;</code> elements
     * with the URI of the VCRs that have a <code>&lt;checked-out&gt;</code>
     * property pointing to this VR.
     * If the resource is not a VR, the returned XMLValue is empty.
     * The difference to the other
     * {@link #computeCheckoutSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) computeCheckoutSet()}
     * method signature is that the <code>&lt;href&gt;</code> contain only
     * the slide URI and not the complete URI that is to be returned by e.g.
     * PROPFIND.
     *
     * @deprecated use {@link #computeCheckoutSet(NodeRevisionDescriptors, NodeRevisionDescriptor, String)}
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the VR.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the VR.
     *
     * @return   the value of the <code>&lt;checkout-set&gt;</code> property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public XMLValue computeCheckoutSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor) throws SlideException, JDOMException {
        return computeCheckoutSet(revisionDescriptors, revisionDescriptor, null);
    }
   
    /**
     * Returns an XMLValue containing <code>&lt;href&gt;</code> elements
     * with the URI of the VCRs that have a <code>&lt;checked-out&gt;</code>
     * property pointing to this VR.
     * If the resource is not a VR, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the VR.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the VR.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;checkout-set&gt;</code> property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public XMLValue computeCheckoutSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        if (resourceKind instanceof Version) {
           
            String resourcePath = VersioningHelper.getUri(nsaToken,
                                                          sToken,
                                                          nsaToken.getContentHelper(),
                                                          revisionDescriptors,
                                                          revisionDescriptor);
           
            Element basicSearch = getCheckoutSetQueryElement(resourcePath);
           
            String grammarNamespace = basicSearch.getNamespaceURI();
            Search searchHelper = nsaToken.getSearchHelper();
        // @FIXME Why is servletPath not required?
            SearchQuery searchQuery = searchHelper.createSearchQuery(grammarNamespace,
                                                                     basicSearch,
                                                                     sToken,
                                                                     Integer.MAX_VALUE,
                                                                     slideContextPath);
           
            SearchQueryResult queryResult = searchHelper.search(sToken, searchQuery);
            Iterator queryResultIterator = queryResult.iterator();
            RequestedResource requestedResource = null;
            Element href = null;
            while (queryResultIterator.hasNext()) {
                requestedResource = (RequestedResource)queryResultIterator.next();
                href = new Element(E_HREF, DNSP);
               
                href.setText (WebdavUtils.getAbsolutePath (
                                  requestedResource.getUri(), slideContextPath, sConf));
               
                xmlValue.add(href);
            }
        }
       
        return xmlValue;
    }
   
    /**
     * Returns the query document used to search all resources that have
     * a &lt;checked-out&gt; property with a &lt;href&gt; value containing
     * the URI that identifies the given resource.
     *
     * @param      resourcePath  the Uri to search for.
     *
     * @return     the query document.
     */
    protected Element getCheckoutSetQueryElement(String resourcePath) throws SlideException {
       
        if (checkoutSetQueryElement == null) {
           
            checkoutSetQueryElement = new Element(DaslConstants.E_BASICSEARCH, DNSP);
           
            Element select = new Element(DaslConstants.E_SELECT, DNSP);
            checkoutSetQueryElement.addContent(select);
            Element prop = new Element(E_PROP, DNSP);
            select.addContent(prop);
            Element checkedOut = new Element(P_CHECKED_OUT, DNSP);
            prop.addContent(checkedOut);
           
            Element from = new Element(DaslConstants.E_FROM, DNSP);
            checkoutSetQueryElement.addContent(from);
            Element scope = new Element(DaslConstants.E_SCOPE, DNSP);
            from.addContent(scope);
            Element href = new Element(E_HREF, DNSP);
            scope.addContent(href);
            href.setText("");
            Iterator excludeIterator = getNonVcrPathExcludeList().iterator();
            while (excludeIterator.hasNext()) {
                scope.addContent((Element)excludeIterator.next());
            }
           
            Element where = new Element(DaslConstants.E_WHERE, DNSP);
            checkoutSetQueryElement.addContent(where);
            Element propcontains = new Element(DaslConstants.E_PROPCONTAINS, NamespaceCache.SLIDE_NAMESPACE);
            where.addContent(propcontains);
            propcontains.addContent((Element)prop.clone());
            checkoutSetQueryLiteralElement = new Element(DaslConstants.E_LITERAL, DNSP);
            propcontains.addContent(checkoutSetQueryLiteralElement);
        }
        checkoutSetQueryLiteralElement.setText(resourcePath);
       
        return checkoutSetQueryElement;
    }
   
    /**
     ** Returns a List of <code>&lt;exclude&gt;</code> elements containing the
     ** paths to exclude from the search since they does not contain
     ** version-controlled resources (e.g. the users path and the history paths) .
     **
     ** @pre        true
     ** @post       true
     **
     ** @return     a List of <code>&lt;exclude&gt;</code> elements.
     **/
    public List getNonVcrPathExcludeList() {
       
        List excludeList = new ArrayList();
       
        String usersPath = truncateLeadingSlash(nsaToken.getNamespaceConfig().getUsersPath());
        addExcludeElement(usersPath, excludeList);
       
        String groupsPath = truncateLeadingSlash(nsaToken.getNamespaceConfig().getGroupsPath());
        addExcludeElement(groupsPath, excludeList);
       
        String rolesPath = truncateLeadingSlash(nsaToken.getNamespaceConfig().getRolesPath());
        addExcludeElement(rolesPath, excludeList);
       
        Iterator historyPathIterator = HistoryPathHandler.getHistoryPathHandler().getResolvedHistoryPaths().iterator();
        while (historyPathIterator.hasNext()) {
            String path = truncateLeadingSlash(historyPathIterator.next().toString());
            addExcludeElement(path, excludeList);
        }
       
        return excludeList;
    }
   
    private void addExcludeElement(String path, List excludeList) {
        if (path != null && path.length() > 0) {
            Element excludeElement = new Element(DaslConstants.E_EXCLUDE, NamespaceCache.SLIDE_NAMESPACE);
            excludeElement.setText(path);
            excludeList.add(excludeElement);
        }
    }
   
    /**
     * Returns an XMLValue containing <code>&lt;href&gt;</code> elements
     * with the URI of the VCRs in the workspace identified the given
     * NodeRevisionDescriptor(s) that have a <code>&lt;checked-out&gt;</code>.
     * If the resource is not a Workspace, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the Workspace.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the Workspace.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;workspace-checkout-set&gt;</code> property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public XMLValue computeWorkspaceNoBinding(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
        XMLValue result = null;
        UriHandler hrUh = UriHandler.getUriHandler(revisionDescriptors, revisionDescriptor);
        String associatedWsUri = hrUh.getAssociatedWorkspaceUri();
        if (associatedWsUri != null) {
            result = new XMLValue();
            Element hrElm = new Element(E_HREF, DNSP);
            hrElm.setText(associatedWsUri);
            result.add(hrElm);
        }
        return result;
    }
   
    /**
     * Returns an XMLValue containing <code>&lt;href&gt;</code> elements
     * with the URI of the VCRs in the workspace identified the given
     * NodeRevisionDescriptor(s) that have a <code>&lt;checked-out&gt;</code>.
     * If the resource is not a Workspace, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the Workspace.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the Workspace.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;workspace-checkout-set&gt;</code> property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public XMLValue computeWorkspace(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
        XMLValue result = null;
       
        UriHandler rUh = new UriHandler(revisionDescriptors.getUri());
        if (rUh.getAssociatedWorkspaceUri() != null) {
            result = new XMLValue();
            Element hrElm = new Element(E_HREF, DNSP);
            hrElm.setText(rUh.getAssociatedWorkspaceUri());
            result.add(hrElm);
            return result;
        }
       
        NodeProperty psProp = revisionDescriptor.getProperty(P_PARENT_SET);
        if (psProp == null) {
            return new XMLValue();
        }
       
        List psUris = new ArrayList();
        XMLValue xv = new XMLValue(String.valueOf(psProp.getValue()));
        Iterator i = xv.getList().iterator();
        while (i.hasNext()) {
            Element pElm = (Element)i.next();
            UriHandler hrUh = new UriHandler(pElm.getChild(E_HREF, DNSP).getText());
            if (hrUh.getAssociatedWorkspaceUri() != null) {
                result = new XMLValue();
                Element hrElm = new Element(E_HREF, DNSP);
                hrElm.setText(hrUh.getAssociatedWorkspaceUri());
                result.add(hrElm);
                break;
            }
            else if (!hrUh.isRootUri()) {
                psUris.add(hrUh);
            }
        }
       
        if (result == null) {
            i = psUris.iterator();
            while (i.hasNext()) {
                NodeRevisionDescriptors nrds =
                    nsaToken.getContentHelper().retrieve(sToken, ((UriHandler)i.next()).getUri());
                NodeRevisionDescriptor nrd =
                    nsaToken.getContentHelper().retrieve(sToken, nrds);
                result = computeWorkspace(nrds, nrd, slideContextPath);
                if (result != null) {
                    break;
                }
            }
        }
       
        return result;
    }
   
    /**
     * Returns an XMLValue containing <code>&lt;href&gt;</code> elements
     * with the URI of the VCRs in the workspace identified the given
     * NodeRevisionDescriptor(s) that have a <code>&lt;checked-out&gt;</code>.
     * If the resource is not a Workspace, the returned XMLValue is empty.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the Workspace.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the Workspace.
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;workspace-checkout-set&gt;</code> property.
     *
     * @throws   SlideException
     * @throws   JDOMException
     */
    public XMLValue computeWorkspaceCheckoutSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws SlideException, JDOMException {
       
        XMLValue xmlValue = new XMLValue();
       
        ResourceKind resourceKind = AbstractResourceKind.determineResourceKind(nsaToken, revisionDescriptors, revisionDescriptor);
        if (resourceKind instanceof Workspace) {
           
            Element basicSearch = getWorkspaceCheckoutSetQueryElement(revisionDescriptors.getUri());
            String grammarNamespace = basicSearch.getNamespaceURI();
            Search searchHelper = nsaToken.getSearchHelper();
            SearchQuery searchQuery = searchHelper.createSearchQuery(grammarNamespace,
                                                                     basicSearch,
                                                                     sToken,
                                                                     Integer.MAX_VALUE,
                                                                     slideContextPath);
            SearchQueryResult queryResult = searchHelper.search(sToken, searchQuery);
            Iterator queryResultIterator = queryResult.iterator();
            RequestedResource requestedResource = null;
            Element hrefElement = null;
            while (queryResultIterator.hasNext()) {
                requestedResource = (RequestedResource)queryResultIterator.next();
                hrefElement = new Element(E_HREF, DNSP);
               
               
                hrefElement.setText (WebdavUtils.getAbsolutePath (
                                         requestedResource.getUri(),
                                         slideContextPath, sConf));
               
                xmlValue.add(hrefElement);
            }
        }
       
        return xmlValue;
    }
   
    /**
     * Returns the query document used to search all resources that have
     * a &lt;checked-out&gt; property within the given <code>scopePath</code>.
     *
     * @param      scopePath  the Uri of the scope to search in.
     *
     * @return     the query document.
     */
    protected Element getWorkspaceCheckoutSetQueryElement(String scopePath) {
       
        if (workspaceCheckoutSetQueryElement == null) {
           
            workspaceCheckoutSetQueryElement = new Element(DaslConstants.E_BASICSEARCH, DNSP);
           
            Element select = new Element(DaslConstants.E_SELECT, DNSP);
            workspaceCheckoutSetQueryElement.addContent(select);
            Element prop = new Element(E_PROP, DNSP);
            select.addContent(prop);
            Element checkedOut = new Element(P_CHECKED_OUT, DNSP);
            prop.addContent(checkedOut);
           
            Element from = new Element(DaslConstants.E_FROM, DNSP);
            workspaceCheckoutSetQueryElement.addContent(from);
            Element scope = new Element(DaslConstants.E_SCOPE, DNSP);
            from.addContent(scope);
            workspaceCheckoutSetQueryHrefElement = new Element(E_HREF, DNSP);
            scope.addContent(workspaceCheckoutSetQueryHrefElement);
           
            Element where = new Element(DaslConstants.E_WHERE, DNSP);
            workspaceCheckoutSetQueryElement.addContent(where);
            Element isdefined = new Element(DaslConstants.E_ISDEFINED, DNSP);
            where.addContent(isdefined);
            isdefined.addContent((Element)prop.clone());
        }
        workspaceCheckoutSetQueryHrefElement.setText(truncateLeadingSlash(scopePath));
       
        return workspaceCheckoutSetQueryElement;
    }
   
    /**
     * Returns an XMLValue containing the value of the <code>&lt;lockdiscovery&gt;</code>
     * property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;lockdiscovery&gt;</code> property.
     *
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   ObjectNotFoundException
     */
    private XMLValue computeLockDiscovery(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ServiceAccessException, LinkedObjectNotFoundException, ObjectNotFoundException, LockTokenNotFoundException {
       
        XMLValue xmlValue = new XMLValue();
        Lock lock = nsaToken.getLockHelper();
        NodeLock objectLockToken = null;
        Enumeration lockTokens = lock.enumerateLocks(sToken, revisionDescriptors.getUri(), true);
        Set addedLockIDs = new HashSet();
        while (lockTokens.hasMoreElements()) {
            objectLockToken = (NodeLock) lockTokens.nextElement();
            if (revisionDescriptors.getUri().equals(objectLockToken.getObjectUri()) ||
                objectLockToken.isInheritable()
               ) {
               
                if (!addedLockIDs.contains(objectLockToken.getLockId())) {
                    Element activelock = createActiveLockElement(objectLockToken,
                            slideContextPath);
                    if (activelock != null) {
                        xmlValue.add(activelock);
                        addedLockIDs.add(objectLockToken.getLockId());
                    }
                }
            }
        }
       
        return xmlValue;
    }
   
    /**
     * Returns an XMLValue containing the value of the <code>&lt;lockdiscovery&gt;</code>
     * property.
     *
     * @param    objectLockToken     the NodeLock for which to compute the value
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     *
     * @return   the value of the <code>&lt;lockdiscovery&gt;</code> property.
     *
     */
    public XMLValue computeLockDiscovery(NodeLock objectLockToken, String slideContextPath) {
       
        XMLValue xmlValue = new XMLValue();
        Element activelock = createActiveLockElement(objectLockToken, slideContextPath);
       
        if (activelock != null) {
            xmlValue.add(activelock);
        }
        return xmlValue;
    }
   
    /**
     * Returns the <code>&lt;activelock&gt;</code> element to be used as child
     * the <code>&lt;lockdiscovery&gt;</code> property.
     *
     * @param    objectLockToken     the NodeLock for which to compute the value
     *                               of the <code>&lt;activelock&gt;</code>.
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     * @param    contextPath         a  String , the result of HttpRequest.getContextPath()
     *
     * @return   the <code>&lt;activelock&gt;</code> element.
     *
     */
    private Element createActiveLockElement(NodeLock objectLockToken, String slideContextPath) {
       
        Element activelock = null;
        //Security security = nsaToken.getSecurityHelper();
       
        if (objectLockToken != null) {
           
            activelock = new Element(E_ACTIVELOCK, DNSP);
            Element locktype = new Element(E_LOCKTYPE, DNSP);
            activelock.addContent(locktype);
            if (objectLockToken.isLocal()) {
                Element transaction = new Element(E_TRANSACTION, DNSP);
                Element groupoperation = new Element(E_GROUPOPERATION, DNSP);
                transaction.addContent(groupoperation);
                locktype.addContent(transaction);
            } else {
                Element write = new Element(E_WRITE, DNSP);
                locktype.addContent(write);
            }
            Element lockscope = new Element(E_LOCKSCOPE, DNSP);
            activelock.addContent(lockscope);
            Element lockscopeValue = null;
            if (objectLockToken.isExclusive()) {
                lockscopeValue = new Element(E_EXCLUSIVE, DNSP);
            } else if (objectLockToken.isShared()) {
                lockscopeValue = new Element(E_SHARED, DNSP);
            } else if (objectLockToken.isLocal()) {
                lockscopeValue = new Element(E_LOCAL, DNSP);
            }
            lockscope.addContent(lockscopeValue);
            Element depth = new Element(E_DEPTH, DNSP);
            activelock.addContent(depth);
            if (objectLockToken.isInheritable()) {
                depth.setText("infinity");
            } else {
                depth.setText("0");
            }
            Element owner = new Element(E_OWNER, DNSP);
            activelock.addContent(owner);
            /* We need to write this as data (i.e. a CDATA section) because
             * we don't know what the subjectUri (i.e. username) might
             * contain. The webdav RFC leaves us completely free to
             * put whatever we want inside the owner element.
             */
            if( objectLockToken.getOwnerInfo() != null &&
               !objectLockToken.getOwnerInfo().equals(LockMethod.DEFAULT_LOCK_OWNER) ) {
               
                // try to parse
                try {
                    Document d =
                        new SAXBuilder().build( new StringReader(objectLockToken.getOwnerInfo()) );
                    owner.addContent(d.detachRootElement());
                }
                catch( Throwable e ) {
                    owner.addContent(new CDATA(objectLockToken.getOwnerInfo()));
                }
            }
           
            Element timeout = new Element(E_TIMEOUT, DNSP);
            activelock.addContent(timeout);
            long seconds = (new Long((objectLockToken.getExpirationDate().getTime()
                                          - (new Date()).getTime())/1000)).longValue();
            if (seconds > 0.75 * Integer.MAX_VALUE) {
                timeout.setText("Infinite");
            }
            else {
                timeout.setText("Second-"+seconds);
            }
            Element locktoken = new Element(E_LOCKTOKEN, DNSP);
            activelock.addContent(locktoken);
            Element href = new Element(E_HREF, DNSP);
            locktoken.addContent(href);
            href.setText(S_LOCK_TOKEN+objectLockToken.getLockId());
           
            // As proposed on February 08, 2003 by Lisa Dusseault in w3c-dist-auth-request@w3.org
            // >>>>>>>>>> start principal-URL >>>>>>>>>>>>
            if( lockdiscoveryIncludesPrincipalURL ) {
                Element principalUrl = new Element( E_PRINCIPAL_URL, DNSP);
                activelock.addContent(principalUrl);
                SubjectNode snode =
                    SubjectNode.getSubjectNode(objectLockToken.getSubjectUri());
                String subjectUri = objectLockToken.getSubjectUri();
                if (snode.equals(SubjectNode.UNAUTHENTICATED)) {
                    String userspath = nsaToken.getNamespaceConfig().getUsersPath();
                    subjectUri = userspath+"/"+snode.toString();
                }
                Element puhref = new Element(E_HREF, DNSP);
                principalUrl.addContent(puhref);
               
                puhref.setText(
                    WebdavUtils.getAbsolutePath(subjectUri, slideContextPath, sConf));
            }
            // <<<<<<<<<< end principal-URL <<<<<<<<<<<<<<
        }
        return activelock;
    }
   
    /**
     * Returns an XMLValue containing the value of the <code>&lt;supportedlock&gt;</code>
     * property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath         the context path of the NodeRevisionDescriptors' uri.
     * @param    servletPath         a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;supportedlock&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computeSupportedlock(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
       
        XMLValue xmlValue = new XMLValue();
       
        Element lockentry = new Element(E_LOCKENTRY, DNSP);
        Element lockscope = new Element(E_LOCKSCOPE, DNSP);
        lockentry.addContent(lockscope);
        Element exclusive = new Element(E_EXCLUSIVE, DNSP);
        lockscope.addContent(exclusive);
        Element locktype = new Element(E_LOCKTYPE, DNSP);
        lockentry.addContent(locktype);
        Element write = new Element(E_WRITE, DNSP);
        locktype.addContent(write);
        xmlValue.add(lockentry);
       
        lockentry = new Element(E_LOCKENTRY, DNSP);
        lockscope = new Element(E_LOCKSCOPE, DNSP);
        lockentry.addContent(lockscope);
        Element shared = new Element(E_SHARED, DNSP);
        lockscope.addContent(shared);
        locktype = new Element(E_LOCKTYPE, DNSP);
        lockentry.addContent(locktype);
        write = new Element(E_WRITE, DNSP);
        locktype.addContent(write);
        xmlValue.add(lockentry);
       
        return xmlValue;
    }
   
   
    /**
     * Returns an XMLValue containing the value of the <code>&lt;supported-privilege-set&gt;</code>
     * property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;supported-privilege-set&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computeSupportedPrivilegeSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        Map actionAggregation = ((SecurityImpl)nsaToken.getSecurityHelper()).getActionAggregation(sToken);
        Set rootSet = new HashSet(actionAggregation.keySet());
        Iterator actions = actionAggregation.keySet().iterator();
        while (actions.hasNext()) {
            ActionNode a = (ActionNode)actions.next();
            Iterator aggregates = ((Set)actionAggregation.get(a)).iterator();
            while (aggregates.hasNext()) {
                ActionNode c = (ActionNode)aggregates.next();
                rootSet.remove(c);
            }
        }
        Element rootSp = new Element(E_SUPPORTED_PRIVILEGE, DNSP);
        Element p = new Element(E_PRIVILEGE, DNSP);
        p.addContent(new Element(E_ALL, DNSP));
        rootSp.addContent(p);
        Iterator roots = rootSet.iterator();
        addElementsForAggregatedActions(rootSp, roots, actionAggregation);
        return new XMLValue(rootSp);
    }
   
    /**
     * Build the tree of an action with all its aggregated actions for use in
     * the result of <code>supported-privilege-set</code> queries.
     *
     * This method modifies <code>parentActionElement</code>.
     *
     * @param parentActionElement The action element to which to add the direct
     *                            aggregated acttions to.
     * @param aggregatedActions The direct aggregated actions.
     * @param actionAggregation A map from an action to its direct aggregated
     *                          actions.
     */
    private void addElementsForAggregatedActions(Element parentActionElement, Iterator aggregatedActions, Map actionAggregation) {
        while (aggregatedActions.hasNext()) {
            ActionNode a = (ActionNode)aggregatedActions.next();
            Element sp = new Element(E_SUPPORTED_PRIVILEGE, DNSP);
            Element p = new Element(E_PRIVILEGE, DNSP);
            Namespace actionNamespace = a.getNamespace();
            if (actionNamespace == null) {
                actionNamespace = DNSP;
            }
            p.addContent(new Element(a.getPath().lastSegment(), actionNamespace));
            addElementsForAggregatedActions(p, ((Set)actionAggregation.get(a)).iterator(), actionAggregation);
            sp.addContent(p);
            parentActionElement.addContent(sp);
        }
    }


    /**
     * Creates a <code>&lt;privilege&gt;</code> element containing an
     * element with the given <code>privilegeName</code>.
     *
     * @param      privilegeName  the name of the privilege.
     *
     * @return     the <code>&lt;privilege&gt;</code> element.
     * @throws ServiceAccessException
     * @throws RevisionDescriptorNotFoundException
     */
    private Element createPrivilege(ActionNode privilege, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
        return createPrivilege(privilege, true, privilegeUri);
    }
   
    /**
     * Creates a <code>&lt;privilege&gt;</code> element containing an
     * element with the given <code>privilegeName</code>.
     *
     * @param      privilegeName    the name of the privilege.
     * @param      useDavNamespace  if <code>true</code> the <code>DAV:</code>
     *                              namespace will be used for the contained element,
     *                              otherwise the slide namespace.
     *
     * @return     the <code>&lt;privilege&gt;</code> element.
     * @throws ServiceAccessException
     * @throws RevisionDescriptorNotFoundException
     */
    private Element createPrivilege(ActionNode privilege, boolean useDavNamespace, Uri privilegeUri) throws RevisionDescriptorNotFoundException, ServiceAccessException {
        NodeRevisionNumber latestRevisionNumber = privilegeUri.getStore().retrieveRevisionDescriptors(privilegeUri).getLatestRevision();
        NodeProperty privilegeNamespaceProperty = privilegeUri.getStore().retrieveRevisionDescriptor(privilegeUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, WebdavConstants.S_DAV);
        Namespace privilegeNamespace = null;
        if (privilegeNamespaceProperty != null && privilegeNamespaceProperty.getValue() instanceof String) {
            privilegeNamespace = Namespace.getNamespace((String) privilegeNamespaceProperty.getValue());
        } else {
            privilegeNamespace = DNSP;
            if ( ! useDavNamespace ) {
                privilegeNamespace = NamespaceCache.SLIDE_NAMESPACE;
            }
        }
        Element privilegeElement = new Element(E_PRIVILEGE, DNSP);
        Element privilegeNameElement = new Element(privilege.getPath().lastSegment(), privilegeNamespace);
        privilegeElement.addContent(privilegeNameElement);
        return privilegeElement;
    }
   
    /**
     * Returns an XMLValue containing the value of the
     * <code>&lt;current-user-privilege-set&gt;</code> property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;current-user-privilege-set&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computeCurrentuserPrivilegeSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        XMLValue xmlValue = new XMLValue();
       
        try {
        NamespaceConfig config = nsaToken.getNamespaceConfig();
        Structure structure = nsaToken.getStructureHelper();
        ObjectNode object =  structure.retrieve(sToken, revisionDescriptors.getUri());

        // check read-own-permissions permission
        Security security = nsaToken.getSecurityHelper();
        security.checkCredentials(sToken, object, config.getReadOwnPermissionsAction());
       
            String actionsPath = config.getActionsPath();
            Uri actionsPathUri = nsaToken.getUri(sToken, actionsPath);
            ObjectNode actionsPathNode = actionsPathUri.getStore().retrieveObject(actionsPathUri);
            Enumeration actions = actionsPathNode.enumerateChildren();
            addGrantedActionsToPrivilegeSet(xmlValue, object, actions);
        }
        catch (ServiceAccessException e) {
            throw e;
        }
        catch (SlideException e) {
            return xmlValue;
        }
        return xmlValue;
    }
   
    /**
     * Build a set of privileges a subject has for an object for use in the
     * result of <code>current-user-privilege-set</code> queries.
     *
     * This method modifies <code>xmlValue</code>.
     *
     * @param xmlValue The element to which to add the actions which have been
     *                 granted to the subject.
     * @param object The object for which to determine which actions have been
     *               granted.
     * @param actions The URIs (as <code>String</code>s) of the actions to
     *                check.
     */
    private void addGrantedActionsToPrivilegeSet(XMLValue xmlValue, ObjectNode object, Enumeration actions) throws ServiceAccessException, ObjectNotFoundException, RevisionDescriptorNotFoundException {
        while (actions.hasMoreElements()) {
            Uri aNodeUri = nsaToken.getUri(sToken, (String)actions.nextElement());
            ObjectNode oNode = aNodeUri.getStore().retrieveObject(aNodeUri);
            if (oNode.hasChildren()) {
                addGrantedActionsToPrivilegeSet(xmlValue, object, oNode.enumerateChildren());
            } else {
                ActionNode aNode = ActionNode.getActionNode(oNode.getUri());
                if (nsaToken.getSecurityHelper().hasPermission(sToken, object, aNode)) {
                    xmlValue.add(createPrivilege(aNode, aNodeUri));
                }
            }
        }
    }


    /**
     * Returns an XMLValue containing the value of the
     * <code>&lt;acl&gt;</code> property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;acl&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    //public XMLValue computeAcl(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String contextPath, String serverURL) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException, VetoException {
    public XMLValue computeAcl(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException, VetoException {
        // FIXME serverUrl?
        XMLValue xmlValue = new XMLValue();
       
        NamespaceConfig config = nsaToken.getNamespaceConfig();
        Structure structure = nsaToken.getStructureHelper();
        ObjectNode objectNode =  structure.retrieve(sToken, revisionDescriptors.getUri());
       
        // check read-acl permission
        Security security = nsaToken.getSecurityHelper();
        security.checkCredentials(sToken, objectNode, config.getReadPermissionsAction());
       
        String currentSubjectUri = "";
        boolean currentNegative = false;
        String currentInheritedFrom = "";
        Element currentAceElm = null;
        Element currentGrantDenyElm = null;
        Enumeration permissions = security.enumeratePermissions(sToken, objectNode, true);
        while (permissions.hasMoreElements()) {
            NodePermission perm = (NodePermission)permissions.nextElement();
            if (!perm.getSubjectUri().equals(currentSubjectUri)
                || (perm.isNegative() && !currentNegative || !perm.isNegative() && currentNegative)
        || (!currentInheritedFrom.equals(perm.getInheritedFrom()))) {
               
                // save previous ACE
                if (currentAceElm != null) {
                    xmlValue.add(currentAceElm);
                }
               
                // new ACE
                currentAceElm = new Element(E_ACE, DNSP);
               
                // principal
                if (perm.isInvert()) {
                    Element invertElm = new Element(E_INVERT, DNSP);
                    invertElm.addContent(createPrincipalElement(perm.getSubjectUri()));
                    currentAceElm.addContent(invertElm);
                }
                else {
                    currentAceElm.addContent(createPrincipalElement(perm.getSubjectUri()));
                }
               
                // grant/deny
                currentGrantDenyElm = perm.isNegative()
                    ? new Element(E_DENY, DNSP)
                    : new Element(E_GRANT, DNSP);
                currentAceElm.addContent(currentGrantDenyElm);
               
                // inherited
                String inheritedFrom = perm.getInheritedFrom();
                if (inheritedFrom != null && inheritedFrom.length() > 0) {
                    currentAceElm.addContent(createInheritedElement(inheritedFrom));
                }
               
                // protected
                if (perm.isProtected()) {
                    currentAceElm.addContent(new Element(E_PROTECTED, DNSP));
                }
               
                currentSubjectUri = perm.getSubjectUri();
                currentNegative = perm.isNegative();
                currentInheritedFrom = inheritedFrom != null ? inheritedFrom : "";
            }
            currentGrantDenyElm.addContent(createPrivilegeElement(perm.getActionUri()));
        }
       
        // save last ACE
        if (currentAceElm != null) {
            xmlValue.add(currentAceElm);
        }
       
        return xmlValue;
    }
   
    private Element createInheritedElement(String inheritedFrom) {
        Element inheritedElm = new Element(E_INHERITED, DNSP);
        Element hrefElm = new Element(E_HREF, DNSP);
        hrefElm.addContent(new Text(inheritedFrom));
        inheritedElm.addContent(hrefElm);
        return inheritedElm;
    }
   
    private Element createPrincipalElement(String subjectUri) {
        Element principalElm = new Element(E_PRINCIPAL, DNSP);
        if (subjectUri.equals(SubjectNode.ALL_URI)) {
            Element allElm = new Element(E_ALL, DNSP);
            principalElm.addContent(allElm);
        }
        else if (subjectUri.equals(SubjectNode.AUTHENTICATED_URI)) {
            Element authenticatedElm = new Element(E_AUTHENTICATED, DNSP);
            principalElm.addContent(authenticatedElm);
        }
        else if (subjectUri.equals(SubjectNode.UNAUTHENTICATED_URI)) {
            Element unauthenticatedElm = new Element(E_UNAUTHENTICATED, DNSP);
            principalElm.addContent(unauthenticatedElm);
        }
        else if (subjectUri.equals(SubjectNode.OWNER_URI)) {
            Element propertyElm = new Element(E_PROPERTY, DNSP);
            propertyElm.addContent(new Element(P_OWNER, DNSP));
            principalElm.addContent(propertyElm);
        }
        else if (subjectUri.equals(SubjectNode.SELF_URI)) {
            Element selfElm = new Element(E_SELF, DNSP);
            principalElm.addContent(selfElm);
        }
        else {
            Element hrefElm = new Element(E_HREF, DNSP);
            hrefElm.addContent(new Text(subjectUri));
            principalElm.addContent(hrefElm);
        }
        return principalElm;
    }
   
    private Element createPrivilegeElement(String actionUriAsString) throws RevisionDescriptorNotFoundException, ServiceAccessException {
        Element privilegeElm = new Element(E_PRIVILEGE, DNSP);
        if (actionUriAsString.equals(ActionNode.ALL_URI)) {
            Element allElm = new Element(E_ALL, DNSP);
            privilegeElm.addContent(allElm);
        }
        else {
            Uri actionUri = nsaToken.getUri(sToken, actionUriAsString);
            NodeRevisionNumber latestRevisionNumber = actionUri.getStore().retrieveRevisionDescriptors(actionUri).getLatestRevision();
            NodeProperty privilegeNamespace = actionUri.getStore().retrieveRevisionDescriptor(actionUri, latestRevisionNumber).getProperty(PRIVILEGE_NAMESPACE, WebdavConstants.S_DAV);
            Namespace actionNamespace = null;
            if (privilegeNamespace != null && privilegeNamespace.getValue() instanceof String) {
                actionNamespace = Namespace.getNamespace((String) privilegeNamespace.getValue());
            }
            else {
                actionNamespace = DNSP;
            }

            Element actionElm = new Element(new UriPath(actionUriAsString).lastSegment(), actionNamespace);
            privilegeElm.addContent(actionElm);
        }
        return privilegeElm;
    }   
   
    /**
     * Returns an XMLValue containing the value of the
     * <code>&lt;principal-collection-set&gt;</code> property.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;principal-collection-set&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computePrincipalCollectionSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        XMLValue xmlValue = new XMLValue();
        NamespaceConfig namespaceConfig = nsaToken.getNamespaceConfig();
       
        xmlValue.addHref(WebdavUtils.getAbsolutePath (namespaceConfig.getUsersPath(),
                slideContextPath, sConf));
       
        if (namespaceConfig.getGroupsPath() != null) {
           
            xmlValue.addHref(WebdavUtils.getAbsolutePath (namespaceConfig.getGroupsPath(),
                    slideContextPath, sConf));
        }
        if (namespaceConfig.getRolesPath() != null) {
            xmlValue.addHref(WebdavUtils.getAbsolutePath (namespaceConfig.getRolesPath(),
                    slideContextPath, sConf));
        }
        return xmlValue;
    }
   
   
    public XMLValue computePrivilegeCollectionSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        XMLValue xmlValue = new XMLValue();
        NamespaceConfig namespaceConfig = nsaToken.getNamespaceConfig();
       
        String absUri = WebdavUtils.getAbsolutePath (namespaceConfig.getActionsPath(),
                slideContextPath, sConf);
       
        xmlValue.addHref(absUri);
        return xmlValue;
    }
   
   
    /**
     * Returns an XMLValue containing the value of the
     * <code>&lt;owner&gt;</code> property.
     * The XMLValue is comupted of userspath + user_collection + owner.
     * The userspath and the user_prefix properties are set in the Domain.xml file.
     *
     * @param    revisionDescriptors  the NodeRevisionDescriptors of the resource.
     * @param    revisionDescriptor   the NodeRevisionDescriptor of the resource.
     * @param    contextPath          a  String , the result of HttpRequest.getContextPath()
     * @param    servletPath          a String, the result of HttpRequest.getServletPath()
     *
     * @return   the value of the <code>&lt;owner&gt;</code> property.
     *
     * @throws   ObjectLockedException
     * @throws   RevisionDescriptorNotFoundException
     * @throws   ServiceAccessException
     * @throws   LinkedObjectNotFoundException
     * @throws   AccessDeniedException
     * @throws   ObjectNotFoundException
     * @throws   JDOMException
     */
    public XMLValue computeOwner(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
       
        NodeProperty ownerProperty = revisionDescriptor.getProperty(P_OWNER,
                                                                    NodeProperty.DEFAULT_NAMESPACE);
       
        XMLValue xmlValue = createUserPath(ownerProperty, slideContextPath);
       
        return xmlValue;
    }   
   
    public XMLValue computeCreationUser(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
       
        NodeProperty creationUserProperty = revisionDescriptor.getProperty(P_CREATIONUSER,
                                                                           NodeProperty.DEFAULT_NAMESPACE);
        XMLValue xmlValue = createUserPath(creationUserProperty, slideContextPath);
       
        return xmlValue;
    }
   
    public XMLValue computeModificationUser(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
       
        NodeProperty modificationUserProperty = revisionDescriptor.getProperty(P_MODIFICATIONUSER,
                                                                               NodeProperty.DEFAULT_NAMESPACE);
       
        XMLValue xmlValue = createUserPath(modificationUserProperty, slideContextPath);
       
        return xmlValue;
    }
   
    public XMLValue computeInheritedAclSet(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        // TODO: find appropriate strategy, e.g. refer to root of namespace
        if (revisionDescriptor.getProperty(P_INHERITED_ACL_SET) != null) {
            Object v = revisionDescriptor.getProperty(P_INHERITED_ACL_SET).getValue();
            return (v instanceof XMLValue)
                ? (XMLValue)v
                : new XMLValue((String)v);
        }
        else {
            return new XMLValue();
        }
    }
   
    public XMLValue computeAclRestrictions(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        // no restrictions in Slide implementation?
        if (revisionDescriptor.getProperty(P_ACL_RESTRICTIONS) != null) {
            Object v = revisionDescriptor.getProperty(P_ACL_RESTRICTIONS).getValue();
            return (v instanceof XMLValue)
                ? (XMLValue)v
                : new XMLValue((String)v);
        }
        else {
            return new XMLValue();
        }
    }
   
    public XMLValue computeGroupMembership(NodeRevisionDescriptors revisionDescriptors, NodeRevisionDescriptor revisionDescriptor, String slideContextPath) throws ObjectLockedException, RevisionDescriptorNotFoundException, ServiceAccessException, LinkedObjectNotFoundException, AccessDeniedException, ObjectNotFoundException, LockTokenNotFoundException, JDOMException {
        if (revisionDescriptor.getProperty(P_GROUP_MEMBERSHIP) != null) {
            Object v = revisionDescriptor.getProperty(P_GROUP_MEMBERSHIP).getValue();
            return (v instanceof XMLValue)
                ? (XMLValue)v
                : new XMLValue((String)v);
        }
        else {
            XMLValue xmlValue = new XMLValue();
            Uri principalUri = nsaToken.getUri(sToken, revisionDescriptors.getUri());
            SubjectNode principalNode = (SubjectNode)principalUri.getStore().retrieveObject(principalUri);
            Enumeration roles = ((ACLSecurityImpl)nsaToken.getSecurityHelper()).getGroupMembership(sToken, principalNode);
            while (roles.hasMoreElements()) {
                String rolePath = (String)roles.nextElement();
                String roleHref = slideContextPath+rolePath;
                xmlValue.addHref(roleHref);
            }
            return xmlValue;
        }
    }
   
    private XMLValue createUserPath(NodeProperty userProperty, String slideContextPath)
       throws IllegalArgumentException
    {
        XMLValue xmlValue = new XMLValue();
        String userHref = "";
        NamespaceConfig config = nsaToken.getNamespaceConfig();
        if ((userProperty != null) && (userProperty.getValue()!=null) &&
                (!"".equals(userProperty.getValue().toString()))) {
           
            userHref = slideContextPath + config.getUsersPath()
                       + "/" + userProperty.getValue().toString();
            xmlValue.addHref(userHref);
        }
        else {
            xmlValue.add(new Element(E_UNAUTHENTICATED, DNSP));
        }
        return xmlValue;
    }
   
   
    /**
     * Returns the concatenation of <code>serverURL</code>, <code>contextPath</code>
     * and <code>uri</code> and inserts all needed slashes.
     *
     * This method is deprecated, as it takes neither scope nor the servlet
     * path into account (when the servlet is not the default servlet). Please
     * use WebdavUtils.getAbsolutePath() instead.
     *
     * @deprecated
     * @param      serverURL    the URL of the server
     * @param      contextPath  the context path.
     * @param      uri          the (slide-) URI of the resource.
     *
     * @return     the concatenated URL.
     */
    public static String getAbsoluteURL(String serverURL, String contextPath, String uri) {
        // FIXME servletContext??
        StringBuffer buffer = new StringBuffer();
        String lastAppended = null;
        //        if (serverURL != null) {
        //            buffer.append(serverURL);
        //            lastAppended = buffer.toString();
        //        }
        if (contextPath != null) {
            if ( (lastAppended != null) && !lastAppended.endsWith("/") && !contextPath.startsWith("/") ) {
                buffer.append("/");
            }
            buffer.append(contextPath);
            lastAppended = buffer.toString();
        }
        if (uri != null) {
            if ( (lastAppended != null) && !lastAppended.endsWith("/") && !uri.startsWith("/") ) {
                buffer.append("/");
            }
            buffer.append(uri);
        }
       
        return WebdavUtils.encodeURL(buffer.toString());
    }
   
    /**
     * Returns <code>true</code> if the given <code>uri</code> is an absolute URL.
     *
     * @param      contextPath  the context path.
     * @param      uri          the (slide-) URI of the resource.
     *
     * @return     <code>true</code> if the given <code>uri</code> is an absolute URL.
     */
    public static boolean isAbsoluteURL(String servletContextPath, String uri) {
        if (uri.startsWith(S_RESOURCE_ID)) {
            return true;
        }
        if (uri.startsWith(S_LOCK_TOKEN)) {
            return true;
        }
        if (!uri.startsWith("/")) {
            uri = "/" + uri;
        }
        return uri.startsWith(servletContextPath);
    }
   
    /**
     * Adds the given <code>uri</code> as a <code>&lt;href&gt;</code> element
     * to the value of the property (specified by the <code>propertyName</code>)
     * of the given NodeRevisionDescriptor (if not already contained).
     *
     * @param      revisionDescriptor  the NodeRevisionDescriptor for which to
     *                                 update the property.
     * @param      propertyName        the name of the property to add the uri to.
     * @param      uri                 the uri to add as a <code>&lt;href&gt;</code> element.
     * @return     true, if href was added; false, if already contained
     * @throws   JDOMException
     *
     */
    public static boolean addHrefToProperty(NodeRevisionDescriptor revisionDescriptor, String propertyName, String uri) throws JDOMException {
        return addElementToProperty(revisionDescriptor, propertyName, E_HREF, uri);
    }
   
    /**
     * Adds the given <code>elementValue</code> as a <code>&lt;elementName&gt;</code> element
     * to the value of the property (specified by the <code>propertyName</code>)
     * of the given NodeRevisionDescriptor (if not already contained).
     *
     * @param      revisionDescriptor  the NodeRevisionDescriptor for which to
     *                                 update the property.
     * @param      propertyName        the name of the property to add the element to.
     * @param      elementName         the name of the element to add.
     * @param      elementValue        the value to add as a <code>&lt;elementName&gt;</code> element.
     * @return     true, if element was added; false, if already contained
     * @throws   JDOMException
     *
     */
    public static boolean addElementToProperty(NodeRevisionDescriptor revisionDescriptor, String propertyName, String elementName, String elementValue) throws JDOMException {
       
        NodeProperty property = revisionDescriptor.getProperty(propertyName);
        if (property == null) {
            property = new NodeProperty(propertyName, null);
        }
        XMLValue xmlValue = new XMLValue((String)property.getValue());
        Iterator iterator = xmlValue.iterator();
        boolean alreadyContained = false;
        Element element = null;
        while (iterator.hasNext() && !alreadyContained) {
            element = (Element)iterator.next();
            if (element.getName().equals(elementName) && element.getText().equals(elementValue)) {
                alreadyContained = true;
            }
        }
        if (!alreadyContained) {
            element = new Element(elementName);
            element.setText(elementValue);
            xmlValue.add(element);
        }
        revisionDescriptor.setProperty(propertyName, xmlValue.toString());
        return !alreadyContained;
    }
   
    /**
     * Removes the <code>&lt;href&gt;</code> element with the given <code>uri</code>
     * from the value of the property (specified by the <code>propertyName</code>)
     * of the given NodeRevisionDescriptor (if contained).
     *
     * @param      revisionDescriptor  the NodeRevisionDescriptor for which to
     *                                 update the property.
     * @param      propertyName        the name of the property to remove the uri from.
     * @param      uri                 the uri of the <code>&lt;href&gt;</code> element
     *                                 to remove.
     * @return     true, if href was removed; false, if not found
     * @throws   JDOMException
     *
     */
    public static boolean removeHrefFromProperty(NodeRevisionDescriptor revisionDescriptor, String propertyName, String uri) throws JDOMException {
        return removeElementFromProperty(revisionDescriptor, propertyName, E_HREF, uri);
    }
   
    /**
     * Removes the <code>&lt;elementName&gt;</code> element with the given <code>elementValue</code>
     * from the value of the property (specified by the <code>propertyName</code>)
     * of the given NodeRevisionDescriptor (if contained).
     *
     * @param      revisionDescriptor  the NodeRevisionDescriptor for which to
     *                                 update the property.
     * @param      propertyName        the name of the property to add the element to.
     * @param      elementName         the name of the element to add.
     * @param      elementValue        the value to add as a <code>&lt;elementName&gt;</code> element.
     * @return     true, if element was removed; false, if not found
     *
     * @throws   JDOMException
     *
     */
    public static boolean removeElementFromProperty(NodeRevisionDescriptor revisionDescriptor, String propertyName, String elementName, String elementValue) throws JDOMException {
       
        NodeProperty property = revisionDescriptor.getProperty(propertyName);
        boolean found = false;
        if (property != null) {
           
            XMLValue xmlValue = new XMLValue((String)property.getValue());
            Iterator iterator = xmlValue.iterator();
            Element element = null;
            while (iterator.hasNext() && !found) {
                element = (Element)iterator.next();
                if (element.getName().equals(elementName) && element.getText().equals(elementValue)) {
                    found = true;
                    iterator.remove();
                }
            }
            if (found) {
                revisionDescriptor.setProperty(propertyName, xmlValue.toString());
            }
        }
        return found;
    }
   
    /**
     * Any leading <code>/</code> in the given <code>uri</code> will be removed.
     *
     * @param      uri  the Uri to remove leading slashes from.
     *
     * @return     the Uri without leading slashes.
     */
    public static String truncateLeadingSlash(String uri) {
       
        if (uri == null) {
            return uri;
        }
       
        while (uri.startsWith("/")) {
            uri = uri.substring(1);
        }
        return uri;
    }
   
    /**
     * Any leading <code>/</code> in the given <code>uri</code> will be removed.
     *
     * @param      uri  the Uri to remove leading slashes from.
     *
     * @return     the Uri without leading slashes.
     */
    public static String computeEtag(String uri, NodeRevisionDescriptor nrd) {
        StringBuffer sb = new StringBuffer();
        sb.append(System.currentTimeMillis()).append('_')
          .append(uri.hashCode()).append('_')
          .append(nrd.getLastModified()).append('_')
          .append(nrd.getContentLength());
        return new String(DigestUtils.md5Hex(sb.toString()));
    }
   
   
}


TOP

Related Classes of org.apache.slide.webdav.util.PropertyHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.