You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2015/12/18 15:50:40 UTC

svn commit: r1720802 [1/2] - in /sling/trunk/bundles/extensions: models/validation-impl/src/main/java/org/apache/sling/models/validation/ validation/api/src/main/java/org/apache/sling/validation/ validation/api/src/main/java/org/apache/sling/validation...

Author: kwin
Date: Fri Dec 18 14:50:39 2015
New Revision: 1720802

URL: http://svn.apache.org/viewvc?rev=1720802&view=rev
Log:
SLING-5026 - refactor validator interface to allow to set multiple failure messages

This closes #117

Added:
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java   (with props)
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java   (with props)
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java   (with props)
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java   (with props)
Removed:
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/Validator.java
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationModelCache.java
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationModelProvider.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/Constants.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResultImpl.java
Modified:
    sling/trunk/bundles/extensions/models/validation-impl/src/main/java/org/apache/sling/models/validation/InvalidResourceException.java
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationResult.java
    sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ParameterizedValidator.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelRetrieverImpl.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResourceVisitor.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ParameterizedValidatorImpl.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ResourcePropertyBuilder.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelBuilder.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImpl.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java
    sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationModelRetrieverImplTest.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ValidatorTypeUtilTest.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/AbstractValidatorWithAdditionalType.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/DateValidator.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/ExtendedStringValidator.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/IntegerValidator.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringArrayValidator.java
    sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/examplevalidators/StringValidator.java
    sling/trunk/bundles/extensions/validation/examples/src/main/java/org/apache/sling/validation/examples/models/UserModel.java
    sling/trunk/bundles/extensions/validation/examples/src/main/java/org/apache/sling/validation/examples/servlets/ModifyUserServlet.java
    sling/trunk/bundles/extensions/validation/examples/src/main/resources/SLING-INF/apps/validationdemo/components/user/user.jsp
    sling/trunk/bundles/extensions/validation/test-services/src/main/java/org/apache/sling/validation/testservices/ValidationPostResponse.java

Modified: sling/trunk/bundles/extensions/models/validation-impl/src/main/java/org/apache/sling/models/validation/InvalidResourceException.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/validation-impl/src/main/java/org/apache/sling/models/validation/InvalidResourceException.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/validation-impl/src/main/java/org/apache/sling/models/validation/InvalidResourceException.java (original)
+++ sling/trunk/bundles/extensions/models/validation-impl/src/main/java/org/apache/sling/models/validation/InvalidResourceException.java Fri Dec 18 14:50:39 2015
@@ -16,11 +16,8 @@
  */
 package org.apache.sling.models.validation;
 
-import java.util.List;
-import java.util.Map.Entry;
-
-import org.apache.commons.lang.StringUtils;
 import org.apache.sling.models.factory.InvalidModelException;
+import org.apache.sling.validation.ValidationFailure;
 import org.apache.sling.validation.ValidationResult;
 
 /**
@@ -61,8 +58,8 @@ public class InvalidResourceException ex
     public String getMessage() {
         StringBuilder builder = new StringBuilder("Validation errors for ");
         builder.append("'" + path +"':");
-        for (Entry<String, List<String>> entry : result.getFailureMessages().entrySet()) {
-            builder.append("\n" + entry.getKey() + ":" + StringUtils.join(entry.getValue(), "\n\t"));
+        for (ValidationFailure failure : result.getFailures()) {
+            builder.append("\n" + failure.getLocation() + ":" + failure.getMessage() + "\n\t");
         }
         return builder.toString();
     }

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation;
+
+import javax.annotation.Nonnull;
+
+public interface ValidationFailure {
+
+    /**
+     * @return the failure message
+     */
+    public @Nonnull String getMessage();
+    
+    /**
+     * Returns the relative location of the property/resource/value which triggered this validation failure.
+     * The location 
+     * <ul>
+     * <li>is relative to the resource given in the first parameter in case it was returned by {@link ValidationService#validate(org.apache.sling.api.resource.Resource, org.apache.sling.validation.model.ValidationModel)} or {@link ValidationService#validateResourceRecursively(org.apache.sling.api.resource.Resource, boolean, org.apache.commons.collections.Predicate, boolean)} or</li>
+     * <li>contains just the value name in case it was returned by {@link ValidationService#validate(org.apache.sling.api.resource.ValueMap, org.apache.sling.validation.model.ValidationModel)}</li>
+     * </ul>
+     * @return the location (usually the validated resource's property path).
+     */
+    public @Nonnull String getLocation();
+    
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationFailure.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationResult.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationResult.java (original)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/ValidationResult.java Fri Dec 18 14:50:39 2015
@@ -23,8 +23,10 @@ import java.util.Map;
 
 import javax.annotation.Nonnull;
 
+import org.apache.sling.validation.spi.Validator;
+
 /**
- * A {@code ValidationResult} contains validation information about a validated property / child resource.
+ * A {@code ValidationResult} contains validation information either from a single {@link Validator} or from multiple Validator invocations.
  */
 public interface ValidationResult {
 
@@ -36,11 +38,9 @@ public interface ValidationResult {
     boolean isValid();
 
     /**
-     * In case the validation failed (check the {@link ValidationResult#isValid()} method), this method returns the failure's causes. The
-     * keys of the returned {@link Map} will contain the validated resource's properties (or child resources' properties) names; the
-     * associated values will be the actual failure messages.
+     * In case the validation failed (check the {@link ValidationResult#isValid()} method), this method returns the failure's causes.
      *
-     * @return the validation's failure messages (never {@code null})
+     * @return the validation's failures (never {@code null})
      */
-    @Nonnull Map<String, List<String>> getFailureMessages();
+    @Nonnull List<ValidationFailure> getFailures();
 }

Modified: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ParameterizedValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ParameterizedValidator.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ParameterizedValidator.java (original)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ParameterizedValidator.java Fri Dec 18 14:50:39 2015
@@ -21,7 +21,7 @@ package org.apache.sling.validation.mode
 import javax.annotation.Nonnull;
 
 import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.validation.Validator;
+import org.apache.sling.validation.spi.Validator;
 
 /**
  * Defines a validator instance with information about the type and the parameterization of the validator.

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.model.spi;
+
+/**
+ * Validation models are cached until explicitly invalidated through this OSGi service.
+ */
+public interface ValidationModelCache {
+    public void invalidate();
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.model.spi;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.validation.model.ValidationModel;
+import org.apache.sling.validation.spi.Validator;
+
+/**
+ * All providers of {@link ValidationModel}s must implement this interface. In addition if the model might become
+ * invalid after some time it is also the obligatation of the provider implementation to invalidate the cache via the
+ * {@link ValidationModelCache} OSGi service.
+ */
+public interface ValidationModelProvider {
+
+    /**
+     * Retrieves the models responsible for validating the given resourceType.
+     * 
+     * @param relativeResourceType
+     * @param validatorsMap
+     *            all known validators in a map (key=name of validator). Only one of those should be used in the
+     *            returned validation models.
+     * @param resourceResolver
+     *            the resource resolver which should be used by the provider (if one is necessary).
+     * @return a Collection of {@link ValidationModel}s. Never {@code null}, but might be empty collection in case no
+     *         model for the given resource type could be found.
+     * @throws IllegalStateException
+     *             in case a validation model was found but it is invalid
+     */
+    public @Nonnull Collection<ValidationModel> getModel(@Nonnull String relativeResourceType,
+            @Nonnull Map<String, Validator<?>> validatorsMap, @Nonnull ResourceResolver resourceResolver)
+            throws IllegalStateException;
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+@Version("1.0.0")
+package org.apache.sling.validation.model.spi;
+
+import aQute.bnd.annotation.Version;
\ No newline at end of file

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/package-info.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.spi;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.validation.ValidationFailure;
+
+public class DefaultValidationFailure implements ValidationFailure {
+
+    private final @Nonnull String message;
+    private final @Nonnull String location;
+
+    public DefaultValidationFailure(@Nonnull String message, @Nonnull String location) {
+        this.message = message;
+        this.location = location;
+    }
+
+    @Override
+    public @Nonnull String getMessage() {
+        return message;
+    }
+
+    @Override
+    public @Nonnull String getLocation() {
+        return location;
+    }
+
+    @Override
+    public String toString() {
+        return "DefaultValidationFailure [message=" + message + ", location=" + location + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((location == null) ? 0 : location.hashCode());
+        result = prime * result + ((message == null) ? 0 : message.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (!(obj instanceof DefaultValidationFailure))
+            return false;
+        DefaultValidationFailure other = (DefaultValidationFailure) obj;
+        if (location == null) {
+            if (other.location != null)
+                return false;
+        } else if (!location.equals(other.location))
+            return false;
+        if (message == null) {
+            if (other.message != null)
+                return false;
+        } else if (!message.equals(other.message))
+            return false;
+        return true;
+    }
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationFailure.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.spi;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.validation.ValidationFailure;
+import org.apache.sling.validation.ValidationResult;
+
+public class DefaultValidationResult implements ValidationResult {
+
+    private final boolean isValid;
+    private final @Nonnull List<ValidationFailure> failures;
+
+    private DefaultValidationResult(boolean isValid) {
+        this.isValid = isValid;
+        this.failures = Collections.emptyList();
+    }
+
+    /** 
+     * Constructs a result with one failure message and an according location
+     * @param message the failure message
+     * @param location the location
+     */
+    public DefaultValidationResult(@Nonnull String message, String location) {
+        this.isValid = false;
+        this.failures = Collections.<ValidationFailure>singletonList(new DefaultValidationFailure(message, location));
+    }
+
+    public DefaultValidationResult(ValidationFailure... failures) {
+        this.isValid = false;
+        this.failures = Arrays.asList(failures);
+    }
+
+    @Override
+    public boolean isValid() {
+        return isValid;
+    }
+
+    @Override
+    @Nonnull
+    public List<ValidationFailure> getFailures() {
+        return failures;
+    }
+
+    public static final @Nonnull DefaultValidationResult VALID = new DefaultValidationResult(true);
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/DefaultValidationResult.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.spi;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.ValidationService;
+
+/**
+ * Used as parameter for each call of {@link Validator#validate(Object, ValidationContext, ValueMap)}
+ * Exposes additional information about the context in which the validation was called.
+ */
+public interface ValidationContext {
+
+    /**
+     * @return the relative location of the property which should be checked by the validator. Refers to the 'data' parameter of {@link Validator#validate(Object, ValidationContext, ValueMap)}
+     */
+    @Nonnull String getLocation();
+
+    /**
+     * all properties of the validated resource/valuemap (only used for validations considering multiple properties), never {@code null}.
+     * @return
+     */
+    @Nonnull ValueMap getValueMap();
+
+    /**
+     * @return the resource on which the validation was triggered. {@code null} in case the validation was triggered on a {@link ValueMap} (via {@link ValidationService#validate(ValueMap, org.apache.sling.validation.model.ValidationModel)}).
+     */
+    @CheckForNull Resource getResource();
+    
+    
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/ValidationContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java (added)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.spi;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.ValidationResult;
+import org.apache.sling.validation.exceptions.SlingValidationException;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * A {@code Validator} is responsible for validating a single piece of information according to an internal constraint.
+ */
+@ConsumerType
+public interface Validator <T> {
+
+    /**
+     * Validates the {@code data} and/or the {@code valueMap} according to the internal constraints of this validator.
+     * 
+     * The validator can enforce the type of the given data just by setting the appropriate parameter type {@code T} which can be any non-primitive class. 
+     * Depending on whether this type is an array or not the {@code validate} method is called differently:
+     * <table> 
+     *  <tr>
+     *    <th>T is array type</th>
+     *    <th>Valuemap contains array value</th>
+     *    <th>{@code validate} is called...</th>
+     *  </tr>
+     *  <tr>
+     *    <td>yes</td>
+     *    <td>yes</td>
+     *    <td>once per property with {@code data} containing the full array</td>
+     *  </tr>
+     *  <tr>
+     *    <td>yes</td>
+     *    <td>no</td>
+     *    <td>once per property with {@code data} containing a single element array</td>
+     *  </tr>
+     *  <tr>
+     *    <td>no</td>
+     *    <td>yes</td>
+     *    <td>once per element in the property array with {@code data} containing one array element</td>
+     *  </tr>
+     *  <tr>
+     *    <td>no</td>
+     *    <td>no</td>
+     *    <td>once per property with {@code data} containing the value of the property</td>
+     *  </tr>
+     * </table>
+     * If the data cannot be converted into the type {@code T} the validator is not called, but validation fails.
+     *
+     * @param data the data to validate (primary property), never {@code null}.
+     * @param context the validation context contains additional information about the data to be validated, never {@code null}.
+     * @param arguments the parameterization of the validator. Never {@code null} but might be the empty map.
+     * @return the validation result (encapsulates the validation status as well as messages).
+     * @throws org.apache.sling.validation.exceptions.SlingValidationException if some expected arguments are missing from the arguments map
+     */
+    @Nonnull ValidationResult validate(@Nonnull T data, @Nonnull ValidationContext context, @Nonnull ValueMap arguments) throws SlingValidationException;
+}

Propchange: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/spi/Validator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java (added)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.impl;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.apache.sling.validation.ValidationFailure;
+import org.apache.sling.validation.ValidationResult;
+import org.apache.sling.validation.spi.DefaultValidationResult;
+
+/**
+ * Aggregates multiple {@link ValidationResult}s.
+ */
+public class CompositeValidationResult implements ValidationResult {
+
+    private final @Nonnull List<ValidationResult> results;
+
+    public CompositeValidationResult() {
+        results = new ArrayList<ValidationResult>();
+    }
+
+    public void addValidationResult(ValidationResult result) {
+        results.add(result);
+    }
+
+    public void addFailure(@Nonnull String message, String location) {
+        results.add(new DefaultValidationResult(message, location));
+    }
+
+    @Override
+    public boolean isValid() {
+        // this is only valid iff all aggregated results are valid
+        for (ValidationResult result : results) {
+            if (!result.isValid()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    @Nonnull
+    public List<ValidationFailure> getFailures() {
+        List<ValidationFailure> failures = new LinkedList<ValidationFailure>();
+        for (ValidationResult result : results) {
+            for (ValidationFailure failure : result.getFailures()) {
+                failures.add(failure);
+            }
+        }
+        return failures;
+    }
+}

Propchange: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/CompositeValidationResult.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java?rev=1720802&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java (added)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java Fri Dec 18 14:50:39 2015
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.validation.impl;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.validation.spi.ValidationContext;
+
+public class ValidationContextImpl implements ValidationContext {
+
+    private final @Nonnull String location;
+    private final @Nonnull ValueMap valueMap;
+    private final Resource resource;
+
+    public ValidationContextImpl(@Nonnull String location, @Nonnull ValueMap valueMap, Resource resource) {
+        super();
+        this.location = location;
+        this.valueMap = valueMap;
+        this.resource = resource;
+    }
+
+    @Override
+    @Nonnull
+    public String getLocation() {
+        return location;
+    }
+
+    @Override
+    @Nonnull
+    public ValueMap getValueMap() {
+        return valueMap;
+    }
+
+    @Override
+    @CheckForNull
+    public Resource getResource() {
+        return resource;
+    }
+
+}

Propchange: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationContextImpl.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java Fri Dec 18 14:50:39 2015
@@ -21,7 +21,7 @@ package org.apache.sling.validation.impl
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.validation.spi.ValidationModelCache;
+import org.apache.sling.validation.model.spi.ValidationModelCache;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
 

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelRetrieverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelRetrieverImpl.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelRetrieverImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelRetrieverImpl.java Fri Dec 18 14:50:39 2015
@@ -36,11 +36,11 @@ import org.apache.sling.api.resource.Log
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.commons.osgi.RankedServices;
-import org.apache.sling.validation.Validator;
 import org.apache.sling.validation.impl.model.MergedValidationModel;
 import org.apache.sling.validation.impl.util.Trie;
 import org.apache.sling.validation.model.ValidationModel;
-import org.apache.sling.validation.spi.ValidationModelProvider;
+import org.apache.sling.validation.model.spi.ValidationModelProvider;
+import org.apache.sling.validation.spi.Validator;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventConstants;
 import org.osgi.service.event.EventHandler;
@@ -73,7 +73,7 @@ public class ValidationModelRetrieverImp
      * List of all known validators (key=classname of validator)
      */
     @Reference(name = "validator", referenceInterface = Validator.class, policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
-    Map<String, Validator<?>> validators = new ConcurrentHashMap<String, Validator<?>>();
+    @Nonnull Map<String, Validator<?>> validators = new ConcurrentHashMap<String, Validator<?>>();
 
     @Reference
     private ResourceResolverFactory resourceResolverFactory;

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResourceVisitor.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResourceVisitor.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResourceVisitor.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationResourceVisitor.java Fri Dec 18 14:50:39 2015
@@ -18,9 +18,6 @@
  */
 package org.apache.sling.validation.impl;
 
-import java.util.List;
-import java.util.Map.Entry;
-
 import javax.annotation.Nonnull;
 
 import org.apache.commons.collections.Predicate;
@@ -36,7 +33,7 @@ public class ValidationResourceVisitor e
     private final String rootResourcePath;
     private final boolean enforceValidation;
     private final boolean considerResourceSuperTypeModels;
-    private final @Nonnull ValidationResultImpl result;
+    private final @Nonnull CompositeValidationResult result;
     private final Predicate filter;
 
     public ValidationResourceVisitor(ValidationServiceImpl validationService, String rootResourcePath, boolean enforceValidation, Predicate filter,  boolean considerResourceSuperTypeModels) {
@@ -46,7 +43,7 @@ public class ValidationResourceVisitor e
         this.enforceValidation = enforceValidation;
         this.considerResourceSuperTypeModels = considerResourceSuperTypeModels;
         this.filter = filter;
-        this.result = new ValidationResultImpl();
+        this.result = new CompositeValidationResult();
     }
 
     @Override
@@ -60,6 +57,7 @@ public class ValidationResourceVisitor e
                 }
                 return;
             }
+            // calculate the property name correctly from the root
             // the relative path must end with a slash and not start with a slash
             final String relativePath;
             if (resource.getPath().startsWith(rootResourcePath)) {
@@ -68,12 +66,7 @@ public class ValidationResourceVisitor e
                 relativePath = "";
             }
             ValidationResult localResult = validationService.validate(resource, model, relativePath);
-            for (Entry<String, List<String>> entry : localResult.getFailureMessages().entrySet()) {
-                for (String message : entry.getValue()) {
-                    // calculate the property name correctly from the root
-                    result.addFailureMessage(entry.getKey(), message);
-                }
-            }
+            result.addValidationResult(localResult);
         }
     }
     
@@ -91,7 +84,7 @@ public class ValidationResourceVisitor e
         return true;
     }
 
-    public @Nonnull ValidationResultImpl getResult() {
+    public @Nonnull CompositeValidationResult getResult() {
         return result;
     }
 

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationServiceImpl.java Fri Dec 18 14:50:39 2015
@@ -40,12 +40,13 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.validation.ValidationResult;
 import org.apache.sling.validation.ValidationService;
-import org.apache.sling.validation.Validator;
 import org.apache.sling.validation.exceptions.SlingValidationException;
 import org.apache.sling.validation.model.ChildResource;
 import org.apache.sling.validation.model.ParameterizedValidator;
 import org.apache.sling.validation.model.ResourceProperty;
 import org.apache.sling.validation.model.ValidationModel;
+import org.apache.sling.validation.spi.ValidationContext;
+import org.apache.sling.validation.spi.Validator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -134,7 +135,7 @@ public class ValidationServiceImpl imple
         if (resource == null || model == null || relativePath == null) {
             throw new IllegalArgumentException("ValidationService.validate - cannot accept null parameters");
         }
-        ValidationResultImpl result = new ValidationResultImpl();
+        CompositeValidationResult result = new CompositeValidationResult();
 
         // validate direct properties of the resource
         validateValueMap(resource.adaptTo(ValueMap.class), resource, relativePath, model.getResourceProperties(), result );
@@ -153,7 +154,7 @@ public class ValidationServiceImpl imple
      * @param result
      * @param childResources
      */
-    private void validateChildren(Resource resource, String relativePath, Collection<ChildResource> childResources, ValidationResultImpl result) {
+    private void validateChildren(Resource resource, String relativePath, Collection<ChildResource> childResources, CompositeValidationResult result) {
         // validate children resources, if any
         for (ChildResource childResource : childResources) {
             // if a pattern is set we validate all children matching that pattern
@@ -168,20 +169,20 @@ public class ValidationServiceImpl imple
                     }
                 }
                 if (!foundMatch && childResource.isRequired()) {
-                    result.addFailureMessage(relativePath + pattern.pattern(), "Missing required child resource.");
+                    result.addFailure("Missing required child resource.", relativePath + pattern.pattern());
                 }
             } else {
                 Resource expectedResource = resource.getChild(childResource.getName());
                 if (expectedResource != null) {
                     validateChildResource(expectedResource, relativePath, childResource, result);
                 } else if (childResource.isRequired()) {
-                    result.addFailureMessage(relativePath + childResource.getName(), "Missing required child resource.");
+                    result.addFailure("Missing required child resource.", relativePath + childResource.getName());
                 }
             } 
         }
     }
 
-    private void validateChildResource(Resource resource, String relativePath, ChildResource childResource, ValidationResultImpl result) {
+    private void validateChildResource(Resource resource, String relativePath, ChildResource childResource, CompositeValidationResult result) {
         validateValueMap(resource.adaptTo(ValueMap.class), resource, relativePath + resource.getName() + "/", childResource.getProperties(), result);
         validateChildren(resource, relativePath + resource.getName() + "/", childResource.getChildren(), result);
     }
@@ -191,7 +192,7 @@ public class ValidationServiceImpl imple
         if (valueMap == null || model == null) {
             throw new IllegalArgumentException("ValidationResult.validate - cannot accept null parameters");
         }
-        ValidationResultImpl result = new ValidationResultImpl();
+        CompositeValidationResult result = new CompositeValidationResult();
         validateValueMap(valueMap, null, "", model.getResourceProperties(), result);
         return result;
     }    
@@ -205,7 +206,7 @@ public class ValidationServiceImpl imple
     }
 
     private void validateValueMap(ValueMap valueMap, Resource resource, String relativePath, Collection<ResourceProperty> resourceProperties,
-            ValidationResultImpl result) {
+            CompositeValidationResult result) {
         if (valueMap == null) {
             throw new IllegalArgumentException("ValueMap may not be null");
         }
@@ -220,7 +221,7 @@ public class ValidationServiceImpl imple
                     }
                 }
                 if (!foundMatch && resourceProperty.isRequired()) {
-                    result.addFailureMessage(relativePath + resourceProperty.getNamePattern(), "Missing required property.");
+                    result.addFailure("Missing required property.", relativePath + resourceProperty.getNamePattern());
                 }
             } else {
                 validatePropertyValue(resourceProperty.getName(), valueMap, resource, relativePath, resourceProperty, result);
@@ -228,18 +229,18 @@ public class ValidationServiceImpl imple
         }
     }
 
-    private void validatePropertyValue(String property, ValueMap valueMap, Resource resource, String relativePath, ResourceProperty resourceProperty, ValidationResultImpl result) {
+    private void validatePropertyValue(String property, ValueMap valueMap, Resource resource, String relativePath, ResourceProperty resourceProperty, CompositeValidationResult result) {
         Object fieldValues = valueMap.get(property);
         if (fieldValues == null) {
             if (resourceProperty.isRequired()) {
-                result.addFailureMessage(relativePath + property, "Missing required property.");
+                result.addFailure("Missing required property.", relativePath + property);
             }
             return;
         }
         List<ParameterizedValidator> validators = resourceProperty.getValidators();
         if (resourceProperty.isMultiple()) {
             if (!fieldValues.getClass().isArray()) {
-                result.addFailureMessage(relativePath + property, "Expected multiple-valued property.");
+                result.addFailure("Expected multiple-valued property.", relativePath + property);
                 return;
             }
         }
@@ -260,7 +261,7 @@ public class ValidationServiceImpl imple
             // see https://issues.apache.org/jira/browse/SLING-4178 for why the second check is necessary
             if (typedValue == null || (typedValue.length > 0 && typedValue[0] == null)) {
                 // here the missing required property case was already treated in validateValueMap
-                result.addFailureMessage(property, "Property was expected to be of type '" + validator.getType() + "' but cannot be converted to that type." );
+                result.addFailure("Property was expected to be of type '" + validator.getType() + "' but cannot be converted to that type.", property);
                 return;
             }
             
@@ -284,17 +285,12 @@ public class ValidationServiceImpl imple
     }
     
     @SuppressWarnings("rawtypes")
-    private void validateValue(ValidationResultImpl result, @Nonnull Object value, String property, String relativePath, @Nonnull ValueMap valueMap, Resource resource, ParameterizedValidator validator) {
+    private void validateValue(CompositeValidationResult result, @Nonnull Object value, String property, String relativePath, @Nonnull ValueMap valueMap, Resource resource, ParameterizedValidator validator) {
         try {
             @SuppressWarnings("unchecked")
-            String validatorMessage = ((Validator)validator.getValidator()).validate(value, valueMap, resource, validator.getParameters());
-            if (validatorMessage != null) {
-                if (validatorMessage.isEmpty()) {
-                    validatorMessage = "Property does not contain a valid value for the " + validator
-                            .getClass().getName() + " validator";
-                } 
-                result.addFailureMessage(relativePath + property, validatorMessage);
-            }
+            ValidationContext validationContext = new ValidationContextImpl(relativePath + property, valueMap, resource);
+            ValidationResult validatorResult = ((Validator)validator.getValidator()).validate(value, validationContext, validator.getParameters());
+            result.addValidationResult(validatorResult);
         } catch (SlingValidationException e) {
             // wrap in another SlingValidationException to include information about the property
             throw new SlingValidationException("Could not call validator " + validator

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ParameterizedValidatorImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ParameterizedValidatorImpl.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ParameterizedValidatorImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ParameterizedValidatorImpl.java Fri Dec 18 14:50:39 2015
@@ -24,9 +24,9 @@ import javax.annotation.Nonnull;
 
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
-import org.apache.sling.validation.Validator;
 import org.apache.sling.validation.impl.util.ValidatorTypeUtil;
 import org.apache.sling.validation.model.ParameterizedValidator;
+import org.apache.sling.validation.spi.Validator;
 
 public class ParameterizedValidatorImpl implements ParameterizedValidator {
     private final @Nonnull Validator<?> validator;

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ResourcePropertyBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ResourcePropertyBuilder.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ResourcePropertyBuilder.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ResourcePropertyBuilder.java Fri Dec 18 14:50:39 2015
@@ -25,9 +25,9 @@ import java.util.Map;
 
 import javax.annotation.Nonnull;
 
-import org.apache.sling.validation.Validator;
 import org.apache.sling.validation.model.ParameterizedValidator;
 import org.apache.sling.validation.model.ResourceProperty;
+import org.apache.sling.validation.spi.Validator;
 
 public class ResourcePropertyBuilder {
 

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelBuilder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelBuilder.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelBuilder.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelBuilder.java Fri Dec 18 14:50:39 2015
@@ -34,8 +34,8 @@ import org.apache.sling.validation.model
  */
 public class ValidationModelBuilder {
 
-    private final List<ResourceProperty> resourceProperties;
-    private final List<ChildResource> children;
+    private final @Nonnull List<ResourceProperty> resourceProperties;
+    private final @Nonnull List<ChildResource> children;
     private final Collection<String> applicablePaths;
     
     public ValidationModelBuilder() {

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImpl.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImpl.java Fri Dec 18 14:50:39 2015
@@ -43,8 +43,6 @@ import org.apache.sling.api.resource.Val
 import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.commons.threads.ThreadPool;
 import org.apache.sling.commons.threads.ThreadPoolManager;
-import org.apache.sling.validation.Validator;
-import org.apache.sling.validation.impl.Constants;
 import org.apache.sling.validation.impl.model.ChildResourceImpl;
 import org.apache.sling.validation.impl.model.ParameterizedValidatorImpl;
 import org.apache.sling.validation.impl.model.ResourcePropertyImpl;
@@ -54,8 +52,9 @@ import org.apache.sling.validation.model
 import org.apache.sling.validation.model.ParameterizedValidator;
 import org.apache.sling.validation.model.ResourceProperty;
 import org.apache.sling.validation.model.ValidationModel;
-import org.apache.sling.validation.spi.ValidationModelCache;
-import org.apache.sling.validation.spi.ValidationModelProvider;
+import org.apache.sling.validation.model.spi.ValidationModelCache;
+import org.apache.sling.validation.model.spi.ValidationModelProvider;
+import org.apache.sling.validation.spi.Validator;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.event.Event;
@@ -69,9 +68,22 @@ import org.slf4j.LoggerFactory;
 @Component
 public class ResourceValidationModelProviderImpl implements ValidationModelProvider, EventHandler {
 
-    static final String MODEL_XPATH_QUERY = "/jcr:root%s/*[@sling:resourceType=\""+Constants.VALIDATION_MODEL_RESOURCE_TYPE+"\" and @"+Constants.VALIDATED_RESOURCE_TYPE+"=\"%s\"]";
+    static final String MODEL_XPATH_QUERY = "/jcr:root%s/*[@sling:resourceType=\""+ResourceValidationModelProviderImpl.VALIDATION_MODEL_RESOURCE_TYPE+"\" and @"+ResourceValidationModelProviderImpl.VALIDATED_RESOURCE_TYPE+"=\"%s\"]";
     static final String[] TOPICS = { SlingConstants.TOPIC_RESOURCE_REMOVED, SlingConstants.TOPIC_RESOURCE_CHANGED,
             SlingConstants.TOPIC_RESOURCE_ADDED };
+    
+    public static final String NAME_REGEX = "nameRegex";
+    public static final String CHILDREN = "children";
+    public static final String VALIDATOR_ARGUMENTS = "validatorArguments";
+    public static final String VALIDATORS = "validators";
+    public static final String OPTIONAL = "optional";
+    public static final String PROPERTY_MULTIPLE = "propertyMultiple";
+    public static final String PROPERTY_TYPE = "propertyType";
+    public static final String PROPERTIES = "properties";
+    public static final String VALIDATION_MODEL_RESOURCE_TYPE = "sling/validation/model";
+    public static final String MODELS_HOME = "validation/";
+    public static final String APPLICABLE_PATHS = "applicablePaths";
+    public static final String VALIDATED_RESOURCE_TYPE = "validatedResourceType";
 
     @Reference
     private ResourceResolverFactory rrf = null;
@@ -103,7 +115,7 @@ public class ResourceValidationModelProv
                 if (searchPath.endsWith("/")) {
                     searchPath = searchPath.substring(0, searchPath.length() - 1);
                 }
-                String path = searchPath + "/*" + Constants.MODELS_HOME;
+                String path = searchPath + "/*" + ResourceValidationModelProviderImpl.MODELS_HOME;
                 sb.append("(path=").append(path).append("*)");
             }
             sb.append(")");
@@ -144,31 +156,9 @@ public class ResourceValidationModelProv
     }
 
     /**
-     * Searches for valid validation models in the JCR repository for a certain resource type. All validation models
+     * Searches for validation models bound to a specific resource type in the repository. All validation models
      * will be returned in a {@link Trie} data structure for easy retrieval of the models using their
      * {@code applicable paths} as trie keys.
-     * <p/>
-     * A valid content-tree {@code ValidationModel} has the following structure:
-     * 
-     * <pre>
-     * validationModel
-     *      &#064;validatedResourceType
-     *      &#064;applicablePaths = [path1,path2,...] (optional)
-     *      &#064;sling:resourceType = sling/validation/model
-     *      fields
-     *          field1
-     *              &#064;fieldType
-     *              validators
-     *                  validator1
-     *                      &#064;validatorArguments = [key=value,key=value...] (optional)
-     *                  validatorN
-     *                      #064;validatorArguments = [key=value,key=value...] (optional)
-     *          fieldN
-     *              &#064;fieldType
-     *              validators
-     *                  validator1
-     *                  &#064;validatorArguments = [key=value,key=value...] (optional)
-     * </pre>
      *
      * @param relativeResourceType
      *            {@inheritDoc}
@@ -177,7 +167,6 @@ public class ResourceValidationModelProv
      * @return {@inheritDoc}
      * @throws {@inheritDoc}
      */
-
     @Override
     @Nonnull
     public Collection<ValidationModel> getModel(@Nonnull String relativeResourceType, @Nonnull Map<String, Validator<?>> validatorsMap, @Nonnull ResourceResolver resourceResolver) {
@@ -193,8 +182,8 @@ public class ResourceValidationModelProv
                 String jcrPath = model.getPath();
                 try {
                     ValueMap validationModelProperties = model.adaptTo(ValueMap.class);
-                    String[] applicablePaths = PropertiesUtil.toStringArray(validationModelProperties.get(Constants.APPLICABLE_PATHS, String[].class));
-                    Resource r = model.getChild(Constants.PROPERTIES);
+                    String[] applicablePaths = PropertiesUtil.toStringArray(validationModelProperties.get(ResourceValidationModelProviderImpl.APPLICABLE_PATHS, String[].class));
+                    Resource r = model.getChild(ResourceValidationModelProviderImpl.PROPERTIES);
                     List<ResourceProperty> resourceProperties = buildProperties(validatorsMap,r);
                     List<ChildResource> children = buildChildren(model, model, validatorsMap);
                     if (resourceProperties.isEmpty() && children.isEmpty()) {
@@ -233,10 +222,10 @@ public class ResourceValidationModelProv
             for (Resource property : propertiesResource.getChildren()) {
                 String fieldName = property.getName();
                 ValueMap propertyValueMap = property.adaptTo(ValueMap.class);
-                Boolean propertyMultiple = PropertiesUtil.toBoolean(propertyValueMap.get(Constants.PROPERTY_MULTIPLE), false);
-                Boolean propertyRequired = !PropertiesUtil.toBoolean(propertyValueMap.get(Constants.OPTIONAL), false);
-                String nameRegex = PropertiesUtil.toString(propertyValueMap.get(Constants.NAME_REGEX), null);
-                Resource validators = property.getChild(Constants.VALIDATORS);
+                Boolean propertyMultiple = PropertiesUtil.toBoolean(propertyValueMap.get(ResourceValidationModelProviderImpl.PROPERTY_MULTIPLE), false);
+                Boolean propertyRequired = !PropertiesUtil.toBoolean(propertyValueMap.get(ResourceValidationModelProviderImpl.OPTIONAL), false);
+                String nameRegex = PropertiesUtil.toString(propertyValueMap.get(ResourceValidationModelProviderImpl.NAME_REGEX), null);
+                Resource validators = property.getChild(ResourceValidationModelProviderImpl.VALIDATORS);
                 List<ParameterizedValidator> parameterizedValidators = new ArrayList<ParameterizedValidator>();
                 if (validators != null) {
                     Iterator<Resource> validatorsIterator = validators.listChildren();
@@ -252,7 +241,7 @@ public class ResourceValidationModelProv
                             throw new IllegalArgumentException("Could not find validator with name '" + validatorName + "'");
                         }
                         // get type of validator
-                        String[] validatorArguments = validatorProperties.get(Constants.VALIDATOR_ARGUMENTS, String[].class);
+                        String[] validatorArguments = validatorProperties.get(ResourceValidationModelProviderImpl.VALIDATOR_ARGUMENTS, String[].class);
                         Map<String, Object> validatorArgumentsMap = new HashMap<String, Object>();
                         if (validatorArguments != null) {
                             for (String arg : validatorArguments) {
@@ -279,14 +268,14 @@ public class ResourceValidationModelProv
      *
      * @param modelResource          the resource describing a {@link org.apache.sling.validation.api.ValidationModel}
      * @param rootResource           the model's resource from which to search for children (this resource has to have a {@link
-     *                               Constants#CHILDREN} node directly underneath it)
+     *                               ResourceValidationModelProviderImpl#CHILDREN} node directly underneath it)
      * @param validatorsMap          a map containing {@link Validator}s as values and their class names as values
      * @return a list of all the children resources; the list will be empty if there are no children resources
      */
     private @Nonnull List<ChildResource> buildChildren(@Nonnull Resource modelResource, @Nonnull Resource rootResource,
                                                     @Nonnull Map<String, Validator<?>> validatorsMap) {
         List<ChildResource> children = new ArrayList<ChildResource>();
-        Resource childrenResource = rootResource.getChild(Constants.CHILDREN);
+        Resource childrenResource = rootResource.getChild(ResourceValidationModelProviderImpl.CHILDREN);
         if (childrenResource != null) {
             for (Resource child : childrenResource.getChildren()) {
                 // if pattern is set, always use that
@@ -296,14 +285,14 @@ public class ResourceValidationModelProv
                 }
                 final String name = child.getName();
                 final String nameRegex;
-                if (childrenProperties.containsKey(Constants.NAME_REGEX)) {
-                    nameRegex = childrenProperties.get(Constants.NAME_REGEX, String.class);
+                if (childrenProperties.containsKey(ResourceValidationModelProviderImpl.NAME_REGEX)) {
+                    nameRegex = childrenProperties.get(ResourceValidationModelProviderImpl.NAME_REGEX, String.class);
                 } else {
                     // otherwise fall back to the name
                     nameRegex = null;
                 }
-                boolean isRequired = !PropertiesUtil.toBoolean(childrenProperties.get(Constants.OPTIONAL), false);
-                ChildResource childResource = new ChildResourceImpl(name, nameRegex, isRequired, buildProperties(validatorsMap, child.getChild(Constants.PROPERTIES)), buildChildren(modelResource, child, validatorsMap));
+                boolean isRequired = !PropertiesUtil.toBoolean(childrenProperties.get(ResourceValidationModelProviderImpl.OPTIONAL), false);
+                ChildResource childResource = new ChildResourceImpl(name, nameRegex, isRequired, buildProperties(validatorsMap, child.getChild(ResourceValidationModelProviderImpl.PROPERTIES)), buildChildren(modelResource, child, validatorsMap));
                 children.add(childResource);
             }
         }

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/util/ValidatorTypeUtil.java Fri Dec 18 14:50:39 2015
@@ -27,7 +27,7 @@ import java.util.Map.Entry;
 import javax.annotation.Nonnull;
 
 import org.apache.commons.lang3.reflect.TypeUtils;
-import org.apache.sling.validation.Validator;
+import org.apache.sling.validation.spi.Validator;
 
 public class ValidatorTypeUtil {
     

Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/validators/RegexValidator.java Fri Dec 18 14:50:39 2015
@@ -25,10 +25,12 @@ import javax.annotation.Nonnull;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.validation.Validator;
+import org.apache.sling.validation.ValidationResult;
 import org.apache.sling.validation.exceptions.SlingValidationException;
+import org.apache.sling.validation.spi.DefaultValidationResult;
+import org.apache.sling.validation.spi.ValidationContext;
+import org.apache.sling.validation.spi.Validator;
 
 /**
  * Performs regular expressions validation on the supplied data with the help of the {@link Pattern} class. This {@code Validator} expects a
@@ -41,7 +43,7 @@ public class RegexValidator implements V
     public static final String REGEX_PARAM = "regex";
 
     @Override
-    public String validate(@Nonnull String data, @Nonnull ValueMap valueMap, Resource resource, @Nonnull ValueMap arguments)
+    public @Nonnull ValidationResult validate(@Nonnull String data, @Nonnull ValidationContext context, @Nonnull ValueMap arguments)
             throws SlingValidationException {
         String regex = arguments.get(REGEX_PARAM, "");
         if (StringUtils.isEmpty(regex)) {
@@ -49,9 +51,9 @@ public class RegexValidator implements V
         }
         Pattern pattern = Pattern.compile(regex);
         if (pattern.matcher((String)data).matches()) {
-            return null;
+            return DefaultValidationResult.VALID;
         }
-        return "Property does not match the pattern " + regex;
+        return new DefaultValidationResult("Property does not match the pattern '" + regex + "'", context.getLocation());
     }
 
 }

Modified: sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationModelRetrieverImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationModelRetrieverImplTest.java?rev=1720802&r1=1720801&r2=1720802&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationModelRetrieverImplTest.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationModelRetrieverImplTest.java Fri Dec 18 14:50:39 2015
@@ -31,13 +31,13 @@ import javax.annotation.Nonnull;
 import org.apache.commons.collections.MultiHashMap;
 import org.apache.commons.collections.MultiMap;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.validation.Validator;
 import org.apache.sling.validation.impl.model.ResourcePropertyBuilder;
 import org.apache.sling.validation.impl.model.ValidationModelBuilder;
 import org.apache.sling.validation.impl.util.examplevalidators.DateValidator;
 import org.apache.sling.validation.model.ResourceProperty;
 import org.apache.sling.validation.model.ValidationModel;
-import org.apache.sling.validation.spi.ValidationModelProvider;
+import org.apache.sling.validation.model.spi.ValidationModelProvider;
+import org.apache.sling.validation.spi.Validator;
 import org.hamcrest.Description;
 import org.hamcrest.Matchers;
 import org.hamcrest.TypeSafeMatcher;