Cq60MSMContentUpgrade.java 9.62 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.text.Text
 *  javax.jcr.ItemNotFoundException
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.Value
 *  javax.jcr.ValueFactory
 *  javax.jcr.Workspace
 *  javax.jcr.query.Query
 *  javax.jcr.query.QueryManager
 *  javax.jcr.query.QueryResult
 *  javax.jcr.version.Version
 *  javax.jcr.version.VersionHistory
 *  javax.jcr.version.VersionIterator
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.compat.codeupgrade.impl.cq60;

import com.day.cq.compat.codeupgrade.internal.api.ProgressInfoProvider;
import com.day.text.Text;
import java.util.Calendar;
import java.util.HashSet;
import javax.jcr.ItemNotFoundException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.Workspace;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.version.Version;
import javax.jcr.version.VersionHistory;
import javax.jcr.version.VersionIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Cq60MSMContentUpgrade
implements ProgressInfoProvider {
    private static final String NT_LIVE_RELATIONSHIP = "cq:LiveRelationship";
    private static final String STATEMENT = String.format("/jcr:root/jcr:system/jcr:versionStorage//*[%s/@%s='%s']", "jcr:frozenNode", "jcr:frozenMixinTypes", "cq:LiveRelationship");
    private static final String PN_CQ_PARENT_PATH = "cq:parentPath";
    private static final String PN_CQ_NAME = "cq:name";
    private static final Logger log = LoggerFactory.getLogger(Cq60MSMContentUpgrade.class);
    private static final int COMMIT_SIZE = 1024;
    private static final int HEART_BEAT_FREQUENCY = 1000;
    private String progressInfo = "No info yet";

    @Override
    public String getProgressInfo() {
        return this.progressInfo;
    }

    void setProgressInfo(String info) {
        this.progressInfo = info;
        log.info(this.progressInfo);
    }

    public void doUpgrade(Session session) throws Exception {
        QueryManager qm = session.getWorkspace().getQueryManager();
        int changed = this.changeDeletedLiveRelationships(qm);
        this.setProgressInfo(String.format("Changed %s LiveCopies to ", changed));
        if (session.hasPendingChanges()) {
            session.save();
        }
    }

    int changeDeletedLiveRelationships(QueryManager queryManager) throws RepositoryException {
        int total = 0;
        int commitCnt = 0;
        Query query = queryManager.createQuery(STATEMENT, "xpath");
        NodeIterator res = query.execute().getNodes();
        int heartbeat = 0;
        while (res.hasNext()) {
            Node versionNode = res.nextNode();
            Version v = (Version)versionNode;
            if (Cq60MSMContentUpgrade.filterVersion(v)) {
                Session session = v.getSession();
                String path = Cq60MSMContentUpgrade.buildPath(v);
                if (path != null && !session.nodeExists(path)) {
                    log.debug("Found deleted LiveRelationship at {}", (Object)path);
                    Node parent = Cq60MSMContentUpgrade.getClosestParentRelation(session, path);
                    if (parent != null) {
                        log.debug("Parent of deleted liveRelation found at {}", (Object)parent);
                        LiveCopy lc = Cq60MSMContentUpgrade.getClosestLiveCopy(parent);
                        if (lc != null && lc.addExclusion(path)) {
                            ++total;
                            this.setProgressInfo(String.format("Add exclusion to LiveCopy at %s for %s", lc.path, path));
                            if (commitCnt == 1024) {
                                session.save();
                                commitCnt = 0;
                            } else {
                                ++commitCnt;
                            }
                        } else {
                            log.debug("LiveCopy of deleted LiveRelation at {} missing: no updated", (Object)parent);
                        }
                    }
                }
            }
            if (heartbeat++ <= 1000) continue;
            this.setProgressInfo(String.format("...inspected %s Versions for deleted LiveRelationship", 1000));
            heartbeat = 0;
        }
        return total;
    }

    private static boolean filterVersion(Version v) throws RepositoryException {
        VersionHistory vh = v.getContainingHistory();
        String vI = vh.getVersionableIdentifier();
        try {
            v.getSession().getNodeByIdentifier(vI);
            return false;
        }
        catch (ItemNotFoundException e) {
            VersionIterator itr = vh.getAllVersions();
            Version last = null;
            while (itr.hasNext()) {
                Version next = itr.nextVersion();
                if (last != null && !next.getCreated().after(last.getCreated())) continue;
                last = next;
            }
            if (last != null) {
                Property mixin = last.getFrozenNode().getProperty("jcr:frozenMixinTypes");
                for (Value value : mixin.getValues()) {
                    if (!"cq:LiveRelationship".equals(value.getString())) continue;
                    return true;
                }
            }
            return false;
        }
    }

    private static LiveCopy getClosestLiveCopy(Node parent) throws RepositoryException {
        LiveCopy lc = LiveCopy.create(parent);
        if (lc == null) {
            if (parent.getParent() != null && Cq60MSMContentUpgrade.isLiveRelationship(parent.getParent())) {
                return Cq60MSMContentUpgrade.getClosestLiveCopy(parent.getParent());
            }
        } else if (lc.isDeep()) {
            return lc;
        }
        return null;
    }

    private static Node getClosestParentRelation(Session session, String path) throws RepositoryException {
        String parent = Text.getRelativeParent((String)path, (int)1);
        while (parent != null) {
            if (session.nodeExists(parent)) {
                Node parentNode = session.getNode(parent);
                if (!Cq60MSMContentUpgrade.isLiveRelationship(parentNode)) break;
                return parentNode;
            }
            parent = Text.getRelativeParent((String)parent, (int)1);
        }
        return null;
    }

    private static String buildPath(Version version) throws RepositoryException {
        Node frozenNode = version.getFrozenNode();
        if (frozenNode.hasProperty("cq:name") && frozenNode.hasProperty("cq:parentPath")) {
            return frozenNode.getProperty("cq:parentPath").getString() + "/" + frozenNode.getProperty("cq:name").getString();
        }
        return null;
    }

    private static boolean isLiveRelationship(Node node) throws RepositoryException {
        return node.hasNode("jcr:content") && node.getNode("jcr:content").isNodeType("cq:LiveRelationship");
    }

    private static class LiveCopy {
        private static final String NT_LIVE_SYNC_CONFIG = "cq:LiveSyncConfig";
        private static final String PATH_CONFIG = "jcr:content/cq:LiveSyncConfig";
        private static final String PN_EXCLUDES = "cq:excludedPaths";
        private static final String PN_IS_DEEP = "cq:isDeep";
        private static final String NT_LC_PATH_FILTER = "cq:LcPathFilter";
        private final Node node;
        private final String path;

        public LiveCopy(Node node) throws RepositoryException {
            this.node = node.getNode("jcr:content/cq:LiveSyncConfig");
            this.path = node.getPath();
        }

        public boolean isDeep() throws RepositoryException {
            return this.node.hasProperty("cq:isDeep") && this.node.getProperty("cq:isDeep").getBoolean();
        }

        private static LiveCopy create(Node node) throws RepositoryException {
            if (node.hasProperty("jcr:content/cq:LiveSyncConfig/cq:master")) {
                return new LiveCopy(node);
            }
            return null;
        }

        public boolean addExclusion(String absPath) throws RepositoryException {
            String relPath = this.makeRelative(absPath);
            if (relPath == null) {
                log.error("Attempt to set non descendant {} to LiveCopy {}", (Object)this.path, (Object)this.path);
                return false;
            }
            HashSet<Value> values = new HashSet<Value>();
            if (this.node.hasProperty("cq:excludedPaths")) {
                for (Value value : this.node.getProperty("cq:excludedPaths").getValues()) {
                    String saved = value.getString();
                    if (saved.equals(relPath) || relPath.startsWith(saved + "/")) {
                        return false;
                    }
                    if (saved.startsWith(relPath + "/")) continue;
                    values.add(value);
                }
            }
            ValueFactory factory = this.node.getSession().getValueFactory();
            values.add(factory.createValue(relPath));
            if (!this.node.isNodeType("cq:LcPathFilter")) {
                this.node.addMixin("cq:LcPathFilter");
            }
            this.node.setProperty("cq:excludedPaths", values.toArray((T[])new Value[values.size()]));
            return true;
        }

        private String makeRelative(String descendant) {
            if (this.path.length() < descendant.length() + 1) {
                return descendant.substring(this.path.length() + 1);
            }
            return null;
        }
    }

}