Author: kwin Date: Tue Dec 9 14:46:28 2014 New Revision: 1644069 URL: http://svn.apache.org/r1644069 Log: SLING-4161 support Sling Validation by a new field on the Model annotation
The dependency to Sling Validation is optional (i.e. Sling Models still work even if Sling Validation is not deployed) Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/ValidationStrategy.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidResourceException.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidValidationModelException.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelClassException.java sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidation.java sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidationImpl.java Removed: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java Modified: sling/trunk/bundles/extensions/models/api/pom.xml sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelFactory.java sling/trunk/bundles/extensions/models/impl/pom.xml sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/AdapterFactoryTest.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java Modified: sling/trunk/bundles/extensions/models/api/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/pom.xml?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/pom.xml (original) +++ sling/trunk/bundles/extensions/models/api/pom.xml Tue Dec 9 14:46:28 2014 @@ -49,6 +49,7 @@ <configuration> <instructions> <Export-Package>org.apache.sling.models.*,javax.inject;version=0</Export-Package> + <DynamicImport-Package>org.apache.sling.validation.api.*</DynamicImport-Package> </instructions> </configuration> </plugin> @@ -61,5 +62,18 @@ <version>1</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.validation.api</artifactId> + <version>1.0.0-SNAPSHOT</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.5</version> + <scope>provided</scope> + </dependency> </dependencies> </project> Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/Model.java Tue Dec 9 14:46:28 2014 @@ -50,5 +50,14 @@ public @interface Model { * @return Condition that is displayed in the felix console adapter plugin */ public String condition() default ""; + + /** + * + * @return {@link ValidationStrategy.DISABLED} in case the model should not be validated through Sling Validation (default), + * {@link ValidationStrategy.REQUIRED} in case the model should be validated and if no appropriate Sling Validation Model exists it is considered invalid or + * {@link ValidationStrategy.OPTIONAL} in case the model should be validated only in case an appropriate Sling Validation Model is found. + * @see <a href="http://sling.apache.org/documentation/bundles/validation.html">Sling Validation</a> + */ + public ValidationStrategy validation() default ValidationStrategy.DISABLED; } Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/ValidationStrategy.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/ValidationStrategy.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/ValidationStrategy.java (added) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/ValidationStrategy.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,24 @@ +/* + * 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.models.annotations; + +/** + * Used by the {@link Model} annotation. + */ +public enum ValidationStrategy { + DISABLED, REQUIRED, OPTIONAL +} Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/annotations/package-info.java Tue Dec 9 14:46:28 2014 @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@Version("1.1.3") +@Version("1.2.0") package org.apache.sling.models.annotations; import aQute.bnd.annotation.Version; \ No newline at end of file Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidResourceException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidResourceException.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidResourceException.java (added) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidResourceException.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,68 @@ +/* + * 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.models.factory; + +import java.util.List; +import java.util.Map.Entry; + +import org.apache.commons.lang.StringUtils; +import org.apache.sling.validation.api.ValidationResult; + +/** + * Thrown in case Sling Validation detected an invalid resource upon which the model should be instanciated. + * @see <a href="http://sling.apache.org/documentation/bundles/validation.html">Sling Validation</a> + * @see ModelFactory + */ +public class InvalidResourceException extends RuntimeException { + private static final long serialVersionUID = 366657841414210438L; + private final ValidationResult result; + private final String path; + + public InvalidResourceException(ValidationResult result, String path) { + if (result.isValid()) { + throw new IllegalArgumentException("Could not create a validator exception from a valid validation result!"); + } + this.path = path; + this.result = result; + } + + /** + * + * @return the underlying {@link ValidationResult} + */ + public ValidationResult getResult() { + return result; + } + + /** + * + * @return the path of the resource which was considered invalid + */ + public String getPath() { + return path; + } + + @Override + 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")); + } + return builder.toString(); + } +} Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidValidationModelException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidValidationModelException.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidValidationModelException.java (added) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidValidationModelException.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,38 @@ +/* + * 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.models.factory; + +/** + * Thrown in case an invalid Sling validation model was found or no validation model was found at all + * (although it would be required through {@link org.apache.sling.models.annotations.ValidationStrategy.REQUIRED}). + * Usually just wraps a {@link org.apache.sling.validation.api.exceptions.SlingValidationException} + * @see <a href="http://sling.apache.org/documentation/bundles/validation.html">Sling Validation</a> + * @see ModelFactory + */ +public class InvalidValidationModelException extends RuntimeException { + + private static final long serialVersionUID = 1115037385798809055L; + + public InvalidValidationModelException(String message) { + super(message); + } + + public InvalidValidationModelException(Throwable cause) { + super(cause); + } + +} Added: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelClassException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelClassException.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelClassException.java (added) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelClassException.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,35 @@ +/* + * 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.models.factory; + +/** + * Exception which is triggered when the Model class could not be instantiated due to + * not having a model annotation, some reflection error, invalid constructors or + * because some exception within the post construct method was triggered. + * + * @see ModelFactory + */ +public final class ModelClassException extends RuntimeException { + + private static final long serialVersionUID = 4323592065808565135L; + + public ModelClassException(String message) { + super(message); + } +} Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelFactory.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelFactory.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/ModelFactory.java Tue Dec 9 14:46:28 2014 @@ -18,6 +18,7 @@ */ package org.apache.sling.models.factory; + /** * The ModelFactory instantiates Sling Model classes similar to adaptTo but is allowed to throw an exception in case * instantiation fails for some reason. @@ -31,19 +32,21 @@ public interface ModelFactory { * @return a new instance for the required model (never null) * @throws MissingElementsException in case no injector was able to inject some required values with the given types * @throws InvalidAdaptableException in case the given class cannot be instantiated from the given adaptable (different adaptable on the model annotation) - * @throws InvalidModelException in case the model could not be instanciated because model annotation was missing, reflection failed, no valid constructor was found or post-construct has thrown an error + * @throws ModelClassException in case the model could not be instanciated because model annotation was missing, reflection failed, no valid constructor was found or post-construct has thrown an error + * @throws InvalidValidationModelException in case an invalid validation model was found + * @throws InvalidResourceException in case the resource (for the Sling Model) could not be validated through Sling Validation */ public <ModelType> ModelType createModel(Object adaptable, Class<ModelType> type) throws MissingElementsException, - InvalidAdaptableException, InvalidModelException; + InvalidAdaptableException, ModelClassException, InvalidValidationModelException, InvalidResourceException; /** * * @param adaptable the adaptable to check * @param type the class to check * @return false in case the given class can not be created from the given adaptable - * @throws InvalidModelException in case no class with the Model annotation adapts to the requested type + * @throws ModelClassException in case no class with the Model annotation adapts to the requested type */ - public boolean canCreateFromAdaptable(Object adaptable, Class<?> type) throws InvalidModelException; + public boolean canCreateFromAdaptable(Object adaptable, Class<?> type) throws ModelClassException; /** * Modified: sling/trunk/bundles/extensions/models/impl/pom.xml URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/pom.xml?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/pom.xml (original) +++ sling/trunk/bundles/extensions/models/impl/pom.xml Tue Dec 9 14:46:28 2014 @@ -54,6 +54,7 @@ <Embed-Dependency> *;scope=compile, org.osgi.compendium;inline="org/osgi/util/tracker/*"</Embed-Dependency> + <DynamicImport-Package>org.apache.sling.validation.api.*</DynamicImport-Package> </instructions> </configuration> </plugin> @@ -138,5 +139,12 @@ <version>1.8.3</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.validation.api</artifactId> + <version>1.0.0-SNAPSHOT</version> + <scope>provided</scope> + <optional>true</optional> + </dependency> </dependencies> </project> Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java Tue Dec 9 14:46:28 2014 @@ -52,15 +52,21 @@ import org.apache.felix.scr.annotations. import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.ReferencePolicy; +import org.apache.felix.scr.annotations.ReferencePolicyOption; import org.apache.felix.scr.annotations.Service; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.adapter.Adaptable; import org.apache.sling.api.adapter.AdapterFactory; +import org.apache.sling.api.resource.Resource; import org.apache.sling.commons.osgi.PropertiesUtil; import org.apache.sling.commons.osgi.ServiceUtil; import org.apache.sling.models.annotations.Model; +import org.apache.sling.models.annotations.ValidationStrategy; import org.apache.sling.models.factory.InvalidAdaptableException; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.InvalidResourceException; +import org.apache.sling.models.factory.InvalidValidationModelException; import org.apache.sling.models.factory.MissingElementsException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.factory.ModelFactory; import org.apache.sling.models.impl.Result.FailureType; import org.apache.sling.models.impl.model.ConstructorParameter; @@ -69,6 +75,7 @@ import org.apache.sling.models.impl.mode import org.apache.sling.models.impl.model.InjectableMethod; import org.apache.sling.models.impl.model.ModelClass; import org.apache.sling.models.impl.model.ModelClassConstructor; +import org.apache.sling.models.impl.validation.ModelValidation; import org.apache.sling.models.spi.AcceptsNullName; import org.apache.sling.models.spi.DisposalCallback; import org.apache.sling.models.spi.DisposalCallbackRegistry; @@ -157,6 +164,9 @@ public class ModelAdapterFactory impleme @Reference(name = "implementationPicker", referenceInterface = ImplementationPicker.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) private final Map<Object, ImplementationPicker> implementationPickers = new TreeMap<Object, ImplementationPicker>(); + + @Reference(cardinality=ReferenceCardinality.OPTIONAL_UNARY, policyOption=ReferencePolicyOption.GREEDY) + private ModelValidation modelValidation; ModelPackageBundleListener listener; @@ -177,21 +187,21 @@ public class ModelAdapterFactory impleme @Override public <ModelType> ModelType createModel(Object adaptable, Class<ModelType> type) throws MissingElementsException, - InvalidAdaptableException, InvalidModelException { + InvalidAdaptableException, InvalidValidationModelException, InvalidResourceException { Result<ModelType> result = internalCreateModel(adaptable, type); result.throwException(log); return result.getModel(); } @Override - public boolean canCreateFromAdaptable(Object adaptable, Class<?> modelClass) throws InvalidModelException { + public boolean canCreateFromAdaptable(Object adaptable, Class<?> modelClass) throws ModelClassException { return innerCanCreateFromAdaptable(adaptable, modelClass); } - private boolean innerCanCreateFromAdaptable(Object adaptable, Class<?> requestedType) throws InvalidModelException { + private boolean innerCanCreateFromAdaptable(Object adaptable, Class<?> requestedType) throws ModelClassException { ModelClass<?> modelClass = getImplementationTypeForAdapterType(requestedType, adaptable); if (!modelClass.hasModelAnnotation()) { - throw new InvalidModelException(String.format("Model class '%s' does not have a model annotation", modelClass)); + throw new ModelClassException(String.format("Model class '%s' does not have a model annotation", modelClass)); } Class<?>[] declaredAdaptable = modelClass.getModelAnnotation().adaptables(); @@ -261,19 +271,24 @@ public class ModelAdapterFactory impleme } if (!isAdaptable) { result.addFailure(FailureType.ADAPTABLE_DOES_NOT_MATCH, modelClass.getType()); - } else if (modelClass.getType().isInterface()) { - InvocationHandler handler = createInvocationHandler(adaptable, modelClass, result); - if (handler != null) { - ModelType model = (ModelType) Proxy.newProxyInstance(modelClass.getType().getClassLoader(), new Class<?>[] { modelClass.getType() }, handler); - result.setModel(model); - } } else { - try { - ModelType model = createObject(adaptable, modelClass, result); - result.setModel(model); + if (!validateModel(modelAnnotation, adaptable, result)) { return result; - } catch (Exception e) { - result.addFailure(FailureType.OTHER, "Unable to create object", e); + } + if (modelClass.getType().isInterface()) { + InvocationHandler handler = createInvocationHandler(adaptable, modelClass, result); + if (handler != null) { + ModelType model = (ModelType) Proxy.newProxyInstance(modelClass.getType().getClassLoader(), new Class<?>[] { modelClass.getType() }, handler); + result.setModel(model); + } + } else { + try { + ModelType model = createObject(adaptable, modelClass, result); + result.setModel(model); + return result; + } catch (Exception e) { + result.addFailure(FailureType.OTHER, "Unable to create object", e); + } } } return result; @@ -281,6 +296,30 @@ public class ModelAdapterFactory impleme threadInvocationCounter.decrease(); } } + + private <ModelType> boolean validateModel(Model modelAnnotation, Object adaptable, Result<ModelType> result) { + if (modelAnnotation.validation() != ValidationStrategy.DISABLED) { + if (modelValidation == null) { + result.addFailure(FailureType.VALIDATION_NOT_AVAILABLE); + return false; + } + Resource resource = null; + if (adaptable instanceof SlingHttpServletRequest) { + resource = ((SlingHttpServletRequest)adaptable).getResource(); + } else if (adaptable instanceof Resource) { + resource = (Resource)adaptable; + } + if (resource != null) { + if (!modelValidation.validate(resource, modelAnnotation.validation() == ValidationStrategy.REQUIRED, result)) { + return false; + } + } else { + result.addFailureWithParameters(FailureType.ADAPTABLE_NOT_USABLE_FOR_VALIDATION, adaptable.getClass().getName()); + return false; + } + } + return true; + } private static interface InjectCallback { /** Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java Tue Dec 9 14:46:28 2014 @@ -24,13 +24,13 @@ import java.util.List; import java.util.Set; import org.apache.sling.models.factory.InvalidAdaptableException; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.factory.MissingElementsException; import org.slf4j.Logger; public class Result<ModelType> { - enum FailureType { + public enum FailureType { ADAPTABLE_DOES_NOT_MATCH("Adaptable is not acceptable for the model class"), FAILED_CALLING_POST_CONSTRUCT("Failure calling post-construct method"), NO_MODEL_ANNOTATION("Provided Adapter class does not have a Model annotation"), @@ -38,7 +38,12 @@ public class Result<ModelType> { OTHER("Unclassified problem"), MISSING_METHODS("Required methods %s on model %s were not able to be injected."), MISSING_FIELDS("Required fields %s on model %s were not able to be injected."), - MISSING_CONSTRUCTOR_PARAMS("Required constructor parameters %s on model %s were not able to be injected."); + MISSING_CONSTRUCTOR_PARAMS("Required constructor parameters %s on model %s were not able to be injected."), + ADAPTABLE_NOT_USABLE_FOR_VALIDATION("Can not call Sling Validation in case the adaptable is neiter SlingHttpServletRequest or Resource (adaptable is'%s')"), + VALIDATION_NOT_AVAILABLE("Sling Validation Bundle is not there, therefore no validation can be performed."), + VALIDATION_MODEL_NOT_FOUND("Sling Validation model could not be found"), + VALIDATION_MODEL_INVALID("Sling Validation model is invalid"), + VALIDATION_RESULT_RESOURCE_INVALID("Model is invalid according to Sling Validation"); private String message; @@ -95,13 +100,19 @@ public class Result<ModelType> { case FAILED_CALLING_POST_CONSTRUCT: case NO_MODEL_ANNOTATION: case NO_USABLE_CONSTRUCTOR: - e = new InvalidModelException(msg); + case VALIDATION_NOT_AVAILABLE: + case ADAPTABLE_NOT_USABLE_FOR_VALIDATION: + e = new ModelClassException(msg); break; case MISSING_CONSTRUCTOR_PARAMS: case MISSING_FIELDS: case MISSING_METHODS: e = new MissingElementsException(failureType.message, missingElements, clazz); break; + case VALIDATION_MODEL_NOT_FOUND: + case VALIDATION_RESULT_RESOURCE_INVALID: + case VALIDATION_MODEL_INVALID: + throw (RuntimeException)failureException; default: e = new RuntimeException(msg); break; @@ -130,6 +141,12 @@ public class Result<ModelType> { failure.log(log); } } + + public void addFailure(FailureType type) { + Failure f = new Failure(); + f.failureType = type; + failures.add(f); + } public void addFailure(FailureType type, Class<?> clazz) { Failure f = new Failure(); @@ -152,6 +169,13 @@ public class Result<ModelType> { f.clazz = clazz; failures.add(f); } + + public void addFailureWithParameters(FailureType type, Object... parameters) { + Failure f = new Failure(); + f.failureType = type; + f.failureMessage = String.format(type.message, parameters); + failures.add(f); + } public void addFailure(FailureType type, String msg) { Failure f = new Failure(); Added: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidation.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidation.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidation.java (added) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidation.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,32 @@ +/* + * 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.models.impl.validation; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.impl.Result; + +public interface ModelValidation { + + /** + * Calls the Sling Validation for the given resource. + * @param resource + * @param required if {@code true} validation fails even if no appropriate validation model could be found. + * @return {@code true} if validation was successful, otherwise {@code false} + */ + public abstract <ModelType> boolean validate(Resource resource, boolean required, Result<ModelType> result); + +} Added: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidationImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidationImpl.java?rev=1644069&view=auto ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidationImpl.java (added) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/validation/ModelValidationImpl.java Tue Dec 9 14:46:28 2014 @@ -0,0 +1,75 @@ +/* + * 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.models.impl.validation; + +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.api.resource.Resource; +import org.apache.sling.models.factory.InvalidResourceException; +import org.apache.sling.models.factory.InvalidValidationModelException; +import org.apache.sling.models.impl.Result; +import org.apache.sling.models.impl.Result.FailureType; +import org.apache.sling.validation.api.ValidationModel; +import org.apache.sling.validation.api.ValidationResult; +import org.apache.sling.validation.api.ValidationService; +import org.apache.sling.validation.api.exceptions.SlingValidationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Service +@Component +public class ModelValidationImpl implements ModelValidation { + + @Reference + private ValidationService validation; + + private static final Logger log = LoggerFactory.getLogger(ModelValidationImpl.class); + + @Override + public <ModelType> boolean validate(Resource resource, boolean required, Result<ModelType> result) { + try { + ValidationModel validationModel = validation.getValidationModel(resource); + if (validationModel == null) { + String error = String.format("Could not find validation model for resource '%s' with type '%s'", resource.getPath(), resource.getResourceType()); + if (required) { + result.addFailure(FailureType.VALIDATION_MODEL_NOT_FOUND, new InvalidValidationModelException(error)); + return false; + } else { + log.warn(error); + } + } else { + try { + ValidationResult validationResult = validation.validate(resource, validationModel); + if (!validationResult.isValid()) { + result.addFailure(FailureType.VALIDATION_RESULT_RESOURCE_INVALID, new InvalidResourceException(validationResult, resource.getPath())); + return false; + } + } catch (SlingValidationException e) { + result.addFailure(FailureType.VALIDATION_MODEL_INVALID, new InvalidValidationModelException(e)); + return false; + } + } + } catch (IllegalStateException e) { + result.addFailure(FailureType.VALIDATION_MODEL_INVALID, new SlingValidationException(e.getMessage(), e)); + } + + return true; + } + + +} Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/AdapterFactoryTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/AdapterFactoryTest.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/AdapterFactoryTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/AdapterFactoryTest.java Tue Dec 9 14:46:28 2014 @@ -29,7 +29,7 @@ import org.apache.sling.api.wrappers.Val import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.Self; import org.apache.sling.models.factory.InvalidAdaptableException; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.factory.MissingElementsException; import org.apache.sling.models.impl.injectors.SelfInjector; import org.apache.sling.models.impl.injectors.ValueMapInjector; @@ -85,12 +85,12 @@ public class AdapterFactoryTest { Assert.assertFalse(factory.canCreateFromAdaptable(request, DefaultStringModel.class)); } - @Test(expected = InvalidModelException.class) + @Test(expected = ModelClassException.class) public void testCanCreateFromAdaptableWithInvalidModel() { factory.canCreateFromAdaptable(resource, InvalidModelWithMissingAnnotation.class); } - @Test(expected = InvalidModelException.class) + @Test(expected = ModelClassException.class) public void testCreateFromNonModelClass() { factory.createModel(resource, InvalidModelWithMissingAnnotation.class); } Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java Tue Dec 9 14:46:28 2014 @@ -22,7 +22,7 @@ import static org.mockito.Mockito.*; import java.util.Hashtable; import org.apache.sling.api.SlingHttpServletRequest; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.impl.injectors.RequestAttributeInjector; import org.apache.sling.models.impl.injectors.SelfInjector; import org.apache.sling.models.testmodels.classes.InvalidConstructorModel; @@ -110,7 +110,7 @@ public class ConstructorTest { assertNull(model); } - @Test(expected = InvalidModelException.class) + @Test(expected = ModelClassException.class) public void testInvalidConstructorInjectorException() { factory.createModel(request, InvalidConstructorModel.class); } Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/InvalidAdaptationsTest.java Tue Dec 9 14:46:28 2014 @@ -29,7 +29,7 @@ import org.apache.sling.api.resource.Val import org.apache.sling.api.wrappers.ValueMapDecorator; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.factory.InvalidAdaptableException; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.impl.injectors.ChildResourceInjector; import org.apache.sling.models.impl.injectors.ValueMapInjector; import org.junit.Before; @@ -72,7 +72,7 @@ public class InvalidAdaptationsTest { assertNull(factory.getAdapter(res, NonModel.class)); } - @Test(expected = InvalidModelException.class) + @Test(expected = ModelClassException.class) public void testNonModelClassException() { Map<String, Object> emptyMap = Collections.<String, Object> emptyMap(); Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java?rev=1644069&r1=1644068&r2=1644069&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java Tue Dec 9 14:46:28 2014 @@ -22,7 +22,7 @@ import static org.mockito.Mockito.*; import java.util.Hashtable; import org.apache.sling.api.resource.Resource; -import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.factory.ModelClassException; import org.apache.sling.models.testmodels.classes.FailingPostConstuctModel; import org.apache.sling.models.testmodels.classes.SubClass; import org.apache.sling.models.testmodels.classes.SubClassOverriddenPostConstruct; @@ -81,7 +81,7 @@ public class PostConstructTest { boolean thrown = false; try { factory.createModel(resource, FailingPostConstuctModel.class); - } catch (InvalidModelException e) { + } catch (ModelClassException e) { assertTrue(e.getMessage().contains("post-construct")); assertEquals("FAIL", e.getCause().getMessage()); thrown = true;