Diff.java 9.81 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.jcr.Binary
 *  javax.jcr.Item
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.PropertyIterator
 *  javax.jcr.RepositoryException
 *  javax.jcr.Value
 *  javax.jcr.ValueFormatException
 */
package com.day.jcr.diff;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.jcr.Binary;
import javax.jcr.Item;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;

public class Diff {
    Map<Item, ChangeType> changes = new HashMap<Item, ChangeType>();

    public Map<Item, ChangeType> getChanges() {
        return this.changes;
    }

    public boolean hasChanges() {
        return !this.changes.keySet().isEmpty();
    }

    public int getSize() {
        return this.changes.keySet().size();
    }

    public static Diff compareNodes(Node a, Node b) throws Exception {
        return Diff.compareNodes(a, b, new String[0]);
    }

    public static Diff compareNodes(Node a, Node b, String[] excludes) throws Exception {
        Diff diff = new Diff();
        diff.add(Diff.compareProperties(a, b, excludes));
        HashMap<String, Node> targetNodes = new HashMap<String, Node>();
        NodeIterator nIt = b.getNodes();
        while (nIt.hasNext()) {
            Node node = nIt.nextNode();
            targetNodes.put(node.getName(), node);
        }
        nIt = a.getNodes();
        while (nIt.hasNext()) {
            Node ref = nIt.nextNode();
            String name = ref.getName();
            if (targetNodes.containsKey(name)) {
                Node target = (Node)targetNodes.get(name);
                diff.add(Diff.compareNodes(ref, target, excludes));
                targetNodes.remove(name);
                continue;
            }
            diff.add((Item)ref, ChangeType.DELETE);
        }
        Iterator names = targetNodes.keySet().iterator();
        while (names.hasNext()) {
            Node node = (Node)targetNodes.get(names.next());
            diff.add((Item)node, ChangeType.ADD);
        }
        return diff;
    }

    public static Diff compareProperties(Node a, Node b) throws Exception {
        return Diff.compareProperties(a, b, new String[0]);
    }

    public static Diff compareProperties(Node a, Node b, String[] excludes) throws Exception {
        Diff diff = new Diff();
        List<String> exludeNames = Arrays.asList(excludes);
        HashMap<String, Property> targetProps = new HashMap<String, Property>();
        PropertyIterator pIt = b.getProperties();
        while (pIt.hasNext()) {
            Property prop = pIt.nextProperty();
            targetProps.put(prop.getName(), prop);
        }
        pIt = a.getProperties();
        while (pIt.hasNext()) {
            Property ref = pIt.nextProperty();
            String name = ref.getName();
            if (exludeNames.contains(name)) continue;
            if (targetProps.containsKey(name)) {
                Value[] targetValues;
                Value[] refValues;
                Property target = (Property)targetProps.get(name);
                if (ref.getType() != target.getType()) {
                    diff.add((Item)ref, ChangeType.MODIFIED);
                    continue;
                }
                if (ref.isMultiple() != target.isMultiple()) {
                    diff.add((Item)ref, ChangeType.MODIFIED);
                    continue;
                }
                if (ref.isMultiple()) {
                    refValues = ref.getValues();
                    targetValues = target.getValues();
                } else {
                    refValues = new Value[]{ref.getValue()};
                    targetValues = new Value[]{target.getValue()};
                }
                ChangeType ct = Diff.compare(refValues, targetValues);
                if (ct == ChangeType.MODIFIED) {
                    diff.add((Item)ref, ct);
                }
                targetProps.remove(name);
                continue;
            }
            diff.add((Item)ref, ChangeType.DELETE);
        }
        Iterator names = targetProps.keySet().iterator();
        while (names.hasNext()) {
            Property prop = (Property)targetProps.get(names.next());
            if (exludeNames.contains(prop.getName())) continue;
            diff.add((Item)prop, ChangeType.ADD);
        }
        return diff;
    }

    private static ChangeType compare(Value[] v1, Value[] v2) throws Exception {
        if (v1.length != v2.length) {
            return ChangeType.MODIFIED;
        }
        ChangeType ct = ChangeType.NONE;
        for (int i = 0; i < v1.length && (ct = Diff.compare(v1[i], v2[i])) != ChangeType.MODIFIED; ++i) {
        }
        return ct;
    }

    private static ChangeType compare(Value v1, Value v2) throws Exception {
        switch (v1.getType()) {
            case 1: {
                return Diff.compareString(v1, v2);
            }
            case 2: {
                return Diff.compareBinary(v1, v2);
            }
            case 6: {
                return Diff.compareBoolean(v1, v2);
            }
            case 5: {
                return Diff.compareDate(v1, v2);
            }
            case 12: {
                return Diff.compareDecimal(v1, v2);
            }
            case 4: {
                return Diff.compareDouble(v1, v2);
            }
            case 3: {
                return Diff.compareLong(v1, v2);
            }
            case 7: {
                return Diff.compareString(v1, v2);
            }
            case 8: {
                return Diff.compareString(v1, v2);
            }
            case 9: {
                return Diff.compareString(v1, v2);
            }
            case 11: {
                return Diff.compareString(v1, v2);
            }
            case 10: {
                return Diff.compareString(v1, v2);
            }
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareBinary(Value v1, Value v2) throws Exception {
        byte[] h2;
        byte[] h1 = Diff.calcHash(v1.getBinary().getStream());
        if (!Arrays.equals(h1, h2 = Diff.calcHash(v2.getBinary().getStream()))) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static byte[] calcHash(InputStream is) throws RepositoryException, IOException, NoSuchAlgorithmException {
        byte[] buf = new byte[is.available()];
        is.read(buf);
        MessageDigest digest = MessageDigest.getInstance("MD5");
        digest.update(buf);
        return digest.digest();
    }

    private static ChangeType compareLong(Value v1, Value v2) throws ValueFormatException, RepositoryException {
        if (v1.getLong() != v2.getLong()) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareDouble(Value v1, Value v2) throws ValueFormatException, RepositoryException {
        if (v1.getDouble() != v2.getDouble()) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareDecimal(Value v1, Value v2) throws ValueFormatException, RepositoryException {
        if (v1.getDecimal() != v2.getDecimal()) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareDate(Value v1, Value v2) throws ValueFormatException, RepositoryException {
        if (v1.getDate().after(v2.getDate()) || v1.getDate().before(v2.getDate())) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareBoolean(Value v1, Value v2) throws ValueFormatException, RepositoryException {
        if (v1.getBoolean() != v2.getBoolean()) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private static ChangeType compareString(Value v1, Value v2) throws RepositoryException {
        if (!v1.getString().equals(v2.getString())) {
            return ChangeType.MODIFIED;
        }
        return ChangeType.NONE;
    }

    private void add(Item item, ChangeType type) {
        this.changes.put(item, type);
    }

    private void add(Diff diff) {
        for (Item item : diff.changes.keySet()) {
            this.changes.put(item, diff.changes.get((Object)item));
        }
    }

    public void print(OutputStream out) throws RepositoryException {
        PrintWriter w = new PrintWriter(out);
        w.println(this.toString());
        w.flush();
    }

    public String toString() {
        StringBuffer buf = new StringBuffer();
        for (Item item : this.changes.keySet()) {
            try {
                buf.append((Object)((Object)this.changes.get((Object)item)) + " " + item.getPath() + "\n");
            }
            catch (RepositoryException e) {}
        }
        return buf.toString();
    }

    static enum ChangeType {
        ADD,
        DELETE,
        MODIFIED,
        NONE;
        

        private ChangeType() {
        }

        public String toString() {
            switch (this) {
                case ADD: {
                    return "A";
                }
                case DELETE: {
                    return "D";
                }
                case MODIFIED: {
                    return "M";
                }
                case NONE: {
                    return "N";
                }
            }
            return Enum.super.toString();
        }
    }

}