You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/04/19 07:39:19 UTC

[jackrabbit-filevault] branch master updated: JCRVLT-516 simplify usage of DocViewProperties outside JCR context (#134)

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git


The following commit(s) were added to refs/heads/master by this push:
     new 3bc3d00  JCRVLT-516 simplify usage of DocViewProperties outside JCR context (#134)
3bc3d00 is described below

commit 3bc3d00c8c4e6d10e51c6897f7835f116fa789cc
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Mon Apr 19 09:39:09 2021 +0200

    JCRVLT-516 simplify usage of DocViewProperties outside JCR context (#134)
---
 .../jackrabbit/vault/util/DocViewProperty.java     | 207 +++++++++++++++------
 .../apache/jackrabbit/vault/util/package-info.java |   2 +-
 .../jackrabbit/vault/util/DocViewPropertyTest.java |   4 +-
 3 files changed, 153 insertions(+), 60 deletions(-)

diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
index eb3162f..d17cb71 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
@@ -17,6 +17,7 @@
 
 package org.apache.jackrabbit.vault.util;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -33,20 +34,27 @@ import javax.jcr.ValueFormatException;
 
 import org.apache.jackrabbit.api.ReferenceBinary;
 import org.apache.jackrabbit.commons.jackrabbit.SimpleReferenceBinary;
+import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.util.XMLChar;
 import org.apache.jackrabbit.value.ValueHelper;
-import org.apache.jackrabbit.util.Text;
 
 /**
  * Helper class that represents a (jcr) property in the document view format.
  * It contains formatting and parsing methods for writing/reading enhanced
  * docview properties.
- *
- * {@code prop:= [ "{" type "}" ] ( value | "[" [ value { "," value } ] "]" )}
+ * <br>
+ * The string representation adheres to the following grammar:
+ * <pre>
+ * <code>prop:= [ "{" type "}" ] ( value | "[" [ value { "," value } ] "]" )
+ * type := {@link PropertyType#nameFromValue(int)} | {@link #BINARY_REF}
+ * value := is a string representation of the value where the following characters are escaped: ',\[{' with a leading '\'
+ * </code>
+ * </pre>
+ * 
  */
 public class DocViewProperty {
 
-    private static final String BINARY_REF = "BinaryRef";
+    public static final String BINARY_REF = "BinaryRef";
 
     /**
      * name of the property
@@ -75,9 +83,9 @@ public class DocViewProperty {
     public final boolean isReferenceProperty;
 
     /**
-     * set of unambigous property names
+     * set of unambigous property names (which never need an explicit type descriptor as the types are defined by the spec)
      */
-    private static final Set<String> UNAMBIGOUS = new HashSet<String>();
+    private static final Set<String> UNAMBIGOUS = new HashSet<>();
     static {
         UNAMBIGOUS.add("jcr:primaryType");
         UNAMBIGOUS.add("jcr:mixinTypes");
@@ -96,6 +104,75 @@ public class DocViewProperty {
     }
 
     /**
+     * Creates a new property based on an array of Values
+     * @param name
+     * @param values the values (always an array, may be empty)
+     * @param type the type of the property
+     * @param isMulti {@code true} in case this is a multivalue property
+     * @param sort {@code true} in case the value array should be sorted first
+     * @param useBinaryReferences to use the binary reference as value (if available)
+     * @return the new property
+     * @throws RepositoryException
+     */
+    public static DocViewProperty fromValues(String name, Value[] values, int type, boolean isMulti, boolean sort, boolean useBinaryReferences) throws RepositoryException {
+        List<String> strValues = new ArrayList<>();
+        if (isMulti) {
+            if (sort) {
+                Arrays.sort(values, ValueComparator.getInstance());
+            }
+        }
+        for (Value value : values) {
+             strValues.add(serializeValue(value, useBinaryReferences));
+        }
+         
+        boolean isBinaryRef = false;
+        if (type == PropertyType.BINARY && !strValues.get(0).isEmpty()) {
+            isBinaryRef = true;
+        }
+        return new DocViewProperty(name, strValues.toArray(new String[0]), isMulti, type, isBinaryRef);
+    }
+
+    /**
+     * Creates a new property based on a JCR property object
+     * @param prop the jcr property
+     * @param sort if {@code true} multivalue properties should be sorted
+     * @param useBinaryReferences {@code true} to use binary references
+     * @return the new property
+     * @throws RepositoryException 
+     * @throws IllegalArgumentException if single value property and not exactly 1 value is given.
+     */
+    public static DocViewProperty fromProperty(Property prop, boolean sort, boolean useBinaryReferences) throws RepositoryException {
+        boolean isMultiValue = prop.getDefinition().isMultiple();
+        final Value[] values;
+        if (isMultiValue) {
+            values = prop.getValues();
+        } else {
+            values = new Value[] { prop.getValue() };
+        }
+        return fromValues(prop.getName(), values, prop.getType(), isMultiValue, sort, useBinaryReferences);
+    }
+
+    static String serializeValue(Value value, boolean useBinaryReferences) throws RepositoryException {
+        // special handling for binaries
+        String strValue = null;
+        if (value.getType() == PropertyType.BINARY) {
+            if (useBinaryReferences) {
+                Binary bin = value.getBinary();
+                if (bin instanceof ReferenceBinary) {
+                    strValue = ((ReferenceBinary) bin).getReference();
+                }
+            }
+            if (strValue == null) {
+                // leave value empty for other binaries
+                strValue = "";
+            }
+        } else {
+            strValue = ValueHelper.serialize(value, false);
+        }
+        return strValue;
+    }
+
+    /**
      * Creates a new property.
      * @param name name of the property
      * @param values values.
@@ -134,7 +211,7 @@ public class DocViewProperty {
         int pos = 0;
         char state = 'b';
         List<String> vals = null;
-        StringBuffer tmp = new StringBuffer();
+        StringBuilder tmp = new StringBuilder();
         int unicode = 0;
         int unicodePos = 0;
         while (pos < value.length()) {
@@ -264,62 +341,51 @@ public class DocViewProperty {
      */
     public static String format(Property prop, boolean sort, boolean useBinaryReferences)
             throws RepositoryException {
-        StringBuffer attrValue = new StringBuffer();
-        int type = prop.getType();
-        if (type == PropertyType.BINARY || isAmbiguous(prop)) {
-            String referenceBinary = null;
-            if (useBinaryReferences && type == PropertyType.BINARY) {
-                Binary bin = prop.getBinary();
-                if (bin != null && bin instanceof ReferenceBinary) {
-                    referenceBinary = ((ReferenceBinary) bin).getReference();
-                }
-            }
+        return fromProperty(prop, sort, useBinaryReferences).format();
+    }
 
-            if (referenceBinary == null) {
-                attrValue.append("{");
-                attrValue.append(PropertyType.nameFromValue(prop.getType()));
-                attrValue.append("}");
+    /** 
+     * Generates string representation of this DocView property.
+     * @return the string representation
+     */
+    String format() {
+        StringBuilder attrValue = new StringBuilder();
+        
+        if (isAmbiguous(type, name)) {
+            final String strType;
+            if (isReferenceProperty) {
+                strType = BINARY_REF;
             } else {
-                attrValue.append("{");
-                attrValue.append(BINARY_REF);
-                attrValue.append("}");
-                attrValue.append(referenceBinary);
+                strType = PropertyType.nameFromValue(type);
             }
+            attrValue.append('{').append(strType).append('}');
         }
-        // only write values for non binaries
-        if (prop.getType() != PropertyType.BINARY) {
-            if (prop.getDefinition().isMultiple()) {
-                attrValue.append('[');
-                Value[] values = prop.getValues();
-                if (sort) {
-                    Arrays.sort(values, ValueComparator.getInstance());
+        if (isMulti) {
+            attrValue.append('[');
+        }
+        for (int i=0;i<values.length;i++) {
+            String value = values[i];
+            if (values.length == 1 && value.length() == 0) {
+                // special case for empty string MV value (JCR-3661)
+                attrValue.append("\\0");
+            } else {
+                if (i > 0) {
+                    attrValue.append(',');
                 }
-                for (int i = 0; i < values.length; i++) {
-                    if (i > 0) {
-                        attrValue.append(',');
-                    }
-                    String strValue = ValueHelper.serialize(values[i], false);
-                    if (values.length == 1 && strValue.length() == 0) {
-                        // special case for empty string MV value (JCR-3661)
-                        attrValue.append("\\0");
-                    } else {
-                        switch (prop.getType()) {
-                            case PropertyType.STRING:
-                            case PropertyType.NAME:
-                            case PropertyType.PATH:
-                                escape(attrValue, strValue, true);
-                                break;
-                            default:
-                                attrValue.append(strValue);
-                        }
-                    }
+                switch (type) {
+                    case PropertyType.STRING:
+                    case PropertyType.NAME:
+                    case PropertyType.PATH:
+                        attrValue.append(escape(value, isMulti));
+                        break;
+                    default:
+                        attrValue.append(value);
                 }
-                attrValue.append(']');
-            } else {
-                String strValue = ValueHelper.serialize(prop.getValue(), false);
-                escape(attrValue, strValue, false);
             }
         }
+        if (isMulti) {
+            attrValue.append(']');
+        }
         return attrValue.toString();
     }
 
@@ -328,8 +394,21 @@ public class DocViewProperty {
      * @param buf buffer to append to
      * @param value value to escape
      * @param isMulti indicates multi value property
+     * @deprecated Rather use {@link #escape(String, boolean)}
      */
+    @Deprecated
     protected static void escape(StringBuffer buf, String value, boolean isMulti) {
+        buf.append(escape(value, isMulti));
+    }
+
+    /**
+     * Escapes the value
+     * @param value value to escape
+     * @param isMulti indicates multi value property
+     * @return the escaped value
+     */
+    protected static String escape(String value, boolean isMulti) {
+        StringBuilder buf = new StringBuilder();
         for (int i=0; i<value.length(); i++) {
             char c = value.charAt(i);
             if (c == '\\') {
@@ -348,6 +427,7 @@ public class DocViewProperty {
                 buf.append(c);
             }
         }
+        return buf.toString();
     }
     
     /**
@@ -358,9 +438,24 @@ public class DocViewProperty {
      * @param prop the property
      * @return type
      * @throws RepositoryException if a repository error occurs
+     * @deprecated was not supposed to be public but rather is an implementation detail, should not be called at all
      */
+    @Deprecated
     public static boolean isAmbiguous(Property prop) throws RepositoryException {
-        return prop.getType() != PropertyType.STRING && !UNAMBIGOUS.contains(prop.getName());
+        return isAmbiguous(prop.getType(), prop.getName());
+    }
+
+    /**
+     * Checks if the type of the given property is ambiguous in respect to it's
+     * property definition. the current implementation just checks some well
+     * known properties.
+     *
+     * @param type the type
+     * @param name the name
+     * @return {@code true} if type information should be emitted, otherwise {@code false}
+     */
+    private static boolean isAmbiguous(int type, String name) {
+        return type != PropertyType.STRING && !UNAMBIGOUS.contains(name);
     }
 
     /**
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
index 863a0c3..c40fa9a 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/package-info.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("2.6.1")
+@Version("2.7.0")
 package org.apache.jackrabbit.vault.util;
 
 import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/util/DocViewPropertyTest.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/util/DocViewPropertyTest.java
index e69fb8e..d20b447 100644
--- a/vault-core/src/test/java/org/apache/jackrabbit/vault/util/DocViewPropertyTest.java
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/util/DocViewPropertyTest.java
@@ -204,9 +204,7 @@ public class DocViewPropertyTest {
     }
 
     private void assertEscaped(String original, String expected, boolean multi) {
-        StringBuffer buf = new StringBuffer();
-        DocViewProperty.escape(buf, original, multi);
-        Assert.assertEquals(expected, buf.toString());
+        Assert.assertEquals(expected, DocViewProperty.escape(original, multi));
     }
 
     private void assertEquals(DocViewProperty p, boolean multi, int type, String... values) {