jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject svn commit: r109221 - in incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core: . nodetype
Date Tue, 30 Nov 2004 18:12:22 GMT
Author: stefan
Date: Tue Nov 30 10:12:21 2004
New Revision: 109221

URL: http://svn.apache.org/viewcvs?view=rev&rev=109221
Log:
- fixed value constraint handling as spec'ed
- misc. minor fixes
Modified:
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java
   incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/NodeImpl.java	Tue Nov 30
10:12:21 2004
@@ -1163,7 +1163,8 @@
         Path.PathElement insertName;
         try {
             Path p = Path.create(srcName, session.getNamespaceResolver(), false);
-            if (p.getAncestorCount() > 0) {
+            // p must be a relative path of length==depth==1 (to eliminate e.g. "..")
+            if (p.isAbsolute() || p.getLength() != 1 || p.getDepth() != 1) {
                 throw new RepositoryException("invalid name: " + srcName);
             }
             insertName = p.getNameElement();
@@ -1177,7 +1178,8 @@
         if (destName != null) {
             try {
                 Path p = Path.create(destName, session.getNamespaceResolver(), false);
-                if (p.getAncestorCount() > 0) {
+                // p must be a relative path of length==depth==1 (to eliminate e.g. "..")
+                if (p.isAbsolute() || p.getLength() != 1 || p.getDepth() != 1) {
                     throw new RepositoryException("invalid name: " + destName);
                 }
                 beforeName = p.getNameElement();

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java	(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/Path.java	Tue Nov 30 10:12:21
2004
@@ -168,10 +168,11 @@
 
     /**
      * Creates a relative path based on a {@link QName} and an index.
-     * @param name single {@link QName} for this relative path.
+     *
+     * @param name  single {@link QName} for this relative path.
      * @param index index of the sinlge name element.
      * @return the relative path created from <code>name</code>.
-     * @exception IllegalArgumentException if <code>index</code> is negative.
+     * @throws IllegalArgumentException if <code>index</code> is negative.
      */
     public static Path create(QName name, int index) {
         if (index < 0) {
@@ -238,7 +239,7 @@
 
     /**
      * Tests whether this path is canonical, i.e. whether it is absolute and
-     * does not contain redundant names such as "." and "..".
+     * does not contain redundant elements such as "." and "..".
      *
      * @return true if this path is canonical; false otherwise.
      * @see #isAbsolute()
@@ -247,7 +248,7 @@
         if (!isAbsolute()) {
             return false;
         }
-        // check path for "." and ".." names
+        // check path for any "." and ".." elements
         for (int i = 0; i < elements.length; i++) {
             if (elements[i].equals(CURRENT_ELEMENT)
                     || elements[i].equals(PARENT_ELEMENT)) {
@@ -258,8 +259,81 @@
     }
 
     /**
+     * Tests whether this path is normalized, i.e. whether it does not
+     * contain redundant elements such as "." and "..".
+     * <p/>
+     * Note that a normalized path can still contain ".." elements if they are
+     * not redundant, e.g. "../../a/b/c" would be a normalized relative path,
+     * whereas "../a/../../a/b/c" wouldn't (although they're semantically
+     * equivalent).
+     *
+     * @return true if this path is normalized; false otherwise.
+     * @see #getNormalizedPath()
+     */
+    public boolean isNormalized() {
+        if (isAbsolute()) {
+            /**
+             * a normalized absolute path has to be canonical, i.e. it
+             * cannot contain any "." and ".." elements
+             */
+            return isCanonical();
+        }
+
+        // check relative path for redundant "." and ".." elements only
+        for (int i = 0; i < elements.length; i++) {
+            if (elements[i].equals(CURRENT_ELEMENT)) {
+                // "." is always redundant
+                return false;
+            }
+            if (elements[i].equals(PARENT_ELEMENT)) {
+                /**
+                 * ".." is redundant only if there's a preceeding
+                 * non-".." element
+                 */
+                if (i > 0 && !elements[i - 1].equals(PARENT_ELEMENT)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns the normalized path representation of this path. This typically
+     * involves removing/resolving redundant elements such as "." and ".." from
+     * the path, e.g. "/a/./b/.." will be normalized to "/a", "../../a/b/c/.."
+     * will be normalized to "../../a/b", and so on.
+     *
+     * @return a normailzed path representation of this path
+     * @see #isNormalized()
+     */
+    public Path getNormalizedPath() {
+        if (isNormalized()) {
+            return this;
+        }
+
+        LinkedList queue = new LinkedList();
+        for (int i = 0; i < elements.length; i++) {
+            PathElement elem = elements[i];
+
+            if (elem.equals(CURRENT_ELEMENT)) {
+                continue;
+            } else if (elem.equals(PARENT_ELEMENT)) {
+                if (queue.size() > 0 && !queue.getLast().equals(PARENT_ELEMENT))
{
+                    queue.removeLast();
+                } else {
+                    queue.add(elem);
+                }
+            } else {
+                queue.add(elem);
+            }
+        }
+        return new Path((PathElement[]) queue.toArray(new PathElement[queue.size()]));
+    }
+
+    /**
      * Returns the canonical path representation of this path. This typically
-     * involves removing/resolving redundant names such as "." and ".." from
+     * involves removing/resolving redundant elements such as "." and ".." from
      * the path.
      *
      * @return a canonical path representation of this path
@@ -306,6 +380,10 @@
      * <li>And so on to <i>degree</i> = <i>n</i>, where <i>n</i>
is the depth
      * of this path, which returns the root path.
      * </ul>
+     * <p/>
+     * Note that there migth be an unexpected result if <i>this</i> path is not
+     * canonical, e.g. the ancestor of degree = 1 of the path "../.." would
+     * be ".." although this is not the parent of "../..".
      *
      * @param degree the relative degree of the requested ancestor.
      * @return the ancestor path of the specified degree.
@@ -331,33 +409,91 @@
     }
 
     /**
-     * Returns the number of ancestors of this path.
+     * Returns the number of ancestors of this path. This is the equivalent
+     * of <code>{@link #getDepth()} - 1</code>.
+     * <p/>
+     * Note that the returned value might be negative if this path is not
+     * canonical, e.g. the depth of "../../a" is -1, its ancestor count is
+     * therefore -2.
      *
      * @return the number of ancestors of this path
+     * @see #getDepth()
+     * @see #getLength()
+     * @see #isCanonical()
      */
     public int getAncestorCount() {
-        return elements.length - 1;
+        return getDepth() - 1;
     }
 
     /**
-     * Determines if <i>this</i> path is an ancestor of the specified path.
+     * Returns the length of this path, i.e. the number of its elements.
+     * Note that the root element "/" counts as a separate element, e.g.
+     * the length of "/a/b/c" is 4 whereas the length of "a/b/c" is 3.
+     * <p/>
+     * Also note that the special elements "." and ".." are not treated
+     * specially, e.g. both "/a/./.." and "/a/b/c" have a length of 4
+     * but this value does not necessarily reflect the true hierarchy level as
+     * returned by <code>{@link #getDepth()}</code>.
+     *
+     * @return the length of this path
+     * @see #getDepth()
+     * @see #getAncestorCount()
+     */
+    public int getLength() {
+        return elements.length;
+    }
+
+    /**
+     * Returns the depth of this path. The depth reflects the absolute or
+     * relative hierarchy level this path is representing, depending on whether
+     * this path is an absolute or a relative path.
+     * <p/>
+     * Note that the returned value might be negative if this path is not
+     * canonical, e.g. the depth of "../../a" is -1.
+     *
+     * @return the depth this path
+     * @see #getLength()
+     * @see #getAncestorCount()
+     */
+    public int getDepth() {
+        int depth = 0;
+        for (int i = 0; i < elements.length; i++) {
+            if (elements[i].equals(PARENT_ELEMENT)) {
+                depth--;
+            } else if (!elements[i].equals(CURRENT_ELEMENT)) {
+                depth++;
+            }
+        }
+        return depth;
+    }
+
+    /**
+     * Determines if <i>this</i> path is an ancestor of the specified path,
+     * based on their (absolute or relative) hierarchy level as returned by
+     * <code>{@link #getDepth()}</code>.
      *
      * @return <code>true</code> if <code>other</code> is a descendant;
      *         otherwise <code>false</code>
-     * @throws MalformedPathException if either the specified path or this path
-     *                                is a relative path.
+     * @throws MalformedPathException if not both paths are either absolute or
+     *                                relative.
+     * @see #getDepth()
      */
     public boolean isAncestorOf(Path other) throws MalformedPathException {
-        if (equals(other)) {
-            return false;
-        }
         if (other == null) {
             throw new IllegalArgumentException("null argument");
         }
-        // make sure we're comparing canonical paths
-        Path p0 = getCanonicalPath();
-        Path p1 = other.getCanonicalPath();
-        if (p0.elements.length >= p1.elements.length) {
+        // make sure both paths are either absolute or relative
+        if (isAbsolute() != other.isAbsolute()) {
+            throw new MalformedPathException("cannot compare a relative path with an absolute
path");
+        }
+        // make sure we're comparing normalized paths
+        Path p0 = getNormalizedPath();
+        Path p1 = other.getNormalizedPath();
+        if (p0.equals(p1)) {
+            return false;
+        }
+        // calculate depth of paths (might be negative)
+        if (p0.getDepth() >= p1.getDepth()) {
             return false;
         }
         for (int i = 0; i < p0.elements.length; i++) {
@@ -369,12 +505,15 @@
     }
 
     /**
-     * Determines if <i>this</i> path is a descendant of the specified path.
+     * Determines if <i>this</i> path is a descendant of the specified path,
+     * based on their (absolute or relative) hierarchy level as returned by
+     * <code>{@link #getDepth()}</code>.
      *
      * @return <code>true</code> if <code>other</code> is an ancestor;
      *         otherwise <code>false</code>
-     * @throws MalformedPathException if either the specified path or this path
-     *                                is a relative path.
+     * @throws MalformedPathException if not both paths are either absolute or
+     *                                relative.
+     * @see #getDepth()
      */
     public boolean isDescendantOf(Path other) throws MalformedPathException {
         if (equals(other)) {

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/EffectiveNodeType.java
Tue Nov 30 10:12:21 2004
@@ -425,16 +425,30 @@
             throw new ConstraintViolationException("the property is not multi-valued");
         }
 
-        // check value constraints
         ValueConstraint[] constraints = pd.getValueConstraints();
-        if (constraints != null && constraints.length != 0) {
-            for (int i = 0; i < constraints.length; i++) {
-                if (values == null || values.length == 0) {
-                    constraints[i].check(null);
-                } else {
-                    for (int j = 0; j < values.length; j++) {
-                        constraints[i].check(values[j]);
+        if (constraints == null || constraints.length == 0) {
+            // no constraints to check
+            return;
+        }
+        if (values != null || values.length > 0) {
+            // check value constraints on every value
+            for (int i = 0; i < values.length; i++) {
+                // constraints are OR-ed together
+                boolean satisfied = false;
+                ConstraintViolationException cve = null;
+                for (int j = 0; j < constraints.length; j++) {
+                    try {
+                        constraints[j].check(values[i]);
+                        satisfied = true;
+                        break;
+                    } catch (ConstraintViolationException e) {
+                        cve = e;
+                        continue;
                     }
+                }
+                if (!satisfied) {
+                    // re-throw last exception we encountered
+                    throw cve;
                 }
             }
         }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
Tue Nov 30 10:12:21 2004
@@ -313,7 +313,7 @@
                     if (!content.isEmpty()) {
                         String constraint = constraintElem.getTextTrim();
                         try {
-                            list1.add(ValueConstraint.create(type, constraint));
+                            list1.add(ValueConstraint.create(type, constraint, nsResolver));
                         } catch (InvalidConstraintException e) {
                             String msg = "invalid serialized node type definition [" + sntName
+ "]: invalid constraint: " + constraint;
                             log.error(msg, e);

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/NodeTypeRegistry.java
Tue Nov 30 10:12:21 2004
@@ -1055,6 +1055,11 @@
         }
 
         /**
+         * todo build set of node types that have dependencies on the specified
+         * node type
+         */
+
+        /**
          * todo check if this node type (or any node type that has dependencies
          * on this node type) is currently referenced by nodes in the repository.
          *

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/PropertyDefImpl.java
Tue Nov 30 10:12:21 2004
@@ -89,7 +89,7 @@
         }
         String[] vca = new String[constraints.length];
         for (int i = 0; i < constraints.length; i++) {
-            vca[i] = constraints[i].getDefinition();
+            vca[i] = constraints[i].getDefinition(nsResolver);
         }
         return vca;
     }

Modified: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java
Url: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java?view=diff&rev=109221&p1=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java&r1=109220&p2=incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java&r2=109221
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java
(original)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/nodetype/ValueConstraint.java
Tue Nov 30 10:12:21 2004
@@ -15,13 +15,13 @@
  */
 package org.apache.jackrabbit.core.nodetype;
 
-import org.apache.jackrabbit.core.BLOBFileValue;
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.NamespaceResolver;
-import org.apache.jackrabbit.core.QName;
+import org.apache.jackrabbit.core.*;
 import org.apache.log4j.Logger;
 
-import javax.jcr.*;
+import javax.jcr.DateValue;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.ValueFormatException;
 import javax.jcr.nodetype.ConstraintViolationException;
 import java.util.Calendar;
 import java.util.regex.Matcher;
@@ -42,11 +42,33 @@
         this.definition = definition;
     }
 
+    /**
+     * Returns the original (raw) definition of this constraint.
+     *
+     * @return the original (raw) definition of this constraint.
+     */
     public String getDefinition() {
         return definition;
     }
 
-    public static ValueConstraint create(int type, String definition) throws InvalidConstraintException
{
+    /**
+     * For constraints that are not namespace prefix mapping sensitive this
+     * method returns the same result as <code>{@link #getDefinition()}</code>.
+     * <p/>
+     * Those that are namespace prefix mapping sensitive (e.g.
+     * <code>NameConstraint</code>, <code>PathConstraint</code> and
+     * <code>ReferenceConstraint</code>) use the given <code>nsResolver</code>
+     * to reflect the current mapping in the returned value.
+     *
+     * @return the definition of this constraint.
+     */
+    public String getDefinition(NamespaceResolver nsResolver) {
+        return definition;
+    }
+
+    public static ValueConstraint create(int type, String definition,
+                                         NamespaceResolver nsResolver)
+            throws InvalidConstraintException {
         if (definition == null) {
             throw new IllegalArgumentException("illegal definition (null)");
         }
@@ -68,19 +90,13 @@
                 return new NumericConstraint(definition);
 
             case PropertyType.NAME:
-                // @todo implement NAME value constraint
-                //return new NameConstraint(definition, nsResolver);
-                return new StringConstraint(".*");
+                return new NameConstraint(definition, nsResolver);
 
             case PropertyType.PATH:
-                // @todo implement PATH value constraint
-                //return new PathConstraint(definition, nsResolver);
-                return new StringConstraint(".*");
+                return new PathConstraint(definition, nsResolver);
 
             case PropertyType.REFERENCE:
-                // @todo implement REFERENCE value constraint
-                //return new ReferenceConstraint(definition, ntReg, nsResolver);
-                return new ReferenceConstraint(definition, null, null);
+                return new ReferenceConstraint(definition, nsResolver);
 
             default:
                 throw new IllegalArgumentException("unknown/unsupported target type for constraint:
" + PropertyType.nameFromValue(type));
@@ -433,28 +449,39 @@
  * <code>PathConstraint</code> ...
  */
 class PathConstraint extends ValueConstraint {
-    final Pattern pattern;
+    final Path path;
+    final boolean deep;
 
-    PathConstraint(String definition) throws InvalidConstraintException {
+    PathConstraint(String definition, NamespaceResolver nsResolver)
+            throws InvalidConstraintException {
         super(definition);
 
-        // constraint format: regexp
+        // constraint format: absolute or relative path with optional trailing wildcard
+        deep = definition.endsWith("*");
+        if (deep) {
+            // trim trailing wildcard before building path
+            definition = definition.substring(0, definition.length() - 1);
+        }
         try {
-            pattern = Pattern.compile(definition);
-        } catch (PatternSyntaxException pse) {
-            String msg = "'" + definition + "' is not valid regular expression syntax";
-            log.error(msg, pse);
-            throw new InvalidConstraintException(msg, pse);
+            path = Path.create(definition, nsResolver, false);
+        } catch (MalformedPathException mpe) {
+            String msg = "invalid path expression specified as value constraint: " + definition;
+            log.error(msg, mpe);
+            throw new InvalidConstraintException(msg, mpe);
         }
     }
 
-    void check(String text) throws ConstraintViolationException {
-        if (text == null) {
-            throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
-        }
-        Matcher matcher = pattern.matcher(text);
-        if (!matcher.matches()) {
-            throw new ConstraintViolationException("'" + text + "' does not satisfy the constraint
'" + definition + "'");
+    public String getDefinition(NamespaceResolver nsResolver) {
+        try {
+            String p = path.toJCRPath(nsResolver);
+            if (deep) {
+                return (path.denotesRoot() ? p + "*" : p + "/*");
+            } else {
+                return p;
+            }
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here, return raw definition as fallback
+            return definition;
         }
     }
 
@@ -462,21 +489,34 @@
         if (value == null) {
             throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
         }
-        // @todo check PATH value constraint (need a NamespaceResolver)
-        /*
         switch (value.getType()) {
             case PropertyType.PATH:
-            Path p = (Path) value.internalValue();
-            check(p.toJCRPath(nsResolver));
-            return;
+                Path p = (Path) value.internalValue();
+                // normalize paths before comparing them
+                Path p0 = path.getNormalizedPath();
+                Path p1 = p.getNormalizedPath();
+                if (deep) {
+                    try {
+                        if (!p0.isAncestorOf(p1)) {
+                            throw new ConstraintViolationException(p + " does not satisfy
the constraint '" + definition + "'");
+                        }
+                    } catch (MalformedPathException mpe) {
+                        // can't compare relative with absolute path
+                        throw new ConstraintViolationException(p + " does not satisfy the
constraint '" + definition + "'");
+                    }
+                } else {
+                    // exact match required
+                    if (!p0.equals(p1)) {
+                        throw new ConstraintViolationException(p + " does not satisfy the
constraint '" + definition + "'");
+                    }
+                }
+                return;
 
             default:
-            String msg = "PATH constraint can not be applied to value of type: " + PropertyType.nameFromValue(value.getType());
-            log.error(msg);
-            throw new RepositoryException(msg);
+                String msg = "PATH constraint can not be applied to value of type: " + PropertyType.nameFromValue(value.getType());
+                log.error(msg);
+                throw new RepositoryException(msg);
         }
-        */
-        log.warn("validation of PATH constraint is not yet implemented");
     }
 }
 
@@ -484,28 +524,33 @@
  * <code>NameConstraint</code> ...
  */
 class NameConstraint extends ValueConstraint {
-    final Pattern pattern;
+    final QName name;
 
-    NameConstraint(String definition) throws InvalidConstraintException {
+    NameConstraint(String definition, NamespaceResolver nsResolver)
+            throws InvalidConstraintException {
         super(definition);
 
-        // constraint format: regexp
+        // constraint format: JCR name in prefix form
         try {
-            pattern = Pattern.compile(definition);
-        } catch (PatternSyntaxException pse) {
-            String msg = "'" + definition + "' is not valid regular expression syntax";
-            log.error(msg, pse);
-            throw new InvalidConstraintException(msg, pse);
+            QName.checkFormat(definition);
+            name = QName.fromJCRName(definition, nsResolver);
+        } catch (IllegalNameException ine) {
+            String msg = "invalid name specified as value constraint: " + definition;
+            log.error(msg, ine);
+            throw new InvalidConstraintException(msg, ine);
+        } catch (UnknownPrefixException upe) {
+            String msg = "invalid name specified as value constraint: " + definition;
+            log.error(msg, upe);
+            throw new InvalidConstraintException(msg, upe);
         }
     }
 
-    void check(String text) throws ConstraintViolationException {
-        if (text == null) {
-            throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
-        }
-        Matcher matcher = pattern.matcher(text);
-        if (!matcher.matches()) {
-            throw new ConstraintViolationException("'" + text + "' does not satisfy the constraint
'" + definition + "'");
+    public String getDefinition(NamespaceResolver nsResolver) {
+        try {
+            return name.toJCRName(nsResolver);
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here, return raw definition as fallback
+            return definition;
         }
     }
 
@@ -513,21 +558,19 @@
         if (value == null) {
             throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
         }
-        // @todo check NAME value constraint (need a NamespaceResolver)
-        /*
         switch (value.getType()) {
             case PropertyType.NAME:
-            QName name = (QName) value.internalValue();
-            check(name.toJCRName(nsResolver);
-            return;
+                QName n = (QName) value.internalValue();
+                if (!name.equals(n)) {
+                    throw new ConstraintViolationException(n + " does not satisfy the constraint
'" + definition + "'");
+                }
+                return;
 
             default:
-            String msg = "NAME constraint can not be applied to value of type: " + PropertyType.nameFromValue(value.getType());
-            log.error(msg);
-            throw new RepositoryException(msg);
+                String msg = "NAME constraint can not be applied to value of type: " + PropertyType.nameFromValue(value.getType());
+                log.error(msg);
+                throw new RepositoryException(msg);
         }
-        */
-        log.warn("validation of NAME constraint is not yet implemented");
     }
 }
 
@@ -535,62 +578,57 @@
  * <code>ReferenceConstraint</code> ...
  */
 class ReferenceConstraint extends ValueConstraint {
-    final QName[] ntNames;
+    final QName ntName;
 
-    ReferenceConstraint(String definition, NodeTypeRegistry ntReg, NamespaceResolver nsResolver)
throws InvalidConstraintException {
+    ReferenceConstraint(String definition, NamespaceResolver nsResolver) throws InvalidConstraintException
{
         super(definition);
 
-        // format: comma-separated list of node type names
-        String[] strings = definition.split(",\\s*");
-        ntNames = new QName[strings.length];
-        /*
-        for (int i = 0; i < strings.length; i++) {
-            // every node type specified must be registered
-            String s = strings[i];
-            try {
-            ntNames[i] = QName.fromJCRName(s, nsResolver);
-            } catch (UnknownPrefixException upe) {
-            String msg = "invalid node type specified as value constraint: " + s;
+        // format: node type name
+        try {
+            ntName = QName.fromJCRName(definition, nsResolver);
+        } catch (IllegalNameException ine) {
+            String msg = "invalid node type name specified as value constraint: " + definition;
+            log.error(msg, ine);
+            throw new InvalidConstraintException(msg, ine);
+        } catch (UnknownPrefixException upe) {
+            String msg = "invalid node type name specified as value constraint: " + definition;
             log.error(msg, upe);
             throw new InvalidConstraintException(msg, upe);
-            }
-            try {
-            ntReg.getEffectiveNodeType(ntNames[i]);
-            } catch (Exception e) {
-            String msg = "invalid node type specified as value constraint: " + ntNames[i];
-            log.error(msg, e);
-            throw new InvalidConstraintException(msg, e);
-            }
         }
-        */
     }
 
-    QName[] getNodeTypeNames() {
-        return ntNames;
+    public String getDefinition(NamespaceResolver nsResolver) {
+        try {
+            return ntName.toJCRName(nsResolver);
+        } catch (NoPrefixDeclaredException npde) {
+            // should never get here, return raw definition as fallback
+            return definition;
+        }
     }
 
-    void check(Node target) throws ConstraintViolationException {
-        if (target == null) {
-            throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
-        }
+    QName getNodeTypeName() {
+        return ntName;
     }
 
     void check(InternalValue value) throws ConstraintViolationException, RepositoryException
{
         if (value == null) {
             throw new ConstraintViolationException("null value does not satisfy the constraint
'" + definition + "'");
         }
-        // @todo check REFERENCE value constraint (need a session)
+        // @todo check REFERENCE value constraint (requires a session)
         /*
         switch (value.getType()) {
             case PropertyType.REFERENCE:
-            UUID targetUUID = (UUID) value.internalValue();
-            check(session.getNodeByUUID(targetUUID.toString()));
-            return;
+                UUID targetUUID = (UUID) value.internalValue();
+                NodeImpl targetNode = (NodeImpl) session.getNodeByUUID(targetUUID.toString());
+                if (!targetNode.isNodeType(ntName)) {
+                    throw new ConstraintViolationException("the node with uuid " + targetUUID
+ " does not satisfy the constraint '" + definition + "'");
+                }
+                return;
 
             default:
-            String msg = "REFERENCE constraint can not be applied to value of type: " + PropertyType.nameFromValue(value.getType());
-            log.error(msg);
-            throw new RepositoryException(msg);
+                String msg = "REFERENCE constraint can not be applied to value of type: "
+ PropertyType.nameFromValue(value.getType());
+                log.error(msg);
+                throw new RepositoryException(msg);
         }
         */
         log.warn("validation of REFERENCE constraint is not yet implemented");

Mime
View raw message