Package org.apache.slide.macro

Source Code of org.apache.slide.macro.MacroImpl

/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/macro/MacroImpl.java,v 1.36.2.1 2004/02/05 16:05:08 mholz Exp $
* $Revision: 1.36.2.1 $
* $Date: 2004/02/05 16:05:08 $
*
* ====================================================================
*
* 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.macro;

import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.slide.common.Domain;
import org.apache.slide.common.Namespace;
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.SlideTokenWrapper;
import org.apache.slide.content.Content;
import org.apache.slide.content.NodeProperty;
import org.apache.slide.content.NodeRevisionContent;
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.lock.Lock;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.lock.ObjectLockedException;
import org.apache.slide.macro.CopyRouteRedirector.CopyRoute;
import org.apache.slide.security.AccessDeniedException;
import org.apache.slide.security.NodePermission;
import org.apache.slide.security.Security;
import org.apache.slide.store.Store;
import org.apache.slide.structure.LinkedObjectNotFoundException;
import org.apache.slide.structure.ObjectHasChildrenException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.structure.Structure;
import org.apache.slide.util.Configuration;

/**
* Macro helper class.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @version $Revision: 1.36.2.1 $
*/
public final class MacroImpl implements Macro {
   
    private Namespace namespace;
    private NamespaceConfig namespaceConfig;
    private Content contentHelper;
    private Structure structureHelper;
    private Security securityHelper;
    private Lock lockHelper;
   
    /**
     * Constructor.
     *
     * @param namespace Namespace
     * @param namespaceConfig Namespace configuration
     * @param contentHelper Access to content
     * @param structureHelper Access to structure
     */
    public MacroImpl(Namespace namespace, NamespaceConfig namespaceConfig,
                     Security securityHelper, Content contentHelper,
                     Structure structureHelper,
                     Lock lockHelper) {
        this.namespace       = namespace;
        this.namespaceConfig = namespaceConfig;
        this.securityHelper  = securityHelper;
        this.contentHelper   = contentHelper;
        this.structureHelper = structureHelper;
        this.lockHelper      = lockHelper;
    }
   
    /**
     * Recursive copy with overwrite macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @exception CopyMacroException Generic Slide exception
     */
    public void copy(SlideToken token, String sourceUri,
                     String destinationUri)
        throws CopyMacroException, DeleteMacroException {
        copy(token, sourceUri, destinationUri,
                 (CopyRouteRedirector)null, (CopyListener)null,
                 (DeleteTargetRedirector)null, (DeleteListener)null);
    }
   
    /**
     * Recursive copy with overwrite macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param copyRedirector  the CopyRoutRedirector may be used to redirect
     *                        the source and/or destination URI of the
     *                         <code>copy</code> operation.
     *                        (May be <code>null</code>.)
     * @param copyListener    the CopyListener that will be notified
     *                        before and after copying a resource.
     *                        (May be <code>null</code>)
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a destination
     *                        that will be overwritten by the copy.
     *                        (May be <code>null</code>)
     * @exception CopyMacroException Generic Slide exception
     */
    public void copy(SlideToken token, String sourceUri,
                     String destinationUri, CopyRouteRedirector copyRedirector, CopyListener copyListener,
                     DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws CopyMacroException, DeleteMacroException {
       
        this.copy(token, sourceUri, destinationUri,
                  RECURSIVE_OVERWRITE_PARAMETERS, copyRedirector, copyListener,
                  deleteRedirector, deleteListener);
    }
   
   
    /**
     * Copy macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param parameters Macro parameters
     * @exception CopyMacroException Generic Slide exception
     */
    public void copy(SlideToken token, String sourceUri,
                     String destinationUri, MacroParameters parameters)
        throws CopyMacroException, DeleteMacroException {
        copy(token, sourceUri, destinationUri, parameters, null, null, null, null);
    }
   
    /**
     * Copy macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param parameters Macro parameters
     * @param copyRedirector  the CopyRoutRedirector may be used to redirect
     *                        the source and/or destination URI of the
     *                         <code>copy</code> operation.
     *                        (May be <code>null</code>.)
     * @param copyListener    the CopyListener that will be notified
     *                        before and after copying a resource.
     *                        (May be <code>null</code>)
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a destination
     *                        that will be overwritten by the copy.
     *                        (May be <code>null</code>)
     * @exception CopyMacroException Generic Slide exception
     */
    public void copy(SlideToken token, String sourceUri,
                     String destinationUri, MacroParameters parameters,
                     CopyRouteRedirector copyRedirector, CopyListener copyListener,
                     DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws CopyMacroException, DeleteMacroException {
       
        Domain.debug("Copy " + sourceUri + " to " + destinationUri);
       
        // Now performing the actual copy
        CopyMacroException e = new CopyMacroException("Copy failed");
       
        //----------------
        // handle the case that source and destination are identical
        if (sourceUri.equals(destinationUri)) {
            e.addException(new ForbiddenException(sourceUri));
            throw e;
        }
       
        // try to writeLock the complete destination tree
        try {
            writeLock(token, destinationUri, true);
        }
        catch( ServiceAccessException x ) {
            e.addException(x);
            throw e;
        }
        catch (SlideException x) {}; // ignore silently
       
        Map alreadyCopied = new HashMap(); // maps source-UURI -> destination-URI
        parameters.setParameter( ALREADY_COPIED, alreadyCopied );
       
        copyObject(token, sourceUri, destinationUri, parameters, true, e,
                   copyRedirector, copyListener, deleteRedirector, deleteListener);
       
        // If there were errors, we throw the nested exception
        if (!e.isEmpty()) {
            throw e;
        }
       
    }
   
    /**
     * WriteLock the specified URI
     *
     * @param    token               a  SlideToken
     * @param    uri                 a  String
     * @param    recursive           a  boolean
     * @throws   SlideException
     */
    private void writeLock(SlideToken token, String uri, boolean recursive) throws SlideException {
        if (!token.isForceStoreEnlistment()) {
            token = new SlideTokenWrapper(token, true);
        }
        ObjectNode onode = structureHelper.retrieve(token, uri);
        if (onode != null && recursive) {
            Iterator i = onode.getChildren().iterator();
            while (i.hasNext()) {
                writeLock( token, (String)i.next(), true );
            }
           
        }
    }
   
    // TODO: copyRedirector not used
    public void rebind(SlideToken token, String sourceUri,
                       String destinationUri, MacroParameters parameters,
                       CopyRouteRedirector copyRedirector, CopyListener copyListener,
                       DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws CopyMacroException, DeleteMacroException {
       
        CopyMacroException e = new CopyMacroException("Rebind failed");
       
        //----------------
        // handle the case that source and destination are identical
        if (sourceUri.equals(destinationUri)) {
            e.addException(new ForbiddenException(sourceUri));
            throw e;
        }
       
        // try to writeLock the complete destination tree
        try {
            writeLock(token, destinationUri, true);
        }
        catch( ServiceAccessException x ) {
            e.addException(x);
            throw e;
        }
        catch (SlideException x) {}; // ignore silently
       
        if (parameters.isDeleteCreate()) {
            try {
                // If the object we want to overwrite exists, we delete is first
                structureHelper.retrieve(token, destinationUri);
                delete(token, destinationUri, deleteRedirector, deleteListener);
            } catch(ObjectNotFoundException onf) {
                // Silent catch, the target doesn't exist
            } catch(DeleteMacroException s) {
                throw s;
            } catch(SlideException s) {
                e.addException(s);
                throw e;
            }
        }
        //----------------
       
        UriHandler destinationUh = new UriHandler(destinationUri);
        UriHandler destinationParentUh = destinationUh.getParent();
        ObjectNode destinationParentNode = null;
        String destinationSegment = destinationUh.getLastSegment();
        UriHandler sourceUh = new UriHandler(sourceUri);
        UriHandler sourceParentUh = sourceUh.getParent();
        ObjectNode sourceParentNode = null;
        String sourceSegment = sourceUh.getLastSegment();
        ObjectNode sourceNode = null;
       
        try {
            try {
                destinationParentNode =
                    structureHelper.retrieve(token, destinationParentUh.toString(), false );
            }
            catch (ObjectNotFoundException ex) {
                throw new ConflictException(destinationParentUh.toString());
            }
            sourceParentNode =
                structureHelper.retrieve(token, sourceParentUh.toString(), false );
            sourceNode =
                structureHelper.retrieve(token, sourceUri, false );
        }
        catch (SlideException x) {
            e.addException(x);
            throw e;
        }
       
        try {
            // notify Listeners
            if (copyListener != null) {
                copyListener.beforeCopy(sourceUri, destinationUri, true);
            }
           
            structureHelper.addBinding( token, destinationParentNode, destinationSegment, sourceNode );
            structureHelper.removeBinding( token, sourceParentNode, sourceSegment );
        }
        catch (SlideException x) {
            e.addException(x);
            throw e;
        }
    }
   
    /**
     * Recursive move with overwrite macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @exception CopyMacroException Exception occured during copy
     * @exception DeleteMacroException Exception occured during deletion
     */
    public void move(SlideToken token, String sourceUri,
                     String destinationUri)
        throws CopyMacroException, DeleteMacroException {
        move(token, sourceUri, destinationUri,
                 (CopyRouteRedirector)null, (CopyListener)null,
                 (DeleteTargetRedirector)null, (DeleteListener)null);
    }
   
    /**
     * Recursive move with overwrite macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param copyRedirector  the CopyRoutRedirector may be used to redirect
     *                        the source and/or destination URI of the
     *                         <code>copy</code> operation.
     *                        (May be <code>null</code>.)
     * @param copyListener    the CopyListener that will be notified
     *                        before and after copying a resource.
     *                        (May be <code>null</code>)
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a resource.
     *                        (May be <code>null</code>)
     * @exception CopyMacroException Exception occured during copy
     * @exception DeleteMacroException Exception occured during deletion
     */
    public void move(SlideToken token, String sourceUri,
                     String destinationUri, CopyRouteRedirector copyRedirector, CopyListener copyListener,
                     DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws CopyMacroException, DeleteMacroException {
       
        move(token, sourceUri, destinationUri,
             RECURSIVE_OVERWRITE_PARAMETERS,
             copyRedirector, copyListener, deleteRedirector, deleteListener);
    }
   
   
    /**
     * Move macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param parameters Macro parameters
     * @exception CopyMacroException Exception occured during copy
     * @exception DeleteMacroException Exception occured during deletion
     */
    public void move(SlideToken token, String sourceUri,
                     String destinationUri, MacroParameters parameters)
        throws CopyMacroException, DeleteMacroException {
        move(token, sourceUri, destinationUri, parameters, null, null, null, null);
    }
   
    /**
     * Move macro.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param parameters Macro parameters
     * @param copyRedirector  the CopyRoutRedirector may be used to redirect
     *                        the source and/or destination URI of the
     *                         <code>copy</code> operation.
     *                        (May be <code>null</code>.)
     * @param copyListener    the CopyListener that will be notified
     *                        before and after copying a resource.
     *                        (May be <code>null</code>)
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a resource.
     *                        (May be <code>null</code>)
     * @exception CopyMacroException Exception occured during copy
     * @exception DeleteMacroException Exception occured during deletion
     */
    public void move(SlideToken token, String sourceUri,
                     String destinationUri, MacroParameters parameters,
                     CopyRouteRedirector copyRedirector, CopyListener copyListener,
                     DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws CopyMacroException, DeleteMacroException {
       
        if (Configuration.useBinding(namespace.getUri(token, sourceUri).getStore()) &&
            Configuration.useBinding(namespace.getUri(token, destinationUri).getStore()) &&
            sameStore(token, sourceUri, destinationUri)) {
            rebind(token, sourceUri, destinationUri, parameters,
                   copyRedirector, copyListener, deleteRedirector, deleteListener);
        }
        else {
            copy(token, sourceUri, destinationUri, parameters,
                 copyRedirector, copyListener, deleteRedirector, deleteListener);
            delete(token, sourceUri, parameters, deleteRedirector, deleteListener);
        }
    }
   
    /**
     * Recursive delete.
     *
     * @param token Credentials token
     * @param targetUri Uri of the object to delete
     * @exception DeleteMacroException Generic Slide exception
     */
    public void delete(SlideToken token, String targetUri)
        throws DeleteMacroException {
        delete(token, targetUri, (DeleteTargetRedirector)null, (DeleteListener)null);
    }
   
    /**
     * Recursive delete.
     *
     * @param token Credentials token
     * @param targetUri Uri of the object to delete
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a resource.
     *                        (May be <code>null</code>)
     * @exception DeleteMacroException Generic Slide exception
     */
    public void delete(SlideToken token, String targetUri,
                       DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws DeleteMacroException {
        delete(token, targetUri, RECURSIVE_OVERWRITE_PARAMETERS, deleteRedirector, deleteListener);
    }
   
   
    /**
     * Delete macro.
     *
     * @param token Credentials token
     * @param targetUri Uri of the source
     * @param parameters Macro parameters, not used right now,
     * so it can be null
     * @exception DeleteMacroException Generic Slide exception
     */
    public void delete(SlideToken token, String targetUri,
                       MacroParameters parameters)
        throws DeleteMacroException {
        delete(token, targetUri, parameters, null, null);
    }
   
    /**
     * Delete macro.
     *
     * @param token Credentials token
     * @param targetUri Uri of the source
     * @param parameters Macro parameters, not used right now,
     * so it can be null
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a resource.
     *                        (May be <code>null</code>)
     * @exception DeleteMacroException Generic Slide exception
     */
    public void delete(SlideToken token, String targetUri, MacroParameters parameters,
                       DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener)
        throws DeleteMacroException {
       
        Domain.debug("Delete " + targetUri);
       
        DeleteMacroException e = new DeleteMacroException("Delete failed");
       
        deleteObject(token, targetUri, e, deleteRedirector, deleteListener);
       
        // If there were errors, we throw the nested exception
        if (!e.isEmpty()) {
            throw e;
        }
       
    }
   
   
    // -------------------------------------------------------- Private Methods
   
   
    /**
     * Copy object.
     *
     * @param token Credentials token
     * @param sourceUri Uri of the source
     * @param destinationUri Uri of the destination
     * @param parameters Macro parameters
     * @param copyRedirector  the CopyRoutRedirector may be used to redirect
     *                        the source and/or destination URI of the
     *                         <code>copy</code> operation.
     *                        (May be <code>null</code>.)
     * @param copyListener    the CopyListener that will be notified
     *                        before and after copying a resource.
     *                        (May be <code>null</code>)
     * @param CopyMacroException Exception occured during copy
     */
    private void copyObject(SlideToken token, String sourceUri,
                            String destinationUri, MacroParameters parameters, boolean isRootOfCopy,
                            CopyMacroException e, CopyRouteRedirector copyRedirector, CopyListener copyListener,
                            DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener
                           ) {
       
        Domain.debug("Copy object : from " + sourceUri + " to "
                         + destinationUri);
       
        try {
            // check for lock-null
            if (isLockNull(token, sourceUri)) {
                // skip
                return;
            }
           
            // Remember children of orginal source
            ObjectNode sourceNode =
                structureHelper.retrieve(token, sourceUri, false);
            Enumeration sourceNodeChildren = sourceNode.enumerateChildren();
            ObjectNode destinationNode = null;
           
            // now let the client redirect
            if (copyRedirector != null) {  // TODO: dump re-directing
                CopyRoute copyRoute = new CopyRoute(sourceUri, destinationUri);
                copyRoute = copyRedirector.getRedirectedCopyRoute(copyRoute);
                sourceUri = copyRoute.getSourceUri();
                destinationUri = copyRoute.getDestinationUri();
                sourceNode = structureHelper.retrieve(token, sourceUri, false);
                // note that childrenList is *not* re-assigned. This might be a bug ...
            }
           
            // notify CopyListener
            if (copyListener != null) {
                copyListener.beforeCopy(sourceUri, destinationUri, isRootOfCopy );
            }
           
            // delete target if it is the root of the copied tree
            if (isRootOfCopy && parameters.isDeleteCreate()) {
                try {
                    // We make sure the object we want to overwrite exists
                    structureHelper.retrieve(token, destinationUri);
                    if (parameters.getParameter(PARENT_BINDINGS) != null) {
                        Map parentBindings = (Map)parameters.getParameter(PARENT_BINDINGS);
                        Iterator i = parentBindings.entrySet().iterator();
                        while (i.hasNext()) {
                            Map.Entry me = (Map.Entry)i.next();
                            String uriToDelete = (String)me.getKey()+"/"+(String)me.getValue();
                            delete(token, uriToDelete, deleteRedirector, deleteListener);
                        }
                    }
                    else {
                        delete(token, destinationUri, deleteRedirector, deleteListener);
                    }
                } catch(ObjectNotFoundException onf) {
                    // Silent catch, the target doesn't exist
                } catch(DeleteMacroException s) {
                    Enumeration en = s.enumerateExceptions();
                    if (en.hasMoreElements()) {
                        throw (SlideException)en.nextElement();
                    }
                }
            }
           
            boolean destinationExists = destinationExists(token, destinationUri);
           
            // Creating the copy
            if (parameters.isDeleteCreate() || !destinationExists) {
                try {
                    Map alreadyCopied = (Map)parameters.getParameter( ALREADY_COPIED );
                   
                    if (alreadyCopied.containsKey(sourceNode.getUuri())) {
                        // If a COPY request would cause a new resource to be created
                        // as a copy of an existing resource, and that COPY request
                        // has already created a copy of that existing resource,
                        // the COPY request instead creates another binding to the
                        // previous copy, instead of creating a new resource.
                        UriHandler destinationUh = new UriHandler(destinationUri);
                        UriHandler destinationParentUh = destinationUh.getParent();
                        String segment = destinationUh.getLastSegment();
                        destinationNode = structureHelper.retrieve( token, (String)alreadyCopied.get(sourceNode.getUuri()) );
                        ObjectNode destinationParentNode = structureHelper.retrieve( token, destinationParentUh.toString() );
                        structureHelper.addBinding( token, destinationParentNode, segment, destinationNode );
                    }
                    else {
                        structureHelper.create(token, sourceNode.copyObject(),
                                               destinationUri);
                        destinationNode = structureHelper.retrieve( token, destinationUri );
                        alreadyCopied.put( sourceNode.getUuri(), destinationNode.getUri() );
                    }
                } catch (ObjectNotFoundException s){
                    throw new ConflictException(s.getObjectUri());
                }
            }
           
            // Trying to recreate permissions
            try {
               
                Enumeration sourcePermissions = securityHelper
                    .enumeratePermissions(token, sourceNode);
               
                while (sourcePermissions.hasMoreElements()) {
                    NodePermission permission =
                        (NodePermission) sourcePermissions.nextElement();
                    NodePermission newPermission =
                        new NodePermission(destinationUri,
                                           permission.getSubjectUri(),
                                           permission.getActionUri(),
                                           permission.isInheritable(),
                                           permission.isNegative());
                    securityHelper.grantPermission(token, newPermission);
                }
               
            } catch (AccessDeniedException ex) {
                // Means that we don't have modifyPermissions rights
                // (root access) on the target.
                // The copy should definitely succeed anyway,
                // so we silently catch the exception.
            }
           
            // Now copying revision descriptors and content
            NodeRevisionDescriptors sourceNrds =
                contentHelper.retrieve(token, sourceNode.getUri());
            if (sourceNrds.hasRevisions()) {
                NodeRevisionDescriptor sourceNrd =
                    contentHelper.retrieve(token, sourceNrds);
                NodeRevisionContent sourceNrc = null;
                if (sourceNrd.getContentLength() > 0) {
                    sourceNrc =
                        contentHelper.retrieve(token, sourceNrds, sourceNrd);
                }
               
                if (parameters.isDeleteCreate() || !destinationExists) {
                    contentHelper.create(token, destinationUri, sourceNrd, sourceNrc);
                }
                else {
                    NodeRevisionDescriptor destinationNrd =
                        contentHelper.retrieve(token,
                                               contentHelper.retrieve(token, destinationUri));
                    Enumeration sourceProps = sourceNrd.enumerateProperties();
                    while (sourceProps.hasMoreElements()) {
                        destinationNrd.setProperty( (NodeProperty)sourceProps.nextElement() );
                    }
                    contentHelper.store(token, destinationUri, destinationNrd, sourceNrc);
                }
            }
           
            // notify CopyListener
            if (copyListener != null) {
                copyListener.afterCopy(sourceUri, destinationUri, isRootOfCopy);
            }
           
            // We copy each of this object's children
           
            while(sourceNodeChildren.hasMoreElements()) {
                String childUri = (String) sourceNodeChildren.nextElement();
                String childDestinationUri = destinationUri + childUri
                    .substring(sourceNode.getUri().length());
                copyObject(token, childUri, childDestinationUri,
                           parameters, false, e, copyRedirector, copyListener,
                           deleteRedirector, deleteListener
                          );
            }
           
        } catch(SlideException ex) {
            // ex.printStackTrace(); //the exception is packed and
            // (hopefully) reported in the response
            e.addException(ex);
        }
       
    }
   
    private boolean destinationExists(SlideToken token, String destinationUri) throws ServiceAccessException, LinkedObjectNotFoundException, RevisionDescriptorNotFoundException, ObjectLockedException, AccessDeniedException {
        boolean destinationExists = true;
        NodeRevisionDescriptor destinationNrd = null;
        try {
            destinationNrd =
                contentHelper.retrieve(token,
                                       contentHelper.retrieve(token, destinationUri));
        }
        catch (ObjectNotFoundException x) {
            destinationExists = false;
        }
        return destinationExists;
    }
   
   
    /**
     * Delete object function. Recursive for now.
     *
     * @param token Credentials token
     * @param targetUri Uri of the source
     * @param parameters Macro parameters, not used right now, so it can
     * be null
     * @param e Nested exception
     * @param deleteRedirector  the DeleteTargetRedirector may be used to redirect
     *                          the <code>delete</code> operation to a different
     *                          target. (May be <code>null</code>.)
     * @param deleteListener  the DeleteListener that will be notified
     *                        before and after deleting a resource.
     *                        (May be <code>null</code>)
     */
    private void deleteObject(SlideToken token, String targetUri, MacroException e,
                              DeleteTargetRedirector deleteRedirector, DeleteListener deleteListener) {
       
        Domain.debug("Delete object : " + targetUri);
       
        try {
            ObjectNode currentObject =
                structureHelper.retrieve(token, targetUri, false);
           
            if (!Configuration.useBinding(namespace.getUri(token, targetUri).getStore()) || currentObject.numberOfParentBindings() < 2) {
                // Removing children objects
                if (currentObject.hasChildren()) {
                    Enumeration children = currentObject.enumerateChildren();
                    while (children.hasMoreElements()) {
                        String childUri = (String)children.nextElement();
                        deleteObject(token, childUri, e, deleteRedirector, deleteListener);
                    }
                }

        // Removing links objects
        if (currentObject.hasLinks()) {
          Enumeration links = currentObject.enumerateLinks();
          while (links.hasMoreElements()) {
            String linkUri = (String)links.nextElement();
            deleteObject(token, linkUri, e, deleteRedirector, deleteListener);
          }
        }
               
               
                // now let the client redirect
                if (deleteRedirector != null) {
                    targetUri = deleteRedirector.getRedirectedTargetUri(targetUri);
                    currentObject =  structureHelper.retrieve(token, targetUri, false);
                }
               
                // notify DeleteListener
                if (deleteListener != null) {
                    deleteListener.beforeDelete(targetUri);
                }
               
                NodeRevisionDescriptors revisionDescriptors =
                    contentHelper.retrieve(token, currentObject.getUri());
              
                // remove the associated locks
                Enumeration locks = lockHelper.enumerateLocks
                    (token, currentObject.getUri(), false);
                while (locks.hasMoreElements()) {
                    lockHelper.unlock(token, (NodeLock) locks.nextElement());
                }
                // remove the associated security
                Enumeration permissions = securityHelper.enumeratePermissions
                    (token, currentObject);
                while (permissions.hasMoreElements()) {
                    NodePermission permission =
                        (NodePermission) permissions.nextElement();
                    securityHelper.revokePermission(token, permission);
                }
               
                // remove all revisions
                if( !revisionDescriptors.isRedirected() ) {
                    Enumeration revisionNumberEnum =
                        revisionDescriptors.enumerateRevisionNumbers();
                    if (revisionNumberEnum != null) {
                        while (revisionNumberEnum.hasMoreElements()) {
                            contentHelper.remove
                                (token, currentObject.getUri(),
                                     (NodeRevisionNumber)revisionNumberEnum.nextElement());
                        }
                    }
                    removeHiddenRevisions( token, targetUri );
                   
                    // remove the NodeRevisionDescriptors object
                    contentHelper.remove(token, revisionDescriptors);
                }
            }
           
            // Removing object.
            structureHelper.remove(token, currentObject);
           
            // notify DeleteListener
            if (deleteListener != null) {
                deleteListener.afterDelete(targetUri);
            }
           
        } catch (ObjectHasChildrenException ex) {
            // ignore, the object has children because something else failed
            // (one of the children is locked, for example), and the
            // corresponding exception has already been added the the
            // MacroException
        } catch (SlideException ex) {
            e.addException(ex);
        }
       
    }
   
    /**
     * Removes all <i>hidden</i> revisions for the specified URI. Currently there are hidden
     * revisions only at 0.0.
     */
    private void removeHiddenRevisions( SlideToken token, String targetUri ) throws ServiceAccessException, ObjectNotFoundException, LinkedObjectNotFoundException, AccessDeniedException, ObjectLockedException {
       
        // Can this piece of code be moved to MoveMethod.afterDelete() and DeleteMethod.afterDelete?
        // It would look more consistent (the copying of hidden revisions is there!!)
        // BUT: I dont think it's a good idea because the deleteObject() method would delete
        // the NRDS while hidden revisions remain.
       
        try {
            contentHelper.remove(token, targetUri, NodeRevisionNumber.HIDDEN_0_0 );
        }
        catch (RevisionDescriptorNotFoundException ne) {
            // ignore
        }
    }
   
    /**
     ** Uri handler.
     **
     ** @author    peter.nevermann@softwareag.com
     **/
    private static class UriHandler {
       
        /** The path tokens */
        String[] tokens = null;
        final String uriDelimiter = "/";
       
        /**
         ** Default constructor.
         **/
        UriHandler( String uri ) {
            StringTokenizer ut = new StringTokenizer( uri, uriDelimiter );
            int ntok = ut.countTokens();
            this.tokens = new String[ntok];
            for( int i = 0; i < ntok; i++ )
                tokens[i] = ut.nextToken();
        }
       
        /**
         ** Default constructor.
         **/
        UriHandler( String[] toks ) {
            this.tokens = new String[toks.length];
            for( int i = 0; i < toks.length; i++ )
                tokens[i] = toks[i];
        }
       
        /**
         ** Default constructor.
         ** @pre number <= toks.length
         **/
        UriHandler( String[] toks, int number ) {
            this.tokens = new String[number];
            for( int i = 0; i < number; i++ )
                tokens[i] = toks[i];
        }
       
        /**
         ** Check whether this is the root.
         **/
        boolean isRoot() {
            return (tokens.length == 0);
        }
       
        /**
         * Return the parent.
         * Example: for /a/b/c returns: /a/b
         */
        UriHandler getParent() {
            if( isRoot() )
                return null;
            return new UriHandler( tokens, tokens.length - 1 );
        }
       
        /**
         * Checks this URI is parent of the specified URI
         */
        boolean isParentOf( UriHandler uh ) {
            return equals( uh.getParent() );
        }
       
        /**
         * Returns the node name (last token), e.g. "c" for /a/b/c
         */
        String getLastSegment() {
            return tokens[tokens.length - 1];
        }
       
        /**
         *
         */
        public boolean equals( Object o ) {
            if( o instanceof UriHandler ) {
                UriHandler ouh = (UriHandler)o;
                return Arrays.equals( tokens, ouh.tokens );
            }
            return false;
        }
       
        /**
         *
         */
        public int hashCode() {
            return tokens.length;
        }
       
        /**
         * Return string representation.
         */
        public String toString() {
            StringBuffer b = new StringBuffer();
            if( tokens.length == 0 )
                b.append( uriDelimiter );
            for( int i = 0; i < tokens.length; i++ )
                b.append( uriDelimiter ).append( tokens[i] );
            return b.toString();
        }
    }
   
    private boolean sameStore(SlideToken token, String leftUri, String rightUri) {
        Store leftStore = namespace.getUri(token, leftUri).getStore();
        Store rightStore = namespace.getUri(token, rightUri).getStore();
        if (leftStore == null || rightStore == null) {
            throw new IllegalStateException("Got null store: leftStore="+leftStore+", rightStore="+rightStore);
        }
        return leftStore == rightStore;
    }
   
    private boolean isLockNull( SlideToken slideToken, String uriStr ) throws ServiceAccessException {
        boolean isLockNull = false;
        try {
            NodeRevisionDescriptor nrd =
                contentHelper.retrieve(slideToken, contentHelper.retrieve(slideToken, uriStr));
            isLockNull = isLockNull( nrd );
        }
        catch (ServiceAccessException x) {
            throw x;
        }
        catch (SlideException x) {
            // ignore silently
        }
        return isLockNull;
    }
   
    private boolean isLockNull( NodeRevisionDescriptor nrd ) {
        return nrd.propertyValueContains("resourcetype", "lock-null");
    }
}



TOP

Related Classes of org.apache.slide.macro.MacroImpl

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.