All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.commons.DiffInfo Maven / Gradle / Ivy

/*
 * Copyright 1997-2009 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.commons;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.*;
import javax.jcr.version.Version;

import org.apache.commons.lang.time.FastDateFormat;
import org.apache.sling.api.resource.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.commons.jcr.JcrConstants;

/**
 * The DiffInfo can be used by components
 * to display a diff to a previous version.
 * A component has access to the diff information by
 * calling {@link Resource#adaptTo(Class)} with this
 * class as the argument.
 *
 * @since 5.2
 */
public class DiffInfo {

    public static final FastDateFormat DATE_DEFAULT = FastDateFormat.getInstance("dd.MM.yyyy HH:mm:ss");

    /**
     * default logger
     */
    private static final Logger log = LoggerFactory.getLogger(DiffInfo.class);

    /**
     * The general information about the diff
     */
    public enum TYPE {
        /**
         * this resource is new and not contained in the old version
         */
        ADDED,

        /**
         * this resource has been removed and is only in the old version
         */
        REMOVED,

        /**
         * this resource is in both versions but at different locations
         */
        MOVED,

        /**
         * resource is in both versions at the same location
         */
        SAME
    }

    /**
     * The content to diff.
     */
    private final Resource content;

    /**
     * The type information
     */
    private final TYPE type;

    public DiffInfo(final Resource c, final TYPE l) {
        this.content = c;
        this.type = l;
    }

    /**
     * Return the content to diff.
     *
     * @return The content or null
     */
    public Resource getContent() {
        return this.content;
    }

    /**
     * Return the type information.
     *
     * @return The type information.
     */
    public TYPE getType() {
        return this.type;
    }

    /**
     * Helper method to generate the diff output.
     *
     * @param service    The diff service.
     * @param current    The current text (right).
     * @param oldText    The old text (left).
     * @param isRichText Is this rich text?
     * @return The complete output or null.
     */
    public String getDiffOutput(DiffService service, String current,
                                String oldText, boolean isRichText) {
        if (service != null) {
            if (getType() == DiffInfo.TYPE.ADDED) {
                return service.diff(current, null, isRichText);
            } else if (getType() == DiffInfo.TYPE.REMOVED) {
                return service.diff(null, oldText, isRichText);
            }
            return service.diff(current, oldText, isRichText);
        }
        return null;
    }

    /**
     * Helper method that returns the versioned counterpart of the given resource
     * with the specified version label. The label can be a version name, a
     * version label or a version date.
     *
     * @param res the resource
     * @param versionLabel the version specifier
     * @return the versioned resource or null
     */
    public static Resource getVersionedResource(Resource res, String versionLabel) {
        Node currentNode = res.adaptTo(Node.class);
        if (currentNode == null) {
            return null;
        }
        try {
            Node versionNode = getVersionedNode(currentNode, versionLabel);
            if (versionNode != null) {
                return res.getResourceResolver().getResource(versionNode.getPath());
            }
        } catch (RepositoryException e) {
            log.error("Error while trying to get versioned node for path " + res.getPath() + ", version " + versionLabel, e);
        }
        return null;
    }

    /**
     * Get the versioned node for a node.
     *
     * @param node       The current node.
     * @param versionTag The version tag or label
     * @return The versioned node or null
     * @throws RepositoryException if an error occurs
     */
    private static Node getVersionedNode(Node node, String versionTag)
            throws RepositoryException {
        String path = node.getPath();
        while (node != null && !node.isNodeType(JcrConstants.MIX_VERSIONABLE)) {
            if (node.getDepth() > 0) {
                node = node.getParent();
            } else {
                node = null;
            }
        }
        if (node == null) {
            log.debug("getVersionedNode: No versionable node exists at path '{}'", path);
            return null;
        }
        // we have the versionable node, let's get the version
        //check if we can parse the version info as a date
        Node versionNode = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DATE_DEFAULT.getPattern());
            Date d = sdf.parse(versionTag);
            Calendar versionDate = Calendar.getInstance();
            versionDate.setTime(d);
            versionNode = getVersion(node, versionDate);
        } catch (ParseException e) {
            // we ignore this
        }
        if (versionNode == null) {
            try {
                versionNode = node.getVersionHistory().getVersion(versionTag);
            } catch (VersionException ve) {
                try {
                    versionNode = node.getVersionHistory().getVersionByLabel(versionTag);
                } catch (VersionException ve2) {
                    // we just ignore this
                }
            }
        }
        if (versionNode == null) {
            log.debug("getVersionedNode: Version '{}' not found for path '{}'", versionTag, path);
            return null;

        }
        // try to get child
        if (!node.getPath().equals(path)) {
            Session session = node.getSession();
            // build complete path:
            String childPath = versionNode.getPath() + "/" + JcrConstants.JCR_FROZENNODE + path.substring(node.getPath().length());
            if (!session.itemExists(childPath)) {
                log.debug("getVersionedNode: Version '{}' not found for path '{}'", versionTag, path);
                return null;
            }
            versionNode = (Node) session.getItem(childPath);
        } else {
            if (versionNode.hasNode(JcrConstants.JCR_FROZENNODE)) {
                versionNode = versionNode.getNode(JcrConstants.JCR_FROZENNODE);
            } else {
                log.debug("getVersionedNode: Frozen node not found in version '{}' for path '{}'", versionTag, path);
                return null;
            }
        }
        return versionNode;
    }

    /**
     * Get the versioned node closest to the provided date.
     * @param versionedNode the versionable node
     * @param cal the date
     * @return the versioned node or null
     * @throws RepositoryException if an error occurs
     */
    private static Node getVersion(Node versionedNode, Calendar cal)
            throws RepositoryException {
        ArrayList revisions = new ArrayList();

        VersionIterator iter = versionedNode.getVersionHistory().getAllVersions();
        while (iter.hasNext()) {
            revisions.add(iter.nextVersion());
        }

        // sort revisions by creation date in descending order
        Collections.sort(revisions, new Comparator() {
            public int compare(Version r1, Version r2) {
                try {
                    return r2.getCreated().compareTo(r1.getCreated());
                } catch (RepositoryException re) {
                    // we ignore this - no good way to handle it.
                    return 0;
                }
            }
        });

        for (Version v : revisions) {
            if (v.getCreated().compareTo(cal) <= 0) {
                return v;
            }
        }
        return null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy