Package org.apache.cocoon.components.source.impl

Source Code of org.apache.cocoon.components.source.impl.SlideSource

/*

============================================================================
                   The Apache Software License, Version 1.1
============================================================================

Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.

Redistribution and use in source and binary forms, with or without modifica-
tion, are permitted provided that the following conditions are met:

1. Redistributions of  source code must  retain the above copyright  notice,
    this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

3. The end-user documentation included with the redistribution, if any, must
    include  the following  acknowledgment:   "This product includes software
    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
    Alternately, this  acknowledgment may  appear in the software itself,  if
    and wherever such third-party acknowledgments normally appear.

4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
    used to  endorse or promote  products derived from  this software without
    prior written permission. For written permission, please contact
    apache@apache.org.

5. Products  derived from this software may not  be called "Apache", nor may
    "Apache" appear  in their name,  without prior written permission  of the
    Apache Software Foundation.

THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
(INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software  consists of voluntary contributions made  by many individuals
on  behalf of the Apache Software  Foundation and was  originally created by
Stefano Mazzocchi  <stefano@apache.org>. For more  information on the Apache
Software Foundation, please see <http://www.apache.org/>.

*/

package org.apache.cocoon.components.source.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Vector;

import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.LogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.cocoon.CascadingIOException;
import org.apache.cocoon.Constants;
import org.apache.cocoon.components.source.*;
import org.apache.cocoon.components.source.helpers.GroupSourcePermission;
import org.apache.cocoon.components.source.helpers.PrincipalSourcePermission;
import org.apache.cocoon.components.source.helpers.SourceCredential;
import org.apache.cocoon.components.source.helpers.SourceLock;
import org.apache.cocoon.components.source.helpers.SourcePermission;
import org.apache.cocoon.components.source.helpers.SourceProperty;
import org.apache.excalibur.source.ModifiableSource;
import org.apache.excalibur.source.MoveableSource;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.TimeStampValidity;
import org.apache.excalibur.xml.dom.DOMParser;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.NamespaceConfig;
import org.apache.slide.common.SlideException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.SlideTokenImpl;
import org.apache.slide.content.*;
import org.apache.slide.lock.Lock;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.macro.Macro;
import org.apache.slide.security.NodePermission;
import org.apache.slide.security.Security;
import org.apache.slide.structure.GroupNode;
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.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
* A sources from jakarta slide repositories.
*
* @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
* @version CVS $Id: SlideSource.java,v 1.7 2003/08/04 03:06:30 joerg Exp $
*/
public class SlideSource extends AbstractLogEnabled
  implements Contextualizable, Composable, Source, ModifiableSource,
             ModifiableTraversableSource, MoveableSource, RestrictableSource,
             LockableSource, InspectableSource, VersionableSource {

    /** Component context */
    private Context context;

    /** Component manager */
    private ComponentManager manager;

    /** Namespace access token. */
    private NamespaceAccessToken nat;

    /** Configuration of namespace */
    private NamespaceConfig config;

    /** Structure helper. */
    private Structure structure;

    /** Content helper. */
    private Content content;

    /** Security helper. */
    private Security security;

    /** Lock helper. */
    private Lock lock;

    /** Macro helper. */
    private Macro macro;

    private CredentialsToken credToken;

    /** Slide token. */
    private SlideToken slideToken;

    /** Pseudo scheme */
    private String scheme = "slide";

    /** The path of the source, which means the URI without the scheme */
    private String path;

    /** Uniform resource ifdentifier */
    private String uri;

    /** Revision number */
    private NodeRevisionNumber revisionNumber;

    private NodeRevisionDescriptors revisionDescriptors = null;
    private NodeRevisionDescriptor revisionDescriptor = null;

    // private String branch;

    private SourceCredential sourcecredential = new SourceCredential("guest",
                                                    "guest");
    private String sourcerevision = null;
    private String sourcerevisionbranch = null;
    private SourceValidity validity = null;

    private SlideSourceOutputStream outputstream;

    /**
     * Create a slide source.
     *
     * @param nat Namespace access token
     * @param scheme Scheme of the source
     * @param path Path of the source.
     * @param sourcecredential Credential, which should be used.
     * @param sourcerevision Revision, which should be used.
     * @param sourcerevisionbranch Branch, which should be used.
     *
     * @throws SourceException If Exception occurs during the initialization.
     */
    public SlideSource(NamespaceAccessToken nat, String scheme, String path,
                       SourceCredential sourcecredential,
                       String sourcerevision,
                       String sourcerevisionbranch) throws SourceException {

        this.sourcecredential = sourcecredential;

        this.credToken = new CredentialsToken(this.sourcecredential.getPrincipal());
        this.nat = nat;
        this.config = this.nat.getNamespaceConfig();
        this.scheme = scheme;
        this.path = path;
        this.uri = scheme+":/"+path;

        this.sourcerevision = sourcerevision;
        this.sourcerevisionbranch = sourcerevisionbranch;

        this.structure = nat.getStructureHelper();
        this.content = nat.getContentHelper();
        this.security = nat.getSecurityHelper();
        this.lock = nat.getLockHelper();
        this.macro = nat.getMacroHelper();

        this.slideToken = new SlideTokenImpl(credToken);

        try {
            this.revisionDescriptors = content.retrieve(this.slideToken,
                                                        this.config.getFilesPath()+
                                                        this.path);

            // Retrieve latest revision descriptor
            this.revisionDescriptor = content.retrieve(slideToken,
                                                       revisionDescriptors);

            this.sourcerevision = this.revisionDescriptor.getRevisionNumber().toString();
            this.sourcerevisionbranch = this.revisionDescriptor.getBranchName();

        } catch (RevisionDescriptorNotFoundException rdnfe) {

            // getLogger().warn("Could not retrieve revision descriptor", rdnfe);

            this.revisionDescriptor = null;
            this.sourcerevision = null;
            this.sourcerevisionbranch = null;
        } catch (ObjectNotFoundException onfe) {
            // getLogger().debug("Source doesn't exist", onfe);
            // ignore
        } catch (SlideException se) {
            throw new SourceException("Access denied for source '"+this.uri+
                                      "'", se);
        }

    }

    /**
     * Pass the Context to the component.
     * This method is called after the LogEnabled.enableLogging() (if present)
     * method and before any other method.
     *
     * @param context The context.
     */
    public void contextualize(Context context) {
        this.context = context;
    }

    /**
     * Pass the ComponentManager to the composer. The Composable implementation
     * should use the specified ComponentManager to acquire the components it needs for execution
     *
     * @param manager The ComponentManager which this Composable uses
     *
     * @throws ComponentException
     */
    public void compose(ComponentManager manager) throws ComponentException {
        this.manager = manager;
    }

    /**
     * Return an <code>InputStream</code> object to read from the source.
     * This is the data at the point of invocation of this method,
     * so if this is Modifiable, you might get different content
     * from two different invocations.
     *
     * @return Input stream for the source.
     *
     * @throws IOException If an IO excepetion occurs.
     * @throws SourceException If an exception occurs.
     */
    public InputStream getInputStream() throws IOException, SourceException {
        try {
            return content.retrieve(slideToken, this.revisionDescriptors,
                                    this.revisionDescriptor).streamContent();
        } catch (SlideException se) {
            throw new SourceException("Could not get source", se);
        }
    }

    /**
     * Return the unique identifer for this source
     *
     * @return System identifier for the source.
     */
    public String getURI() {
        return this.uri;
    }

    /**
     * @see org.apache.excalibur.source.Source#getScheme()
     *
     * @return Scheme of the source.
     */
    public String getScheme() {
        return this.scheme;
    }

    /**
     *  Get the Validity object. This can either wrap the last modification
     *  date or the expires information or...
     *  If it is currently not possible to calculate such an information
     *  <code>null</code> is returned.
     *
     * @return Validity for the source.
     */
    public SourceValidity getValidity() {

        try {
            if ((this.validity==null) && (this.revisionDescriptor!=null)) {
                this.validity = new TimeStampValidity(this.revisionDescriptor.getLastModifiedAsDate().getTime());
            }
        } catch (Exception e) {
            getLogger().debug("Could not create SourceValidity", e);

            return null;
        }
        return this.validity;
    }

    /**
     * Refresh the content of this object after the underlying data
     * content has changed.
     */
    public void refresh() {

        this.validity = null;
    }

    /**
     * The mime-type of the content described by this object.
     * If the source is not able to determine the mime-type by itself
     * this can be null.
     *
     * @return Mime type of the source.
     */
    public String getMimeType() {
        if (this.revisionDescriptor!=null) {
            return this.revisionDescriptor.getContentType();
        }
        return null;
    }

    /**
     * Does this source actually exist ?
     *
     * @return true if the resource exists.
     */
    public boolean exists() {
        try {
            structure.retrieve(this.slideToken,
                               this.config.getFilesPath()+this.path);
        } catch (SlideException e) {
            return false;
        }
        return true;
    }

    /**
     * Get an <code>InputStream</code> where raw bytes can be written to.
     * The signification of these bytes is implementation-dependent and
     * is not restricted to a serialized XML document.
     *
     * @return a stream to write to
     *
     * @throws IOException
     * @throws SourceException
     */
    public OutputStream getOutputStream()
      throws IOException, SourceException {
        if (outputstream==null) {
            outputstream = new SlideSourceOutputStream();
            outputstream.enableLogging(getLogger());
        }
        return outputstream;
    }

    /**
     * Can the data sent to an <code>OutputStream</code> returned by
     * {@link #getOutputStream()} be cancelled ?
     *
     * @param stream The ouput stream, which should be cancelled.
     * @return true if the stream can be cancelled
     */
    public boolean canCancel(OutputStream stream) {
        return outputstream.canCancel();
    }

    /**
     * Cancel the data sent to an <code>OutputStream</code> returned by
     * {@link #getOutputStream()}.
     * <p>
     * After cancel, the stream should no more be used.
     *
     * @param stream The ouput stream, which should be cancelled.
     *
     * @throws SourceException If the ouput stream can't be cancelled.
     */
    public void cancel(OutputStream stream) throws SourceException {
        if (outputstream==stream) {
            try {
                outputstream.cancel();
            } catch (Exception e) {
                throw new SourceException("Could not cancel output stream",
                                          e);
            }
        }
    }

    /**
     * A helper can the getOutputStream() method
     */
    public class SlideSourceOutputStream extends ByteArrayOutputStream
      implements LogEnabled {
        private boolean isClosed = false;
        private Logger logger = null;

        /**
         * Provide component with a logger.
         *
         * @param logger the logger
         */
        public void enableLogging(Logger logger) {
            this.logger = logger;
        }

        /**
         *
         *
         * @throws IOException
         */
        public void close() throws IOException {
            super.close();

            byte[] bytes = new byte[0]; // must be initialized

            try {
                NodeRevisionContent revisionContent = new NodeRevisionContent();

                bytes = toByteArray();
                revisionContent.setContent(bytes);

                if (revisionDescriptor==null) {
                    revisionDescriptor = new NodeRevisionDescriptor(0);

                    String resourceName = config.getFilesPath()+path;
                    int lastSlash = resourceName.lastIndexOf('/');

                    if (lastSlash!=-1) {
                        resourceName = resourceName.substring(lastSlash+1);
                    }
                    revisionDescriptor.setName(resourceName);
                }

                revisionDescriptor.setContentLength(bytes.length);

                // Last modification date
                revisionDescriptor.setLastModified(new Date());

                nat.begin();
                if (revisionNumber==null) {
                    content.create(slideToken, config.getFilesPath()+path,
                                   revisionDescriptor, null);
                }
                content.store(slideToken, config.getFilesPath()+path,
                              revisionDescriptor, revisionContent);
                try {
                    nat.commit();
                } catch (Exception cme) {
                    throw new CascadingIOException("Could not commit the transaction",
                                                   cme);
                }

            } catch (ObjectNotFoundException e) {

                // Todo : Check to see if parent exists
                SubjectNode subject = new SubjectNode();

                try {
                    // Creating an object
                    structure.create(slideToken, subject,
                                     config.getFilesPath()+path);
                } catch (SlideException se) {
                    throw new CascadingIOException(se);
                }

                NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(bytes.length);

                // Resource type
                revisionDescriptor.setResourceType("");

                // Source
                revisionDescriptor.setSource("");

                // Get content language
                revisionDescriptor.setContentLanguage("en");

                // Get content length
                revisionDescriptor.setContentLength(bytes.length);

                // Get content type
                String contentType = null;

                try {
                    contentType = ((org.apache.cocoon.environment.Context) context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT)).getMimeType(path);
                } catch (ContextException ce) {
                    this.logger.warn("Could not get context to determine the mime type.");
                }
                if (contentType==null) {
                    contentType = "application/octet-stream";
                }
                revisionDescriptor.setContentType(contentType);

                // Last modification date
                revisionDescriptor.setLastModified(new Date());

                // Owner
                revisionDescriptor.setOwner(slideToken.getCredentialsToken().getPublicCredentials());

                // Creating revisionDescriptor associated with the object
                NodeRevisionContent revisionContent = new NodeRevisionContent();

                revisionContent.setContent(bytes);

                try {
                    content.create(slideToken, config.getFilesPath()+path,
                                   revisionDescriptor, revisionContent);

                    try {
                        nat.commit();
                    } catch (Exception cme) {
                        throw new CascadingIOException("Could not commit the transaction",
                                                       cme);

                    }
                } catch (SlideException se) {

                    try {
                        nat.rollback();
                    } catch (Exception rbe) {
                        this.logger.warn("Could not rollback the transaction.",
                                         rbe);
                    }

                    throw new CascadingIOException("Could not create source",
                                                   se);
                }

            } catch (Exception e) {
                if (e instanceof IOException) {
                    throw (IOException) e;
                }
                throw new CascadingIOException("Could not create source", e);
            } finally {

                this.isClosed = true;
            }
        }

        /**
         * Can the data sent to an <code>OutputStream</code> returned by
         * {@link #getOutputStream()} be cancelled ?
         *
         * @return true if the stream can be cancelled
         */
        public boolean canCancel() {
            return !this.isClosed;
        }

        /**
         * Cancel the data sent to an <code>OutputStream</code> returned by
         * {@link #getOutputStream()}.
         * <p>
         * After cancel, the stream should no more be used.
         *
         */
        public void cancel() throws Exception {
            if (this.isClosed) {
                throw new IllegalStateException("Cannot cancel : outputstrem is already closed");
            }

            this.isClosed = true;
            super.close();
        }
    }

    /**
     * Move the current source to a specified destination.
     *
     * @param source
     *
     * @throws SourceException If an exception occurs during
     *                         the move.
     */
    public void moveTo(Source source) throws SourceException {
        if (source instanceof SlideSource) {
            try {
                nat.begin();
                this.macro.move(slideToken,
                                this.config.getFilesPath()+this.path,
                                this.config.getFilesPath()+
                                ((SlideSource) source).path);
                nat.commit();
            } catch (Exception se) {
                try {
                    nat.rollback();
                } catch (Exception rbe) {
                    getLogger().error("Rollback failed for moving source", rbe);
                }
                throw new SourceException("Could not move source.", se);
            }
        } else {
            org.apache.excalibur.source.SourceUtil.move(this, source);
        }
    }

    /**
     * Copy the current source to a specified destination.
     *
     * @param source
     *
     * @throws SourceException If an exception occurs during
     *                         the copy.
     */
    public void copyTo(Source source) throws SourceException {
        if (source instanceof SlideSource) {
            try {
                nat.begin();
                this.macro.copy(slideToken,
                                this.config.getFilesPath()+this.path,
                                this.config.getFilesPath()+
                                ((SlideSource) source).path);
                nat.commit();
            } catch (Exception se) {
                try {
                    nat.rollback();
                } catch (Exception rbe) {
                    getLogger().error("Rollback failed for moving source", rbe);
                }
                throw new SourceException("Could not move source.", se);
            }
        } else {
            org.apache.excalibur.source.SourceUtil.copy(this, source);
        }
    }

    /**
     * Delete the source.
     *
     * @return True, if the delete operation was successful.
     */
    public void delete() {
        try {
            nat.begin();
            this.macro.delete(slideToken,
                              this.config.getFilesPath()+this.path);
            nat.commit();
        } catch (Exception se) {
            getLogger().error("Could not delete source.",se);
            try {
                nat.rollback();
            } catch (Exception rbe) {
                getLogger().error("Rollback failed for moving source", rbe);
            }
        }
    }

    /**
     * Return the content length of the content or -1 if the length is
     * unknown.
     *
     * @return Content length of the source.
     */
    public long getContentLength() {
        if (revisionDescriptor!=null) {
            return revisionDescriptor.getContentLength();
        }

        return -1;
    }

    /**
     * Get the last modification date of the source or 0 if it
     * is not possible to determine the date.
     *
     * @return Last modified date of the source.
     */
    public long getLastModified() {
        if (revisionDescriptor!=null) {
            return revisionDescriptor.getLastModifiedAsDate().getTime();
        }
        return 0;
    }

    /**
     * Tests whether a resource is a collection resource.
     *
     * @return true if the descriptor represents a collection, false otherwise
     *
     * @throws SourceException If an exception occurs.
     */
    public boolean isSourceCollection() throws SourceException {

        boolean result = false;

        if (revisionDescriptor==null) {
            return true;
        }

        NodeProperty property = revisionDescriptor.getProperty("resourcetype");

        if ((property!=null) &&
            (property.getValue().equals("<collection/>"))) {
            result = true;
        }

        return result;
    }

    /**
     * Returns the count of child sources.
     *
     * @return Count of child sources.
     *
     * @throws SourceException If an exception occurs.
     */
    public int getChildSourceCount() throws SourceException {
        try {
            int i = 0;

            for (Enumeration children = structure.retrieve(this.slideToken,
                this.config.getFilesPath()+this.path).enumerateChildren();
                children.hasMoreElements(); )
                if (((String) children.nextElement()).startsWith(this.config.getFilesPath())) {
                    i++;
                }
            return i;
        } catch (SlideException se) {
            throw new SourceException("Could not get children", se);
        }
    }

    /**
     * Return the system id of a child source.
     *
     * @param index Index of the child
     *
     * @return System identifier of the child source.
     *
     * @throws SourceException If an exception occurs.
     */
    public String getChildSource(int index) throws SourceException {
        try {
            int i = 0;
            String child;

            for (Enumeration children = structure.retrieve(this.slideToken,
                this.config.getFilesPath()+this.path).enumerateChildren();
                children.hasMoreElements(); ) {
                child = (String) children.nextElement();

                if (child.startsWith(this.config.getFilesPath())) {
                    if (i==index) {
                        return scheme+":/"+
                               child.substring(this.config.getFilesPath().length());
                    }

                    i++;
                }
            }
            return null;
        } catch (SlideException se) {
            throw new SourceException("Could not get children", se);
        }
    }

    /**
     * Return the system if of the parent source. The method should return
     * null if the source hasn't a parent.
     *
     * @return System identifier of the parent source.
     */
    public String getParentSource() {
        if ((this.path==null) || (this.path.length()<=1)) {
            return null;
        }

        if (this.path.endsWith("/")) {
            return scheme+":/"+
                   this.path.substring(0, this.path.substring(0,
                       this.path.length()-1).lastIndexOf("/"));
        }

        return scheme+":/"+this.path.substring(0, this.path.lastIndexOf("/"));
    }

    /**
     * Create a collection of sources.
     *
     * @param collectionname Name of the collectiom, which
     *                       should be created.
     *
     * @throws SourceException if an exception occurs.
     */
    public void createCollection(String collectionname)
      throws SourceException {

        SubjectNode collection = new SubjectNode();
        NodeRevisionDescriptor revisionDescriptor = new NodeRevisionDescriptor(0);

        // Resource type
        revisionDescriptor.setResourceType("<collection/>");

        // Creation date
        revisionDescriptor.setCreationDate(new Date());

        // Last modification date
        revisionDescriptor.setLastModified(new Date());

        // Content length name
        revisionDescriptor.setContentLength(0);

        // Source
        revisionDescriptor.setSource("");

        // Owner
        revisionDescriptor.setOwner(slideToken.getCredentialsToken().getPublicCredentials());

        try {
            nat.begin();
            structure.create(slideToken, collection,
                             this.config.getFilesPath()+this.path+"/"+
                             collectionname);
            content.create(slideToken,
                           this.config.getFilesPath()+this.path+"/"+
                           collectionname, revisionDescriptor, null);
            nat.commit();
        } catch (Exception se) {
            try {
                nat.rollback();
            } catch (Exception rbe) {
                getLogger().error("Rollback failed for creating collection", rbe);
            }
            throw new SourceException("Could not create collection.", se);
        }
    }

    /**
     * Get the current credential for the source
     *
     * @return Return the current used credential;
     *
     * @throws SourceException If an exception occurs.
     */
    public SourceCredential getSourceCredential() throws SourceException {
        return this.sourcecredential;
    }

    /**
     * Set the credential for the source
     *
     * @param sourcecredential The credential, which should be used.
     *
     * @throws SourceException If an exception occurs.
     */
    public void setSourceCredential(SourceCredential sourcecredential)
      throws SourceException {
        if ((sourcecredential==null) ||
            (sourcecredential.getPrincipal()==null) ||
            (sourcecredential.getPrincipal().length()<=0)) {
            return;
        }

        this.sourcecredential = sourcecredential;
        this.credToken = new CredentialsToken(this.sourcecredential.getPrincipal());
        this.slideToken = new SlideTokenImpl(credToken);
    }

    /**
     * Add a permission to this source
     *
     * @param sourcepermission Permission, which should be set
     *
     * @throws SourceException If an exception occurs during this operation
     **/
    public void addSourcePermission(SourcePermission sourcepermission)
      throws SourceException {

        NamespaceConfig config = this.nat.getNamespaceConfig();

        String subject = null;

        if (sourcepermission instanceof PrincipalSourcePermission) {
            subject = config.getUsersPath()+"/"+
                      ((PrincipalSourcePermission) sourcepermission).getPrincipal();

            // Test if principal exists
            try {
                ObjectNode objectnode = structure.retrieve(this.slideToken,
                                                           subject);

                if ( !(objectnode instanceof SubjectNode)) {
                    throw new SourceException("Principal '"+
                                              ((PrincipalSourcePermission) sourcepermission).getPrincipal()+
                                              "' doesn't exists");
                }
            } catch (SlideException se) {
                throw new SourceException("Could not retrieve object for principal '"+
                                          ((PrincipalSourcePermission) sourcepermission).getPrincipal()+
                                          "'", se);
            }

        } else if (sourcepermission instanceof GroupSourcePermission) {
            subject = config.getUsersPath()+"/"+
                      ((GroupSourcePermission) sourcepermission).getGroup();

            // Test if group exists
            try {
                ObjectNode objectnode = structure.retrieve(this.slideToken,
                                                           subject);

                if ( !(objectnode instanceof GroupNode)) {
                    throw new SourceException("Group '"+
                                              ((GroupSourcePermission) sourcepermission).getGroup()+
                                              "' doesn't exists");
                }
            } catch (SlideException se) {
                throw new SourceException("Could not retrieve object for group '"+
                                          ((GroupSourcePermission) sourcepermission).getGroup()+
                                          "'", se);
            }

            subject = "+"+subject; // Additional '+' to expand the group
        } else {
            throw new SourceException("Does't support category of permission");
        }

        boolean negative = sourcepermission.isNegative();
        boolean inheritable = sourcepermission.isInheritable();

        if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_ALL)) {
            addPermission(subject, "/", negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ)) {
            addPermission(subject, config.getReadObjectAction().getUri(),
                          negative, inheritable);
            addPermission(subject, config.getReadLocksAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getReadRevisionMetadataAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getReadRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_SOURCE)) {
            addPermission(subject, config.getReadObjectAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_LOCKS)) {
            addPermission(subject, config.getReadLocksAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_PROPERTY)) {
            addPermission(subject,
                          config.getReadRevisionMetadataAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_CONTENT)) {
            addPermission(subject,
                          config.getReadRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_WRITE)) {
            addPermission(subject, config.getCreateObjectAction().getUri(),
                          negative, inheritable);
            addPermission(subject, config.getRemoveObjectAction().getUri(),
                          negative, inheritable);
            addPermission(subject, config.getLockObjectAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getCreateRevisionMetadataAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getModifyRevisionMetadataAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getRemoveRevisionMetadataAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getCreateRevisionContentAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getModifyRevisionContentAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getRemoveRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_SOURCE)) {
            addPermission(subject, config.getCreateObjectAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_SOURCE)) {
            addPermission(subject, config.getRemoveObjectAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_LOCK_SOURCE)) {
            addPermission(subject, config.getLockObjectAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_PROPERTY)) {
            addPermission(subject,
                          config.getCreateRevisionMetadataAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_MODIFY_PROPERTY)) {
            addPermission(subject,
                          config.getModifyRevisionMetadataAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_PROPERTY)) {
            addPermission(subject,
                          config.getRemoveRevisionMetadataAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_CONTENT)) {
            addPermission(subject,
                          config.getCreateRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_MODIFY_CONTENT)) {
            addPermission(subject,
                          config.getModifyRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_CONTENT)) {
            addPermission(subject,
                          config.getRemoveRevisionContentAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_ACL)) {
            addPermission(subject,
                          config.getReadPermissionsAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_WRITE_ACL)) {
            addPermission(subject,
                          config.getGrantPermissionAction().getUri(),
                          negative, inheritable);
            addPermission(subject,
                          config.getRevokePermissionAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_GRANT_PERMISSION)) {
            addPermission(subject,
                          config.getGrantPermissionAction().getUri(),
                          negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REVOKE_PERMISSION)) {
            addPermission(subject,
                          config.getRevokePermissionAction().getUri(),
                          negative, inheritable);
        }
    }

    /**
     * Add permission to the list of permissions.
     *
     * @param subject Subject of the permission.
     * @param action Action for the subject.
     * @param negative If the permission, should be allowed or denied.
     * @param inheritable If the permission is inheritable.
     *
     * @throws SourceException If an exception occurs.
     */
    private void addPermission(String subject, String action,
                               boolean negative,
                               boolean inheritable) throws SourceException {
        try {
            NodePermission permission = new NodePermission(this.config.getFilesPath()+
                                            this.path, subject, action,
                                                       inheritable, negative);

            nat.begin();
            this.security.grantPermission(this.slideToken, permission);

            // Last modification date
            revisionDescriptor.setLastModified(new Date());

            content.store(slideToken, this.config.getFilesPath()+this.path,
                          revisionDescriptor, null);
            nat.commit();
        } catch (Exception se) {
            try {
                nat.rollback();
            } catch (Exception rbe) {
                getLogger().error("Rollback failed for granting permission", rbe);
            }  
            throw new SourceException("Couldn't grant permission", se);
        }
    }

    /**
     * Remove a permission from this source
     *
     * @param sourcepermission Permission, which should be removed
     *
     * @throws SourceException If an exception occurs during this operation
     **/
    public void removeSourcePermission(SourcePermission sourcepermission)
      throws SourceException {

        NamespaceConfig config = this.nat.getNamespaceConfig();

        String subject = null;

        if (sourcepermission instanceof PrincipalSourcePermission) {
            subject = config.getUsersPath()+"/"+
                      ((PrincipalSourcePermission) sourcepermission).getPrincipal();

            // Test if principal exists
            try {
                ObjectNode objectnode = structure.retrieve(this.slideToken,
                                                           subject);

                if ( !(objectnode instanceof SubjectNode)) {
                    throw new SourceException("Principal '"+
                                              ((PrincipalSourcePermission) sourcepermission).getPrincipal()+
                                              "' doesn't exists");
                }
            } catch (SlideException se) {
                throw new SourceException("Could not retrieve object for principal '"+
                                          ((PrincipalSourcePermission) sourcepermission).getPrincipal()+
                                          "'", se);
            }

        } else if (sourcepermission instanceof GroupSourcePermission) {
            subject = config.getUsersPath()+"/"+
                      ((GroupSourcePermission) sourcepermission).getGroup();

            // Test if group exists
            try {
                ObjectNode objectnode = structure.retrieve(this.slideToken,
                                                           subject);

                if ( !(objectnode instanceof GroupNode)) {
                    throw new SourceException("Group '"+
                                              ((GroupSourcePermission) sourcepermission).getGroup()+
                                              "' doesn't exists");
                }
            } catch (SlideException se) {
                throw new SourceException("Could not retrieve object for group '"+
                                          ((GroupSourcePermission) sourcepermission).getGroup()+
                                          "'", se);
            }

            subject = "+"+subject; // Additional '+' to expand the group
        } else {
            throw new SourceException("Does't support category of permission");
        }

        boolean negative = sourcepermission.isNegative();
        boolean inheritable = sourcepermission.isInheritable();

        if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_ALL)) {
            removePermission(subject, "/", negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ)) {
            removePermission(subject, config.getReadObjectAction().getUri(),
                             negative, inheritable);
            removePermission(subject, config.getReadLocksAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getReadRevisionMetadataAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getReadRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_SOURCE)) {
            removePermission(subject, config.getReadObjectAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_LOCKS)) {
            removePermission(subject, config.getReadLocksAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_PROPERTY)) {
            removePermission(subject,
                             config.getReadRevisionMetadataAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_CONTENT)) {
            removePermission(subject,
                             config.getReadRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_WRITE)) {
            removePermission(subject,
                             config.getCreateObjectAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getRemoveObjectAction().getUri(),
                             negative, inheritable);
            removePermission(subject, config.getLockObjectAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getCreateRevisionMetadataAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getModifyRevisionMetadataAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getRemoveRevisionMetadataAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getCreateRevisionContentAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getModifyRevisionContentAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getRemoveRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_SOURCE)) {
            removePermission(subject,
                             config.getCreateObjectAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_SOURCE)) {
            removePermission(subject,
                             config.getRemoveObjectAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_LOCK_SOURCE)) {
            removePermission(subject, config.getLockObjectAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_PROPERTY)) {
            removePermission(subject,
                             config.getCreateRevisionMetadataAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_MODIFY_PROPERTY)) {
            removePermission(subject,
                             config.getModifyRevisionMetadataAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_PROPERTY)) {
            removePermission(subject,
                             config.getRemoveRevisionMetadataAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_CREATE_CONTENT)) {
            removePermission(subject,
                             config.getCreateRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_MODIFY_CONTENT)) {
            removePermission(subject,
                             config.getModifyRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REMOVE_CONTENT)) {
            removePermission(subject,
                             config.getRemoveRevisionContentAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_READ_ACL)) {
            removePermission(subject,
                             config.getReadPermissionsAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_WRITE_ACL)) {
            removePermission(subject,
                             config.getGrantPermissionAction().getUri(),
                             negative, inheritable);
            removePermission(subject,
                             config.getRevokePermissionAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_GRANT_PERMISSION)) {
            removePermission(subject,
                             config.getGrantPermissionAction().getUri(),
                             negative, inheritable);
        } else if (sourcepermission.getPrivilege().equals(SourcePermission.PRIVILEGE_REVOKE_PERMISSION)) {
            removePermission(subject,
                             config.getRevokePermissionAction().getUri(),
                             negative, inheritable);
        }
    }

    /**
     * Remove a permission from the list of permissions.
     *
     * @param subject Subject of the permission.
     * @param action Action for the subject.
     * @param negative If the permission, should be allowed or denied.
     * @param inheritable If the permission is inheritable.
     *
     * @throws SourceException If an exception occurs.
     */
    private void removePermission(String subject, String action,
                                  boolean negative,
                                  boolean inheritable)
                                    throws SourceException {
        try {
            NodePermission permission = new NodePermission(this.config.getFilesPath()+
                                            this.path, subject, action,
                                                       inheritable, negative);

            nat.begin();
            this.security.revokePermission(this.slideToken, permission);

            // Last modification date
            revisionDescriptor.setLastModified(new Date());

            content.store(slideToken, this.config.getFilesPath()+this.path,
                          revisionDescriptor, null);
            nat.commit();
        } catch (Exception se) {
            try {
                nat.rollback();
            } catch (Exception rbe) {
                getLogger().error("Rollback failed for removing permission", rbe);
            }
            throw new SourceException("Couldn't remove permission", se);
        }
    }

    /**
     * Returns a list of the existing permissions.
     * Based on the implementation of org.apache.slide.webdav.util.PropertyHelper .
     *
     * @return Array of SourcePermission
     *
     * @throws SourceException If an exception occurs.
     **/
    public SourcePermission[] getSourcePermissions() throws SourceException {
        try {

            NamespaceConfig config = this.nat.getNamespaceConfig();

            ObjectNode current = structure.retrieve(this.slideToken,
                                                    this.config.getFilesPath()+
                                                    this.path);

            security.checkCredentials(this.slideToken, current,
                                      config.getReadPermissionsAction());

            String userspath = config.getUsersPath();

            // read
            String readObjectUri = config.getReadObjectAction().getUri();
            String readRevisionMetadataUri = config.getReadRevisionMetadataAction().getUri();
            String readRevisionContentUri = config.getReadRevisionContentAction().getUri();

            // write
            String createObjectUri = config.getCreateObjectAction().getUri();
            String removeObjectUri = config.getRemoveObjectAction().getUri();
            String lockObjectUri = config.getLockObjectAction().getUri();
            String readLocksUri = config.getReadLocksAction().getUri();
            String createRevisionMetadataUri = config.getCreateRevisionMetadataAction().getUri();
            String modifyRevisionMetadataUri = config.getModifyRevisionMetadataAction().getUri();
            String removeRevisionMetadataUri = config.getRemoveRevisionMetadataAction().getUri();
            String createRevisionContentUri = config.getCreateRevisionContentAction().getUri();
            String modifyRevisionContentUri = config.getModifyRevisionContentAction().getUri();
            String removeRevisionContentUri = config.getRemoveRevisionContentAction().getUri();

            // read-acl
            String readPermissionsUri = config.getReadPermissionsAction().getUri();

            // write-acl
            String grantPermissionUri = config.getGrantPermissionAction().getUri();
            String revokePermissionUri = config.getRevokePermissionAction().getUri();

            boolean inheritedPermissions = false;
            Vector permissions = new Vector();

            ArrayList sourcepermissions = new ArrayList();

            while (current!=null) {
                try {
                    // put all permissions in a list
                    permissions.clear();
                    Enumeration aclList = security.enumeratePermissions(this.slideToken,
                                              current);

                    while (aclList.hasMoreElements()) {
                        NodePermission permission = (NodePermission) aclList.nextElement();

                        // if we are processing inheritedPermissions (from parent and up)
                        // then the permission should be inheritable
                        if (inheritedPermissions &&
                            !permission.isInheritable()) {
                            // continue with next permission
                            continue;
                        }
                        permissions.add(permission);
                    }

                    // start combining and writing the permissions
                    while (permissions.size()>0) {
                        NodePermission permission = (NodePermission) permissions.get(0);

                        permissions.remove(0);

                        String principal = permission.getSubjectUri();
                        boolean negative = permission.isNegative();

                        String action = permission.getActionUri();

                        // read
                        boolean isReadObject = readObjectUri.startsWith(action);
                        boolean isReadLocks = readLocksUri.startsWith(action);
                        boolean isReadRevisionMetadata = readRevisionMetadataUri.startsWith(action);
                        boolean isReadRevisionContent = readRevisionContentUri.startsWith(action);

                        // write
                        boolean isCreateObject = createObjectUri.startsWith(action);
                        boolean isRemoveObject = removeObjectUri.startsWith(action);
                        boolean isLockObject = lockObjectUri.startsWith(action);
                        boolean isCreateRevisionMetadata = createRevisionMetadataUri.startsWith(action);
                        boolean isModifyRevisionMetadata = modifyRevisionMetadataUri.startsWith(action);
                        boolean isRemoveRevisionMetadata = removeRevisionMetadataUri.startsWith(action);
                        boolean isCreateRevisionContent = createRevisionContentUri.startsWith(action);
                        boolean isModifyRevisionContent = modifyRevisionContentUri.startsWith(action);
                        boolean isRemoveRevisionContent = removeRevisionContentUri.startsWith(action);

                        // read-acl
                        boolean isReadPermissions = readPermissionsUri.startsWith(action);

                        // write-acl
                        boolean isGrantPermission = grantPermissionUri.startsWith(action);
                        boolean isRevokePermission = revokePermissionUri.startsWith(action);

                        // check the other permissions to combine them
                        // (if they are for the same principal/negative)
                        for (int i = 0; i<permissions.size(); i++) {
                            NodePermission otherPermission = (NodePermission) permissions.get(i);

                            if (principal.equals(otherPermission.getSubjectUri()) &&
                                (negative==otherPermission.isNegative())) {
                                permissions.remove(i);
                                i--; // because we removed the current one

                                action = otherPermission.getActionUri();

                                // read
                                isReadObject |= readObjectUri.startsWith(action);
                                isReadLocks |= readLocksUri.startsWith(action);
                                isReadRevisionMetadata |= readRevisionMetadataUri.startsWith(action);
                                isReadRevisionContent |= readRevisionContentUri.startsWith(action);

                                // write
                                isCreateObject |= createObjectUri.startsWith(action);
                                isRemoveObject |= removeObjectUri.startsWith(action);
                                isLockObject |= lockObjectUri.startsWith(action);
                                isCreateRevisionMetadata |= createRevisionMetadataUri.startsWith(action);
                                isModifyRevisionMetadata |= modifyRevisionMetadataUri.startsWith(action);
                                isRemoveRevisionMetadata |= removeRevisionMetadataUri.startsWith(action);
                                isCreateRevisionContent |= createRevisionContentUri.startsWith(action);
                                isModifyRevisionContent |= modifyRevisionContentUri.startsWith(action);
                                isRemoveRevisionContent |= removeRevisionContentUri.startsWith(action);

                                // read-acl
                                isReadPermissions |= readPermissionsUri.startsWith(action);

                                // write-acl
                                isGrantPermission |= grantPermissionUri.startsWith(action);
                                isRevokePermission |= revokePermissionUri.startsWith(action);
                            }
                        }

                        // WebDAV privileges
                        boolean isRead = isReadObject && isReadLocks &&
                                         isReadRevisionMetadata &&
                                         isReadRevisionContent;

                        boolean isWrite = isCreateObject && isRemoveObject &&
                                          isLockObject &&
                                          isCreateRevisionMetadata &&
                                          isModifyRevisionMetadata &&
                                          isRemoveRevisionMetadata &&
                                          isCreateRevisionContent &&
                                          isModifyRevisionContent &&
                                          isRemoveRevisionContent;

                        boolean isReadAcl = isReadPermissions;

                        boolean isWriteAcl = isGrantPermission &&
                                             isRevokePermission;

                        boolean isAll = isRead && isWrite && isReadAcl &&
                                        isWriteAcl;

                        SourcePermission sourcepermission = null;

                        if (principal.equals("~")) {
                            sourcepermission = new PrincipalSourcePermission(PrincipalSourcePermission.PRINCIPAL_SELF,
                                null, inheritedPermissions, negative);
                        } else if (principal.equals("nobody")) {
                            sourcepermission = new PrincipalSourcePermission(PrincipalSourcePermission.PRINCIPAL_GUEST,
                                null, inheritedPermissions, negative);
                        } else if (principal.equals(userspath)) {
                            sourcepermission = new PrincipalSourcePermission(PrincipalSourcePermission.PRINCIPAL_ALL,
                                null, inheritedPermissions, negative);
                        } else if (principal.startsWith(userspath+"/")) {
                            sourcepermission = new PrincipalSourcePermission(principal.substring(userspath.length()+
                                1), null, inheritedPermissions, negative);
                        } else if (principal.startsWith("+"+userspath+"/")) {
                            sourcepermission = new GroupSourcePermission(principal.substring(userspath.length()+
                                2), null, inheritedPermissions, negative);
                        } else {
                            sourcepermission = new PrincipalSourcePermission(principal,
                                null, inheritedPermissions, negative);
                        }

                        if (isAll) {
                            sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_ALL);
                        } else {
                            if (isRead) {
                                sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ);
                            } else {
                                if (isReadObject) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ_SOURCE);
                                }
                                if (isReadLocks) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ_LOCKS);
                                }
                                if (isReadRevisionMetadata) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ_PROPERTY);
                                }
                                if (isReadRevisionContent) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ_CONTENT);
                                }
                            }
                            if (isWrite) {
                                sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_WRITE);
                            } else {
                                if (isCreateObject) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_CREATE_SOURCE);
                                }
                                if (isRemoveObject) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_REMOVE_SOURCE);
                                }
                                if (isLockObject) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_LOCK_SOURCE);
                                }
                                if (isCreateRevisionMetadata) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_CREATE_PROPERTY);
                                }
                                if (isModifyRevisionMetadata) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_MODIFY_PROPERTY);
                                }
                                if (isRemoveRevisionMetadata) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_REMOVE_PROPERTY);
                                }
                                if (isCreateRevisionContent) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_CREATE_CONTENT);
                                }
                                if (isModifyRevisionContent) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_MODIFY_CONTENT);
                                }
                                if (isRemoveRevisionContent) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_REMOVE_CONTENT);
                                }
                            }
                            if (isReadAcl) {
                                sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_READ_ACL);
                            }
                            if (isWriteAcl) {
                                sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_WRITE_ACL);
                            } else {
                                if (isGrantPermission) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_GRANT_PERMISSION);
                                }
                                if (isRevokePermission) {
                                    sourcepermission.setPrivilege(SourcePermission.PRIVILEGE_REVOKE_PERMISSION);
                                }
                            }
                        }

                        sourcepermissions.add(sourcepermission);
                    }
                } catch (SlideException se) {
                    throw new SourceException("Exception eccurs while retrieveing source permission",
                                              se);
                }

                inheritedPermissions = true;

                try {
                    current = structure.getParent(this.slideToken, current);
                } catch (SlideException e) {
                    break;
                }
            }

            SourcePermission[] sourcepermissionArray = new SourcePermission[sourcepermissions.size()];

            return (SourcePermission[]) sourcepermissions.toArray((Object[]) sourcepermissionArray);

        } catch (SlideException se) {
            throw new SourceException("Exception eccurs while retrieveing source permission",
                                      se);
        }
    }

    /**
     * Add a lock to this source
     *
     * @param sourcelock Lock, which should be added
     *
     * @throws SourceException If an exception occurs during this operation
     */
    public void addSourceLocks(SourceLock sourcelock) throws SourceException {
        throw new SourceException("Operation not yet supported");
    }

    /**
     * Returns a enumeration of the existing locks
     *
     * @return Enumeration of SourceLock
     *
     * @throws SourceException If an exception occurs.
     */
    public Enumeration getSourceLocks() throws SourceException {
        try {
            Vector sourcelocks = new Vector();

            NodeLock lock;

            for (Enumeration locks = this.lock.enumerateLocks(this.slideToken,
                this.config.getFilesPath()+this.path, false);
                locks.hasMoreElements(); ) {
                lock = (NodeLock) locks.nextElement();

                sourcelocks.addElement(new SourceLock(lock.getSubjectUri(),
                                                      lock.getTypeUri(),
                                                      lock.getExpirationDate(),
                                                      lock.isInheritable(),
                                                      lock.isExclusive()));
            }

            return sourcelocks.elements();
        } catch (SlideException se) {
            throw new SourceException("Could not retrieve locks", se);
        }
    }

    /**
     * Sets a property for a source.
     *
     * @param sourceproperty Property of the source
     *
     * @throws SourceException If an exception occurs during this operation
     */
    public void setSourceProperty(SourceProperty sourceproperty)
      throws SourceException {
        getLogger().debug("Set source property");
        try {
            revisionDescriptor.setProperty(sourceproperty.getName(),
                                           sourceproperty.getNamespace(),
                                           sourceproperty.getValueAsString());

            // Last modification date
            revisionDescriptor.setLastModified(new Date());

            nat.begin();
            content.store(slideToken, this.config.getFilesPath()+this.path,
                          revisionDescriptor, null);
            nat.commit();
        } catch (Exception se) {
            try {
                nat.rollback();
            } catch (Exception rbe) {
                getLogger().error("Rollback failed for setting a source property", rbe);
            }
            throw new SourceException("Could not set source property", se);
        }
    }

    /**
     * Returns a property from a source.
     *
     * @param namespace Namespace of the property
     * @param name Name of the property
     *
     * @return Property of the source.
     *
     * @throws SourceException If an exception occurs.
     */
    public SourceProperty getSourceProperty(String namespace,
                                            String name)
                                              throws SourceException {

        if (revisionDescriptor==null) {
            return null;
        }

        final String quote = "\"";
        NodeProperty property = revisionDescriptor.getProperty(name, namespace);

        if (property==null) {
            return null;
        }

        String pre = "<"+name+" xmlns="+quote+namespace+quote+" >";
        String post = "</"+name+" >";

        StringReader reader = new StringReader(pre+property.getValue().toString()+
                                               post);
        InputSource src = new InputSource(reader);

        DOMParser parser = null;
        Document doc = null;

        try {
            parser = (DOMParser) this.manager.lookup(DOMParser.ROLE);
            doc = parser.parseDocument(src);
        } catch (Exception e) {
            throw new SourceException("Could not parse property", e);
        } finally {
            this.manager.release((Component) parser);
        }

        return new SourceProperty(doc.getDocumentElement());
    }

    /**
     * Returns a enumeration of the properties
     *
     * @return Enumeration of SourceProperty
     *
     * @throws SourceException If an exception occurs.
     */
    public SourceProperty[] getSourceProperties() throws SourceException {

        if (revisionDescriptor==null) {
            return new SourceProperty[0];
        }

        Vector sourceproperties = new Vector();

        DOMParser parser = null;
        String xml = "";

        try {
            parser = (DOMParser) this.manager.lookup(DOMParser.ROLE);
            final String quote = "\"";

            for (Enumeration e = revisionDescriptor.enumerateProperties();
                e.hasMoreElements(); ) {
                NodeProperty property = (NodeProperty) e.nextElement();
                String name = property.getName();
                String namespace = property.getNamespace();
                String pre = "<"+name+" xmlns="+quote+namespace+quote+" >";
                String post = "</"+name+" >";

                xml = pre+property.getValue().toString()+post;
                StringReader reader = new StringReader(xml);

                Document doc = parser.parseDocument(new InputSource(reader));

                SourceProperty srcProperty = new SourceProperty(doc.getDocumentElement());

                sourceproperties.addElement(srcProperty);
            }
        } catch (Exception e) {
            throw new SourceException("Could not parse property "+xml, e);
        } finally {
            this.manager.release((Component) parser);
        }

        SourceProperty[] sourcepropertiesArray = new SourceProperty[sourceproperties.size()];

        for (int i = 0; i<sourceproperties.size(); i++)
            sourcepropertiesArray[i] = (SourceProperty) sourceproperties.elementAt(i);
        return sourcepropertiesArray;
    }

    /**
     * Remove a specified source property.
     *
     * @param namespace Namespace of the property.
     * @param name Name of the property.
     *
     * @throws SourceException If an exception occurs.
     */
    public void removeSourceProperty(String namespace,
                                     String name) throws SourceException {
        try {
            if ((revisionDescriptor!=null) && ( !namespace.equals("DAV:"))) {
                revisionDescriptor.removeProperty(name, namespace);

                // Last modification date
                revisionDescriptor.setLastModified(new Date());

                content.store(slideToken,
                              this.config.getFilesPath()+this.path,
                              revisionDescriptor, null);
            }
        } catch (SlideException se) {
            throw new SourceException("Could not remove property", se);
        }
    }

    /**
     * If this source versioned
     *
     * @return True if the current source is versioned.
     *
     * @throws SourceException If an exception occurs.
     */
    public boolean isVersioned() throws SourceException {
        try {
            this.revisionDescriptors = content.retrieve(this.slideToken,
                                                        this.config.getFilesPath()+
                                                        this.path);

            return this.revisionDescriptors.hasRevisions();

        } catch (SlideException se) {
            throw new SourceException("Could not retrieve revision descriptor",
                                      se);
        }
    }

    /**
     * Get the current revision of the source
     *
     * @return The current revision of the source
     *
     * @throws SourceException If an exception occurs.
     */
    public String getSourceRevision() throws SourceException {
        return this.sourcerevision;
    }

    /**
     * Sets the wanted revision of the source
     *
     * @param sourcerevision The revision, which should be used.
     *
     * @throws SourceException If an exception occurs.
     */
    public void setSourceRevision(String sourcerevision)
      throws SourceException {
        this.sourcerevision = sourcerevision;

        try {
            this.revisionDescriptors = content.retrieve(this.slideToken,
                                                        this.config.getFilesPath()+
                                                        this.path);

            // Retrieve revision descriptor by the revision
            this.revisionDescriptor = content.retrieve(slideToken,
                                                       revisionDescriptors,
                                                       new NodeRevisionNumber(this.sourcerevision));

        } catch (SlideException se) {
            throw new SourceException("Could not retrieve revision descriptor",
                                      se);
        }
    }

    /**
     * Get the current branch of the revision from the source
     *
     * @return The branch of the revision
     *
     * @throws SourceException If an exception occurs.
     */
    public String getSourceRevisionBranch() throws SourceException {
        return this.sourcerevisionbranch;
    }

    /**
     * Sets the wanted branch of the revision from the source
     *
     * @param sourcerevisionbranch The branch, which should be used.
     *
     * @throws SourceException If an exception occurs.
     */
    public void setSourceRevisionBranch(String sourcerevisionbranch)
      throws SourceException {
        this.sourcerevisionbranch = sourcerevisionbranch;

        // FIXME Retrieve the the revsion descriptor with current branch
    }

    /**
     * Get the latest revision
     *
     * @return Last revision of the source.
     *
     * @throws SourceException If an exception occurs.
     */
    public String getLatestSourceRevision() throws SourceException {
        try {
            this.revisionDescriptors = content.retrieve(this.slideToken,
                                                        this.config.getFilesPath()+
                                                        this.path);

            return this.revisionDescriptors.getLatestRevision().toString();

        } catch (SlideException se) {
            throw new SourceException("Could not retrieve revision descriptor",
                                      se);
        }
    }
}
TOP

Related Classes of org.apache.cocoon.components.source.impl.SlideSource

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.