From 5b81c294ae7541cc6a2a5867d1e1e8aa7f4358b5 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 24 Jan 2011 08:42:45 +0000 Subject: [PATCH] Improve JCR utils git-svn-id: https://svn.argeo.org/commons/trunk@4070 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../src/main/java/org/argeo/jcr/JcrUtils.java | 101 ++++++++++++++++-- .../main/java/org/argeo/jcr/PropertyDiff.java | 63 +++++++++++ 2 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/PropertyDiff.java diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java index 707639526..d70a51669 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUtils.java @@ -21,7 +21,9 @@ import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Map; import java.util.StringTokenizer; +import java.util.TreeMap; import javax.jcr.NamespaceRegistry; import javax.jcr.Node; @@ -333,25 +335,102 @@ public class JcrUtils { /** * Check whether all first-level properties (except jcr:* properties) are - * equal. + * equal. Skip jcr:* properties */ - public static Boolean allPropertiesEquals(Node node1, Node node2) { + public static Boolean allPropertiesEquals(Node reference, Node observed, + Boolean onlyCommonProperties) { try { - PropertyIterator pit = node1.getProperties(); - while (pit.hasNext()) { - Property prop1 = pit.nextProperty(); - String propName = prop1.getName(); - if (!node2.hasProperty(propName)) - return false; + PropertyIterator pit = reference.getProperties(); + props: while (pit.hasNext()) { + Property propReference = pit.nextProperty(); + String propName = propReference.getName(); + if (propName.startsWith("jcr:")) + continue props; + + if (!observed.hasProperty(propName)) + if (onlyCommonProperties) + continue props; + else + return false; // TODO: deal with multiple property values? - if (!node2.getProperty(propName).getValue() - .equals(prop1.getValue())) + if (!observed.getProperty(propName).getValue() + .equals(propReference.getValue())) return false; } return true; } catch (RepositoryException e) { throw new ArgeoException("Cannot check all properties equals of " - + node1 + " and " + node2, e); + + reference + " and " + observed, e); + } + } + + public static Map diffProperties(Node reference, + Node observed) { + Map diffs = new TreeMap(); + diffPropertiesLevel(diffs, null, reference, observed); + return diffs; + } + + /** + * Compare the properties of two nodes. Recursivity to child nodes is not + * yet supported. Skip jcr:* properties. + */ + static void diffPropertiesLevel(Map diffs, + String baseRelPath, Node reference, Node observed) { + try { + // check removed and modified + PropertyIterator pit = reference.getProperties(); + props: while (pit.hasNext()) { + Property p = pit.nextProperty(); + String name = p.getName(); + if (name.startsWith("jcr:")) + continue props; + + if (!observed.hasProperty(name)) { + String relPath = propertyRelPath(baseRelPath, name); + PropertyDiff pDiff = new PropertyDiff(PropertyDiff.REMOVED, + relPath, p.getValue(), null); + diffs.put(relPath, pDiff); + } else { + if (p.isMultiple()) + continue props; + Value referenceValue = p.getValue(); + Value newValue = observed.getProperty(name).getValue(); + if (!referenceValue.equals(newValue)) { + String relPath = propertyRelPath(baseRelPath, name); + PropertyDiff pDiff = new PropertyDiff( + PropertyDiff.MODIFIED, relPath, referenceValue, + newValue); + diffs.put(relPath, pDiff); + } + } + } + // check added + pit = observed.getProperties(); + props: while (pit.hasNext()) { + Property p = pit.nextProperty(); + String name = p.getName(); + if (name.startsWith("jcr:")) + continue props; + if (!reference.hasProperty(name)) { + String relPath = propertyRelPath(baseRelPath, name); + PropertyDiff pDiff = new PropertyDiff(PropertyDiff.ADDED, + relPath, null, p.getValue()); + diffs.put(relPath, pDiff); + } + } + } catch (RepositoryException e) { + throw new ArgeoException("Cannot diff " + reference + " and " + + observed, e); } } + + /** Builds a property relPath to be used in the diff. */ + private static String propertyRelPath(String baseRelPath, + String propertyName) { + if (baseRelPath == null) + return propertyName; + else + return baseRelPath + '/' + propertyName; + } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/PropertyDiff.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/PropertyDiff.java new file mode 100644 index 000000000..67e5d8ac6 --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/PropertyDiff.java @@ -0,0 +1,63 @@ +package org.argeo.jcr; + +import javax.jcr.Value; + +import org.argeo.ArgeoException; + +/** The result of the comparison of two JCR properties. */ +public class PropertyDiff { + public final static Integer MODIFIED = 0; + public final static Integer ADDED = 1; + public final static Integer REMOVED = 2; + + private final Integer type; + private final String relPath; + private final Value referenceValue; + private final Value newValue; + + public PropertyDiff(Integer type, String relPath, Value referenceValue, + Value newValue) { + super(); + + if (type == MODIFIED) { + if (referenceValue == null || newValue == null) + throw new ArgeoException( + "Reference and new values must be specified."); + } else if (type == ADDED) { + if (referenceValue != null || newValue == null) + throw new ArgeoException( + "New value and only it must be specified."); + } else if (type == REMOVED) { + if (referenceValue == null || newValue != null) + throw new ArgeoException( + "Reference value and only it must be specified."); + } else { + throw new ArgeoException("Unkown diff type " + type); + } + + if (relPath == null) + throw new ArgeoException("Relative path must be specified"); + + this.type = type; + this.relPath = relPath; + this.referenceValue = referenceValue; + this.newValue = newValue; + } + + public Integer getType() { + return type; + } + + public String getRelPath() { + return relPath; + } + + public Value getReferenceValue() { + return referenceValue; + } + + public Value getNewValue() { + return newValue; + } + +} -- 2.30.2