PageMoveActionFactory.java 18.4 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.commons.jcr.JcrUtil
 *  com.day.cq.wcm.api.Page
 *  com.day.cq.wcm.api.PageManager
 *  com.day.cq.wcm.api.PageManagerFactory
 *  com.day.cq.wcm.api.Template
 *  com.day.cq.wcm.api.WCMException
 *  com.day.cq.wcm.commons.ReferenceSearch
 *  com.day.cq.wcm.commons.ReferenceSearch$Info
 *  com.day.cq.wcm.msm.api.LiveAction
 *  com.day.cq.wcm.msm.api.LiveRelationship
 *  com.day.cq.wcm.msm.api.LiveStatus
 *  com.day.cq.wcm.msm.api.RolloutManager
 *  com.day.cq.wcm.msm.commons.BaseActionFactory
 *  com.day.cq.wcm.msm.commons.FilteredAction
 *  com.day.cq.wcm.msm.commons.FilteredActionFactoryBase
 *  com.day.cq.wcm.msm.commons.ItemFilterImpl
 *  com.day.cq.wcm.msm.commons.ItemFilterUtil
 *  com.day.text.Text
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.nodetype.NodeType
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Modified
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.wcm.msm.impl.actions;

import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.PageManagerFactory;
import com.day.cq.wcm.api.Template;
import com.day.cq.wcm.api.WCMException;
import com.day.cq.wcm.commons.ReferenceSearch;
import com.day.cq.wcm.msm.api.LiveAction;
import com.day.cq.wcm.msm.api.LiveRelationship;
import com.day.cq.wcm.msm.api.LiveStatus;
import com.day.cq.wcm.msm.api.RolloutManager;
import com.day.cq.wcm.msm.commons.BaseActionFactory;
import com.day.cq.wcm.msm.commons.FilteredAction;
import com.day.cq.wcm.msm.commons.FilteredActionFactoryBase;
import com.day.cq.wcm.msm.commons.ItemFilterImpl;
import com.day.cq.wcm.msm.commons.ItemFilterUtil;
import com.day.cq.wcm.msm.impl.LiveCopyManagerImpl;
import com.day.cq.wcm.msm.impl.LiveCopyServiceImpl;
import com.day.cq.wcm.msm.impl.Utils;
import com.day.text.Text;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.NodeType;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, label="%cq.wcm.msm.impl.actions.pagemove.label", description="%cq.wcm.msm.impl.actions.pagemove.description")
@Service
public class PageMoveActionFactory
extends FilteredActionFactoryBase<FilteredAction> {
    @org.apache.felix.scr.annotations.Property(name="liveActionName", propertyPrivate=1)
    private static final String[] LIVE_ACTION_NAME = new String[]{PageMoveAction.class.getSimpleName()};
    @org.apache.felix.scr.annotations.Property(name="cq.wcm.msm.action.excludednodetypes")
    private static final String[] DEFAULT_FILTER_NODE_TYPES = ItemFilterUtil.EMPTY_PROPERTIES;
    @org.apache.felix.scr.annotations.Property(name="cq.wcm.msm.action.excludedparagraphitems")
    private static final String[] DEFAULT_EXCLUDED_PARAGRAPH_ITEMS = ItemFilterUtil.EMPTY_PROPERTIES;
    @org.apache.felix.scr.annotations.Property(name="cq.wcm.msm.action.excludedprops")
    private static final String[] DEFAULT_EXCLUDED_PROPERTIES = ItemFilterUtil.EMPTY_PROPERTIES;
    @org.apache.felix.scr.annotations.Property(boolValue={1})
    static final String PROP_REFERENCE_UPDATE = "cq.wcm.msm.impl.actions.pagemove.prop_referenceUpdate";
    @Reference
    private SlingRepository repository = null;
    @Reference
    private PageManagerFactory pageManagerFactory = null;
    @Reference
    private LiveCopyServiceImpl liveCopyService = null;
    @Reference
    private RolloutManager rolloutManager = null;
    private static final Set<String> RESERVED_NODETYPES = new HashSet<String>(){};
    private static final Set<String> RESERVED_NODENAMES = new HashSet<String>(){};
    private static final String DEFAULT_SEARCH_ROOT = "/jcr:root/content";
    private boolean updateReferences;
    private ItemFilterImpl itemFilter;

    protected boolean isUpdateReferences() {
        return this.updateReferences;
    }

    protected ItemFilterImpl getItemFilter() {
        return this.itemFilter;
    }

    protected PageManager getPageManager(ResourceResolver resolver) {
        return this.pageManagerFactory.getPageManager(resolver);
    }

    protected LiveCopyServiceImpl getLiveCopyService() {
        return this.liveCopyService;
    }

    protected PageManagerFactory getPageManagerFactory() {
        return this.pageManagerFactory;
    }

    protected SlingRepository getRepository() {
        return this.repository;
    }

    public RolloutManager getRolloutManager() {
        return this.rolloutManager;
    }

    @Activate
    @Modified
    protected void configure(ComponentContext context) {
        this.setupFilter(context, this.rolloutManager);
        this.updateReferences = PropertiesUtil.toBoolean(context.getProperties().get("cq.wcm.msm.impl.actions.pagemove.prop_referenceUpdate"), (boolean)Boolean.FALSE);
        Dictionary properties = context.getProperties();
        String[] pageProperties = PropertiesUtil.toStringArray(properties.get("cq.wcm.msm.action.excludedprops"), (String[])ItemFilterUtil.EMPTY_PROPERTIES);
        String[] paragraphItems = PropertiesUtil.toStringArray(properties.get("cq.wcm.msm.action.excludedparagraphitems"), (String[])ItemFilterUtil.EMPTY_PROPERTIES);
        String[] nodeTypes = PropertiesUtil.toStringArray(properties.get("cq.wcm.msm.action.excludednodetypes"), (String[])ItemFilterUtil.EMPTY_PROPERTIES);
        HashSet<String> excludedPageProperties = new HashSet<String>(Arrays.asList(pageProperties));
        HashSet<String> excludedParagraphItems = new HashSet<String>(Arrays.asList(paragraphItems));
        HashSet<String> excludedNodeTypes = new HashSet<String>(Arrays.asList(nodeTypes));
        excludedNodeTypes.addAll(RESERVED_NODETYPES);
        excludedParagraphItems.addAll(RESERVED_NODENAMES);
        excludedPageProperties.addAll(RESERVED_NODENAMES);
        this.itemFilter = ItemFilterUtil.createFilter((String[])excludedNodeTypes.toArray(new String[excludedNodeTypes.size()]), (String[])excludedPageProperties.toArray(new String[excludedPageProperties.size()]), (String[])excludedParagraphItems.toArray(new String[excludedParagraphItems.size()]), (RolloutManager)this.rolloutManager);
    }

    public String createsAction() {
        return LIVE_ACTION_NAME[0];
    }

    protected PageMoveAction newActionInstance(ValueMap config) {
        return new PageMoveAction(config, this);
    }

    protected void bindRepository(SlingRepository slingRepository) {
        this.repository = slingRepository;
    }

    protected void unbindRepository(SlingRepository slingRepository) {
        if (this.repository == slingRepository) {
            this.repository = null;
        }
    }

    protected void bindPageManagerFactory(PageManagerFactory pageManagerFactory) {
        this.pageManagerFactory = pageManagerFactory;
    }

    protected void unbindPageManagerFactory(PageManagerFactory pageManagerFactory) {
        if (this.pageManagerFactory == pageManagerFactory) {
            this.pageManagerFactory = null;
        }
    }

    protected void bindLiveCopyService(LiveCopyServiceImpl liveCopyServiceImpl) {
        this.liveCopyService = liveCopyServiceImpl;
    }

    protected void unbindLiveCopyService(LiveCopyServiceImpl liveCopyServiceImpl) {
        if (this.liveCopyService == liveCopyServiceImpl) {
            this.liveCopyService = null;
        }
    }

    protected void bindRolloutManager(RolloutManager rolloutManager) {
        this.rolloutManager = rolloutManager;
    }

    protected void unbindRolloutManager(RolloutManager rolloutManager) {
        if (this.rolloutManager == rolloutManager) {
            this.rolloutManager = null;
        }
    }

    private static final class PageMoveAction
    extends FilteredAction {
        private static final Logger log = LoggerFactory.getLogger(PageMoveAction.class);
        private final PageManagerFactory pageManagerFactory;
        private final LiveCopyServiceImpl liveCopyService;
        private final RolloutManager rolloutManager;
        private final ItemFilterImpl filter;
        private ReferenceSearch search;
        private boolean isReferenceUpdate;

        protected PageMoveAction(ValueMap config, PageMoveActionFactory factory) {
            super(config, factory.getPagePropertyFilter(), factory.getComponentFilter(), (BaseActionFactory)factory);
            this.pageManagerFactory = factory.getPageManagerFactory();
            this.liveCopyService = factory.getLiveCopyService();
            this.rolloutManager = factory.getRolloutManager();
            this.isReferenceUpdate = config != null ? (Boolean)config.get("cq.wcm.msm.impl.actions.pagemove.prop_referenceUpdate", (Object)factory.updateReferences) : factory.updateReferences;
            this.filter = factory.getItemFilter();
            if (this.isReferenceUpdate) {
                this.search = new ReferenceSearch();
                this.search.setRepository(factory.getRepository());
                this.search.setSearchRoot("/jcr:root/content");
                this.search.setExact(false);
            }
        }

        protected boolean doHandle(Resource source, Resource target, LiveRelationship relation, boolean resetRollout) throws RepositoryException, WCMException {
            LiveStatus status = relation.getStatus();
            if (!(status.isPage() && PageMoveAction.exists(target) && PageMoveAction.exists(source))) {
                log.debug("Action declined to handle {}: only move existing Pages", (Object)relation.getSourcePath());
                return false;
            }
            LiveCopyManagerImpl lcManager = this.liveCopyService.createLiveCopyManager(source.getResourceResolver());
            LiveCopyManagerImpl.LiveCopyImpl lc = lcManager.get(target.getPath());
            return lc != null && lc.getMoveTarget() != null;
        }

        protected void doExecute(Resource source, Resource target, LiveRelationship relation, boolean reset) throws RepositoryException, WCMException {
            ResourceResolver resolver = source.getResourceResolver();
            PageManager pm = this.pageManagerFactory.getPageManager(resolver);
            Page targetPage = pm.getContainingPage(target.getPath());
            LiveCopyManagerImpl lcManager = this.liveCopyService.createLiveCopyManager(source.getResourceResolver());
            LiveCopyManagerImpl.LiveCopyImpl sourceLc = lcManager.get(targetPage.getPath());
            String moveTarget = sourceLc.getMoveTarget();
            if (source.getResourceResolver().getResource(moveTarget) != null) {
                log.debug("Moved Blueprint Page found, but target Exists at {} -> skip ", (Object)moveTarget);
                return;
            }
            lcManager.remove(target.getPath());
            String before = PageMoveAction.findFollowingSibling(pm.getContainingPage(source.getPath()));
            Page copy = this.copyPage(targetPage, Text.getRelativeParent((String)moveTarget, (int)1), Text.getName((String)moveTarget), before, targetPage.getPath(), lcManager);
            LiveCopyManagerImpl.LiveCopyImpl lc = lcManager.getContainingLiveCopy(copy.getParent().getPath());
            if (lc != null) {
                lc.removeExclusion(moveTarget);
                String sourceLcPath = sourceLc.getPath();
                for (String exclude : lc.getExclusions()) {
                    String excludeAbsPath = Utils.appendPath(lc.getPath(), exclude);
                    if (!Text.isDescendant((String)sourceLcPath, (String)excludeAbsPath)) continue;
                    String movedPath = Utils.appendPath(moveTarget, Utils.relativePath(sourceLcPath, excludeAbsPath));
                    lc.addExclusion(Utils.relativePath(lc.getPath(), movedPath));
                }
            }
            lcManager.moveDependentLiveCopies(targetPage.getPath(), moveTarget);
            if (this.isReferenceUpdate) {
                this.updateReferences(target.getResourceResolver(), targetPage.getPath(), copy.getPath());
            }
        }

        protected ItemFilterImpl getFilter(Node node) throws RepositoryException {
            return this.filter;
        }

        private Page copyPage(Page sourcePage, String targetParent, String targetName, String before, String copyRoot, LiveCopyManagerImpl liveCopyManager) throws RepositoryException, WCMException {
            String template = sourcePage.getTemplate() == null ? null : sourcePage.getTemplate().getPath();
            PageManager pm = sourcePage.getPageManager();
            Page copy = pm.create(targetParent, targetName, template, null, false);
            if (before != null) {
                pm.order(copy, before);
            }
            if (sourcePage.hasContent()) {
                LiveCopyManagerImpl.LiveCopyImpl copyLc;
                LiveCopyManagerImpl.LiveCopyImpl lc;
                Node contentNode = (Node)sourcePage.getContentResource().adaptTo(Node.class);
                Node destNode = (Node)copy.getContentResource().adaptTo(Node.class);
                this.copyNodeFiltered(contentNode, destNode);
                if (liveCopyManager.get(sourcePage.getPath()) != null && (copyLc = liveCopyManager.copy(lc = liveCopyManager.get(sourcePage.getPath()), copy.getPath())).getMoveTarget() != null && Text.isDescendant((String)copyRoot, (String)copyLc.getMoveTarget())) {
                    String relMoveTarget = Utils.relativePath(copyRoot, copyLc.getMoveTarget());
                    int level = Utils.relativePath(copyRoot, sourcePage.getPath()).split("/").length;
                    copyLc.setMovedTarget(Utils.appendPath(Text.getRelativeParent((String)copy.getPath(), (int)level), relMoveTarget));
                }
                pm.touch(destNode, true, Calendar.getInstance(), true);
                this.rolloutManager.updateRolloutInfo(destNode, true, false);
                log.debug("Copied Page from {} to {}", (Object)sourcePage.getPath(), (Object)copy.getPath());
            }
            Iterator pages = sourcePage.listChildren();
            while (pages.hasNext()) {
                Page child = (Page)pages.next();
                this.copyPage(child, copy.getPath(), child.getName(), null, copyRoot, liveCopyManager);
            }
            return copy;
        }

        private void copyNodeFiltered(Node sourceNode, Node destNode) throws RepositoryException {
            for (NodeType mixin : sourceNode.getMixinNodeTypes()) {
                String mixinName = mixin.getName();
                if (!destNode.canAddMixin(mixinName)) continue;
                destNode.addMixin(mixinName);
            }
            Iterator itr = this.getFilteredProperties(sourceNode);
            while (itr.hasNext()) {
                Property prop = (Property)itr.next();
                JcrUtil.copy((Property)prop, (Node)destNode, (String)prop.getName());
            }
            Iterator nodes = this.getFilteredNodes(sourceNode);
            while (nodes.hasNext()) {
                Node scrChild = (Node)nodes.next();
                String childName = scrChild.getName();
                Node dstChild = destNode.hasNode(childName) ? destNode.getNode(childName) : destNode.addNode(childName, scrChild.getPrimaryNodeType().getName());
                this.copyNodeFiltered(scrChild, dstChild);
            }
        }

        private void updateReferences(ResourceResolver resolver, String target, String destination) throws RepositoryException, WCMException {
            Map res = this.search.search(resolver, target);
            for (ReferenceSearch.Info info : res.values()) {
                boolean needsTouch = false;
                for (String propertyPath : info.getProperties()) {
                    String nodePath = Text.getRelativeParent((String)propertyPath, (int)1);
                    if (RESERVED_NODENAMES.contains(Text.getName((String)nodePath))) {
                        log.debug("Skipped to update Reference in a reserved Node at {}", (Object)nodePath);
                        continue;
                    }
                    Resource resource = resolver.getResource(nodePath);
                    Node node = resource == null ? null : (Node)resource.adaptTo(Node.class);
                    if (node == null) continue;
                    needsTouch |= !this.search.adjustReferences(node, target, destination, true, Collections.emptySet()).isEmpty();
                }
                if (!needsTouch) continue;
                info.getPage().getPageManager().touch((Node)info.getPage().adaptTo(Node.class), true, Calendar.getInstance(), false);
            }
        }

        private static String findFollowingSibling(Page page) {
            String last = null;
            Page parent = page.getParent();
            if (parent != null) {
                Iterator children = parent.listChildren();
                while (children.hasNext()) {
                    Page child = (Page)children.next();
                    if (page.getPath().equals(last)) {
                        return child.getName();
                    }
                    last = child.getPath();
                }
            }
            return null;
        }

        private static boolean exists(Resource resource) {
            return resource != null && !ResourceUtil.isSyntheticResource((Resource)resource);
        }
    }

}