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 2017/03/02 13:27:51 UTC
svn commit: r1785131 [1/2] - in /sling/trunk/bundles/extensions/validation:
api/src/main/java/org/apache/sling/validation/model/
api/src/main/java/org/apache/sling/validation/model/spi/ core/
core/src/main/java/org/apache/sling/validation/impl/ core/sr...
Author: kwin
Date: Thu Mar 2 13:27:50 2017
New Revision: 1785131
URL: http://svn.apache.org/viewvc?rev=1785131&view=rev
Log:
SLING-6588 refactor caching by moving it back to the model provider
some more refactoring allowed to get rid of dependencies towards commons.osgi and commons.thread
Added:
sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ChildResourceNameRegexMatcher.java (with props)
sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ResourcePropertyNameMatcher.java (with props)
sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/util/ResourcePropertyNameRegexMatcher.java (with props)
Removed:
sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelCache.java
sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/ValidationModelCacheImpl.java
Modified:
sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ValidationModel.java
sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java
sling/trunk/bundles/extensions/validation/core/pom.xml
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/model/MergedValidationModel.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/model/ValidationModelImpl.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/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/model/MergedValidationModelTest.java
sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java
Modified: sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ValidationModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ValidationModel.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ValidationModel.java (original)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/ValidationModel.java Thu Mar 2 13:27:50 2017
@@ -60,5 +60,11 @@ public interface ValidationModel {
* @return the children list (can be empty if there are no children), never {@code null}
*/
@Nonnull Collection<ChildResource> getChildren();
+
+ /**
+ *
+ * @return a string indicating the original source of this validation model, e.g. a resource path
+ */
+ @Nonnull String getSource();
}
Modified: 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=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java (original)
+++ sling/trunk/bundles/extensions/validation/api/src/main/java/org/apache/sling/validation/model/spi/ValidationModelProvider.java Thu Mar 2 13:27:50 2017
@@ -18,20 +18,22 @@
*/
package org.apache.sling.validation.model.spi;
-import java.util.Collection;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
+import org.apache.sling.validation.ValidationService;
import org.apache.sling.validation.model.ValidationModel;
import org.apache.sling.validation.spi.Validator;
import org.osgi.annotation.versioning.ProviderType;
/**
- * 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 obligation of the provider implementation to invalidate the cache via the
- * {@link ValidationModelCache} OSGi service.
+ * All providers of {@link ValidationModel}s must implement this interface. Caching of validation models should be implemented in the provider itself,
+ * because the providers are asked potentially multiple times for each {@link ValidationService#getValidationModel(org.apache.sling.api.resource.Resource, boolean)} or
+ * {@link ValidationService#getValidationModel(String, String, boolean)} call.
+ *
*/
@ProviderType
public interface ValidationModelProvider {
@@ -39,16 +41,17 @@ public interface ValidationModelProvider
/**
* Retrieves the models responsible for validating the given resourceType.
*
- * @param relativeResourceType
+ * @param relativeResourceType the relative resource (relative to one of the resource resolver's search paths)
* @param validatorsMap
* all known validators in a map (key=id of validator). Only one of those should be used in the
* returned validation models.
- * @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.
+ * @return a List of {@link ValidationModel}s. Never {@code null}, but might be empty collection in case no
+ * model for the given resource type could be found. The order which model gets active is mostly determined by {@link ValidationModel#getApplicablePaths()} (longest path match wins)
+ * but in case there are multiple models having the same applicable path, the order being returned here is considered (i.e. the first one is taken).
* @throws IllegalStateException
* in case a validation model was found but it is invalid
*/
- @Nonnull Collection<ValidationModel> getModels(@Nonnull String relativeResourceType,
+ @Nonnull List<ValidationModel> getModels(@Nonnull String relativeResourceType,
@Nonnull Map<String, Validator<?>> validatorsMap) throws IllegalStateException;
}
Modified: sling/trunk/bundles/extensions/validation/core/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/pom.xml?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/pom.xml (original)
+++ sling/trunk/bundles/extensions/validation/core/pom.xml Thu Mar 2 13:27:50 2017
@@ -139,18 +139,6 @@
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.commons.threads</artifactId>
- <version>3.1.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.commons.osgi</artifactId>
- <version>2.3.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.resource</artifactId>
<version>2.2.8</version>
<scope>provided</scope>
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=1785131&r1=1785130&r2=1785131&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 Thu Mar 2 13:27:50 2017
@@ -20,6 +20,7 @@ package org.apache.sling.validation.impl
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -29,56 +30,50 @@ import javax.annotation.Nonnull;
import org.apache.sling.api.resource.LoginException;
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.impl.model.MergedValidationModel;
import org.apache.sling.validation.impl.util.Trie;
import org.apache.sling.validation.model.ValidationModel;
import org.apache.sling.validation.model.spi.ValidationModelProvider;
import org.apache.sling.validation.spi.Validator;
import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.FieldOption;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventConstants;
-import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * Retrieves the most appropriate model (the one with the longest matching applicablePath) from any of the
- * {@link ValidationModelProvider}s. Also implements a cache of all previously retrieved models.
- *
- */
-@Component(property={EventConstants.EVENT_TOPIC+"="+ValidationModelRetrieverImpl.CACHE_INVALIDATION_EVENT_TOPIC})
-public class ValidationModelRetrieverImpl implements ValidationModelRetriever, EventHandler {
+/** Retrieves the most appropriate model (the one with the longest matching applicablePath) from any of the
+ * {@link ValidationModelProvider}s. Also implements a cache of all previously retrieved models. */
+@Component
+public class ValidationModelRetrieverImpl implements ValidationModelRetriever {
public static final String CACHE_INVALIDATION_EVENT_TOPIC = "org/apache/sling/validation/cache/INVALIDATE";
- /**
- * Map of known validation models (key=validated resourceType, value={@link Trie} of {@link ValidationModel}s sorted by their
- * allowed paths)
+ /**
+ * Map of validation providers (key=service properties), Declarative Services 1.3 takes care that the list is ordered according to {@link ServiceReference#compareTo(Object)}.
+ * Highest ranked service is the last one in the list.
+ *
+ * @see OSGi R6 Comp, 112.3.8.1
*/
- protected Map<String, Trie<ValidationModel>> validationModelsCache = new ConcurrentHashMap<String, Trie<ValidationModel>>();
+ @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE, policyOption = ReferencePolicyOption.GREEDY, fieldOption = FieldOption.REPLACE)
+ protected volatile List<ValidationModelProvider> modelProviders;
- /** Map of validation providers (key=service properties) */
- private RankedServices<ValidationModelProvider> modelProviders = new RankedServices<ValidationModelProvider>();
+ /** List of all known validators (key=classname of validator) */
+ @Nonnull
+ Map<String, Validator<?>> validators = new ConcurrentHashMap<>();
- /**
- * List of all known validators (key=classname of validator)
- */
- @Nonnull Map<String, Validator<?>> validators = new ConcurrentHashMap<>();
-
- @Nonnull Map<String, ServiceReference<Validator<?>>> validatorServiceReferences = new ConcurrentHashMap<>();
+ @Nonnull
+ Map<String, ServiceReference<Validator<?>>> validatorServiceReferences = new ConcurrentHashMap<>();
@Reference
ResourceResolverFactory resourceResolverFactory;
private static final Logger LOG = LoggerFactory.getLogger(ValidationModelRetrieverImpl.class);
-
/*
* (non-Javadoc)
*
@@ -121,10 +116,8 @@ public class ValidationModelRetrieverImp
private @CheckForNull ValidationModel getModel(@Nonnull String resourceType, String resourcePath) {
ValidationModel model = null;
- Trie<ValidationModel> modelsForResourceType = validationModelsCache.get(resourceType);
- if (modelsForResourceType == null) {
- modelsForResourceType = fillTrieForResourceType(resourceType);
- }
+ Trie<ValidationModel> modelsForResourceType = fillTrieForResourceType(resourceType);
+
model = modelsForResourceType.getElementForLongestMatchingKey(resourcePath).getValue();
if (model == null && !modelsForResourceType.isEmpty()) {
LOG.warn("Although model for resource type {} is available, it is not allowed for path {}", resourceType,
@@ -133,41 +126,23 @@ public class ValidationModelRetrieverImp
return model;
}
- private synchronized @Nonnull Trie<ValidationModel> fillTrieForResourceType(@Nonnull String resourceType) {
- Trie<ValidationModel> modelsForResourceType = validationModelsCache.get(resourceType);
- // use double-checked locking (http://en.wikipedia.org/wiki/Double-checked_locking)
- if (modelsForResourceType == null) {
- // create a new (empty) trie
- modelsForResourceType = new Trie<ValidationModel>();
- validationModelsCache.put(resourceType, modelsForResourceType);
-
- // fill trie with data from model providers (all models for the given resource type, independent of resource
- // path)
- for (ValidationModelProvider modelProvider : modelProviders) {
- for (ValidationModel model : modelProvider.getModels(resourceType, validators)) {
- for (String applicablePath : model.getApplicablePaths()) {
- modelsForResourceType.insert(applicablePath, model);
- }
+ private @Nonnull Trie<ValidationModel> fillTrieForResourceType(@Nonnull String resourceType) {
+ // create a new (empty) trie
+ Trie<ValidationModel> modelsForResourceType = new Trie<ValidationModel>();
+
+ // fill trie with data from model providers (all models for the given resource type, independent of resource path)
+ // lowest ranked model provider inserts first (i.e. higher ranked should overwrite)
+ for (ValidationModelProvider modelProvider : modelProviders) {
+ for (ValidationModel model : modelProvider.getModels(resourceType, validators)) {
+ for (String applicablePath : model.getApplicablePaths()) {
+ modelsForResourceType.insert(applicablePath, model);
}
}
}
return modelsForResourceType;
}
- @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE, policyOption=ReferencePolicyOption.GREEDY)
- protected synchronized void addModelProvider(ValidationModelProvider modelProvider, Map<String, Object> props) {
- modelProviders.bind(modelProvider, props);
- LOG.debug("Invalidating models cache because new model provider '{}' available", modelProvider);
- validationModelsCache.clear();
- }
-
- protected void removeModelProvider(ValidationModelProvider modelProvider, Map<String, Object> props) {
- modelProviders.unbind(modelProvider, props);
- LOG.debug("Invalidating models cache because model provider '{}' is no longer available", modelProvider);
- validationModelsCache.clear();
- }
-
- @Reference(cardinality = ReferenceCardinality.MULTIPLE, policyOption=ReferencePolicyOption.GREEDY)
+ @Reference(cardinality = ReferenceCardinality.MULTIPLE, policyOption = ReferencePolicyOption.GREEDY)
protected void addValidator(Validator<?> validator, Map<String, Object> properties, ServiceReference<Validator<?>> serviceReference) {
String validatorId = getValidatorIdFromServiceProperties(properties, validator, serviceReference);
if (validators.containsKey(validatorId)) {
@@ -177,12 +152,14 @@ public class ValidationModelRetrieverImp
}
if (serviceReference.compareTo(existingServiceReference) == 1) {
LOG.info("Overwriting already existing validator {} from bundle {} with validator {} from bundle {},"
- + " because it has the same id {} and a higher service ranking",
- validators.get(validatorId), existingServiceReference.getBundle().getBundleId(), validator, serviceReference.getBundle().getBundleId(), validatorId);
+ + " because it has the same id '{}' and a higher service ranking",
+ validators.get(validatorId), existingServiceReference.getBundle().getBundleId(), validator,
+ serviceReference.getBundle().getBundleId(), validatorId);
validators.put(validatorId, validator);
validatorServiceReferences.put(validatorId, serviceReference);
} else {
- LOG.info("A Validator for the same id '{}' is already registered with class '{}' from bundle {} and has a higher service ranking",
+ LOG.info(
+ "A Validator for the same id '{}' is already registered with class '{}' from bundle {} and has a higher service ranking",
validatorId, validators.get(validatorId), existingServiceReference.getBundle().getBundleId());
}
} else {
@@ -191,36 +168,27 @@ public class ValidationModelRetrieverImp
}
}
- protected void removeValidator(Validator<?> validator, Map<String, Object> properties, ServiceReference<Validator<?>> serviceReference) {
- String validatorId = getValidatorIdFromServiceProperties(properties, validator, serviceReference);
- // check if this validator is really bound (might not be the case if another validator with a higher service ranking and the same id is bound)
- boolean removed = validators.remove(validatorId, validator);
- if (removed) {
- validatorServiceReferences.remove(validatorId);
- LOG.debug("Invalidating models cache because validator {} with id '{}' is no longer available", validator, validatorId);
- validationModelsCache.clear();
- } else {
- LOG.debug("Removing validator {} with id '{}' has no effect, as another validator with a higher service ranking was bound previously", validator, validatorId);
- }
+ // no need for an unbind method for validators, as those are static, i.e. component is deactivated first
+ @Activate
+ protected void activate() {
+ LOG.info("Starting service...");
}
- private String getValidatorIdFromServiceProperties(Map<String, Object> properties, Validator<?> validator, ServiceReference<Validator<?>> serviceReference) {
+ private String getValidatorIdFromServiceProperties(Map<String, Object> properties, Validator<?> validator,
+ ServiceReference<Validator<?>> serviceReference) {
Object object = properties.get(Validator.PROPERTY_VALIDATOR_ID);
if (object == null) {
- throw new IllegalArgumentException("Validator '" + validator.getClass().getName() + "' provided from bundle " + serviceReference.getBundle().getBundleId() +
+ throw new IllegalArgumentException("Validator '" + validator.getClass().getName() + "' provided from bundle "
+ + serviceReference.getBundle().getBundleId() +
" is lacking the mandatory service property " + Validator.PROPERTY_VALIDATOR_ID);
}
if (!(object instanceof String)) {
- throw new IllegalArgumentException("Validator '" + validator.getClass().getName() + "' provided from bundle " + serviceReference.getBundle().getBundleId() +
- " is providing the mandatory service property "+ Validator.PROPERTY_VALIDATOR_ID + " with the wrong type "+ object.getClass() +" (must be of type String)");
+ throw new IllegalArgumentException("Validator '" + validator.getClass().getName() + "' provided from bundle "
+ + serviceReference.getBundle().getBundleId() +
+ " is providing the mandatory service property " + Validator.PROPERTY_VALIDATOR_ID + " with the wrong type "
+ + object.getClass() + " (must be of type String)");
}
- return (String)object;
- }
-
- @Override
- public void handleEvent(Event event) {
- validationModelsCache.clear();
- LOG.debug("Models cache invalidated");
+ return (String) object;
}
}
Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/MergedValidationModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/MergedValidationModel.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/MergedValidationModel.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/MergedValidationModel.java Thu Mar 2 13:27:50 2017
@@ -42,6 +42,7 @@ public class MergedValidationModel imple
private final ValidationModel baseModel;
private final Map<String, ResourceProperty> resourcePropertiesMap;
private final Map<String, ChildResource> childResourceMap;
+ private final String source;
public MergedValidationModel(ValidationModel baseModel, ValidationModel... modelsToMerge) {
this.baseModel = baseModel;
@@ -55,7 +56,7 @@ public class MergedValidationModel imple
for (ChildResource childResource : baseModel.getChildren()) {
childResourceMap.put(childResource.getName(), childResource);
}
-
+ StringBuilder sourceStringBuilder = new StringBuilder(baseModel.getSource());
for (ValidationModel modelToMerge : modelsToMerge) {
for (ResourceProperty resourceProperty : modelToMerge.getResourceProperties()) {
// only if name is not already used, the resource property should be considered
@@ -76,7 +77,9 @@ public class MergedValidationModel imple
throw new IllegalArgumentException(msg);
}
}
+ sourceStringBuilder.append(" + ").append(modelToMerge.getSource());
}
+ source = sourceStringBuilder.toString();
}
/**
@@ -118,4 +121,10 @@ public class MergedValidationModel imple
return childResourceMap.values();
}
+ @Override
+ @Nonnull
+ public String getSource() {
+ return source;
+ }
+
}
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=1785131&r1=1785130&r2=1785131&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 Thu Mar 2 13:27:50 2017
@@ -20,7 +20,9 @@ package org.apache.sling.validation.impl
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.annotation.Nonnull;
@@ -40,8 +42,8 @@ public class ValidationModelBuilder {
public ValidationModelBuilder() {
resourceProperties = new ArrayList<ResourceProperty>();
- children = new ArrayList<ChildResource>();
- applicablePaths = new ArrayList<String>();
+ children = new ArrayList<>();
+ applicablePaths = new ArrayList<>();
}
public @Nonnull ValidationModelBuilder resourceProperty(@Nonnull ResourceProperty resourceProperty) {
@@ -49,11 +51,21 @@ public class ValidationModelBuilder {
return this;
}
+ public @Nonnull ValidationModelBuilder resourceProperties(@Nonnull List<ResourceProperty> resourceProperties) {
+ this.resourceProperties.addAll(resourceProperties);
+ return this;
+ }
+
public @Nonnull ValidationModelBuilder childResource(@Nonnull ChildResource childResource) {
children.add(childResource);
return this;
}
+ public @Nonnull ValidationModelBuilder childResources(@Nonnull List<ChildResource> childResources) {
+ children.addAll(childResources);
+ return this;
+ }
+
public @Nonnull ValidationModelBuilder setApplicablePath(@Nonnull String applicablePath) {
applicablePaths.clear();
applicablePaths.add(applicablePath);
@@ -65,7 +77,14 @@ public class ValidationModelBuilder {
return this;
}
- public @Nonnull ValidationModel build(@Nonnull String validatedResourceType) {
- return new ValidationModelImpl(resourceProperties, validatedResourceType, applicablePaths.toArray(new String[0]), children);
+ public @Nonnull ValidationModelBuilder addApplicablePaths(@Nonnull String[] applicablePaths) {
+ for (String applicablePath : applicablePaths) {
+ this.applicablePaths.add(applicablePath);
+ }
+ return this;
+ }
+
+ public @Nonnull ValidationModel build(@Nonnull String validatedResourceType, @Nonnull String source) {
+ return new ValidationModelImpl(resourceProperties, validatedResourceType, applicablePaths.toArray(new String[0]), children, source);
}
}
Modified: sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelImpl.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelImpl.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/main/java/org/apache/sling/validation/impl/model/ValidationModelImpl.java Thu Mar 2 13:27:50 2017
@@ -34,12 +34,24 @@ public class ValidationModelImpl impleme
private final @Nonnull String validatedResourceType;
private final @Nonnull String[] applicablePaths;
private final @Nonnull List<ChildResource> children;
+ private final @Nonnull String source;
- // TODO: only call from ValidationModelBuilder
- public ValidationModelImpl(@Nonnull List<ResourceProperty> resourceProperties, @Nonnull String validatedResourceType,
- String[] applicablePaths, @Nonnull List<ChildResource> children) {
+ /**
+ * Only used from {@link ValidationModelBuilder}
+ * @param resourceProperties
+ * @param validatedResourceType
+ * @param applicablePaths
+ * @param children
+ * @param source a string identifying the model's source (e.g. a resource path)
+ */
+ ValidationModelImpl(@Nonnull List<ResourceProperty> resourceProperties, @Nonnull String validatedResourceType,
+ String[] applicablePaths, @Nonnull List<ChildResource> children, @Nonnull String source) {
this.resourceProperties = resourceProperties;
this.validatedResourceType = validatedResourceType;
+
+ if (resourceProperties.isEmpty() && children.isEmpty()) {
+ throw new IllegalStateException("Neither children nor properties set in validation model for " + validatedResourceType + "'");
+ }
// if this property was not set or is an empty array...
if (applicablePaths == null || applicablePaths.length == 0) {
// ...set this to the empty string (which matches all paths)
@@ -47,12 +59,13 @@ public class ValidationModelImpl impleme
} else {
for (String applicablePath : applicablePaths) {
if (StringUtils.isBlank(applicablePath)) {
- throw new IllegalArgumentException("applicablePaths may not contain empty values!");
+ throw new IllegalStateException("applicablePaths may not contain empty values in validation model for " + validatedResourceType + "'");
}
}
this.applicablePaths = applicablePaths;
}
this.children = children;
+ this.source = source;
}
@Override
@@ -76,9 +89,14 @@ public class ValidationModelImpl impleme
}
@Override
+ public @Nonnull String getSource() {
+ return source;
+ }
+
+ @Override
public String toString() {
- return "ResourceValidationModel [resourceProperties=" + resourceProperties + ", validatedResourceType="
- + validatedResourceType + ", applicablePaths=" + Arrays.toString(applicablePaths) + ", children=" + children + "]";
+ return "ValidationModelImpl [resourceProperties=" + resourceProperties + ", validatedResourceType=" + validatedResourceType
+ + ", applicablePaths=" + Arrays.toString(applicablePaths) + ", children=" + children + ", source="+ source +"]";
}
@Override
@@ -88,6 +106,7 @@ public class ValidationModelImpl impleme
result = prime * result + Arrays.hashCode(applicablePaths);
result = prime * result + ((children == null) ? 0 : children.hashCode());
result = prime * result + ((resourceProperties == null) ? 0 : resourceProperties.hashCode());
+ result = prime * result + ((source == null) ? 0 : source.hashCode());
result = prime * result + ((validatedResourceType == null) ? 0 : validatedResourceType.hashCode());
return result;
}
@@ -107,8 +126,12 @@ public class ValidationModelImpl impleme
return false;
if (!resourceProperties.equals(other.resourceProperties))
return false;
+ if (!source.equals(other.source))
+ return false;
if (!validatedResourceType.equals(other.validatedResourceType))
return false;
return true;
}
+
+
}
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=1785131&r1=1785130&r2=1785131&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 Thu Mar 2 13:27:50 2017
@@ -19,13 +19,16 @@
package org.apache.sling.validation.impl.resourcemodel;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
@@ -35,22 +38,16 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
-import org.apache.sling.commons.osgi.PropertiesUtil;
-import org.apache.sling.commons.threads.ModifiableThreadPoolConfig;
-import org.apache.sling.commons.threads.ThreadPool;
-import org.apache.sling.commons.threads.ThreadPoolManager;
-import org.apache.sling.commons.threads.ThreadPoolConfig.ThreadPoolPolicy;
import org.apache.sling.serviceusermapping.ServiceUserMapped;
import org.apache.sling.validation.impl.model.ChildResourceImpl;
import org.apache.sling.validation.impl.model.ParameterizedValidatorImpl;
import org.apache.sling.validation.impl.model.ResourcePropertyImpl;
-import org.apache.sling.validation.impl.model.ValidationModelImpl;
+import org.apache.sling.validation.impl.model.ValidationModelBuilder;
import org.apache.sling.validation.impl.util.Trie;
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.model.spi.ValidationModelCache;
import org.apache.sling.validation.model.spi.ValidationModelProvider;
import org.apache.sling.validation.spi.Validator;
import org.osgi.framework.ServiceRegistration;
@@ -69,10 +66,12 @@ import org.slf4j.LoggerFactory;
@Component(service = ValidationModelProvider.class)
public class ResourceValidationModelProviderImpl implements ValidationModelProvider, EventHandler {
- 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 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";
@@ -88,29 +87,18 @@ public class ResourceValidationModelProv
@Reference
ResourceResolverFactory rrf = null;
- @Reference
- private ValidationModelCache cache;
-
private static final Logger LOG = LoggerFactory.getLogger(ResourceValidationModelProviderImpl.class);
- @Reference
- private ThreadPoolManager tpm = null;
-
- private ThreadPool threadPool;
-
private ServiceRegistration<EventHandler> eventHandlerRegistration;
@Reference
private ServiceUserMapped serviceUserMapped;
+ /** key = resource type of validation models value = a list of all validation models for the resource type given in the key */
+ final Map<String, List<ValidationModel>> validationModelCacheByResourceType = new ConcurrentHashMap<>();
+
@Activate
protected void activate(ComponentContext componentContext) throws LoginException {
- ModifiableThreadPoolConfig threadPoolConfig = new ModifiableThreadPoolConfig();
- threadPoolConfig.setMinPoolSize(1);
- threadPoolConfig.setMaxPoolSize(1);
- threadPoolConfig.setQueueSize(2); // make sure at most 2 invalidation requests queue up
- threadPoolConfig.setBlockPolicy(ThreadPoolPolicy.DISCARD);
- threadPool = tpm.create(threadPoolConfig, "Validation Service Thread Pool");
ResourceResolver rr = null;
try {
rr = rrf.getServiceResourceResolver(null);
@@ -138,9 +126,6 @@ public class ResourceValidationModelProv
@Deactivate
protected void deactivate(ComponentContext componentContext) {
- if (threadPool != null) {
- tpm.release(threadPool);
- }
if (eventHandlerRegistration != null) {
eventHandlerRegistration.unregister();
eventHandlerRegistration = null;
@@ -149,39 +134,103 @@ public class ResourceValidationModelProv
@Override
public void handleEvent(Event event) {
- LOG.debug("Asynchronously invalidating models cache due to event {}", event);
- Runnable task = new Runnable() {
- @Override
- public void run() {
+ String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
+ if (path == null) {
+ LOG.warn("Received event {}, but could not get the affected path", event);
+ return;
+ }
+ Set<String> resourceTypesToInvalidate = new HashSet<>();
+ switch (event.getTopic()) {
+ case SlingConstants.TOPIC_RESOURCE_REMOVED:
+ // find cache entries below the removed resource
+ for (Entry<String, List<ValidationModel>> validationModelByResourceType : validationModelCacheByResourceType.entrySet()) {
+ for (ValidationModel model : validationModelByResourceType.getValue()) {
+ if (model.getSource().startsWith(path)) {
+ LOG.debug("Invalidate validation model at {}, because resource at {} has been removed", model.getSource(), path);
+ resourceTypesToInvalidate.add(validationModelByResourceType.getKey());
+ }
+ }
+ }
+ break;
+ default:
+ // only consider additions/changes of resources with resource type = validation model resource type
+ String resourceType = (String) event.getProperty(SlingConstants.PROPERTY_RESOURCE_TYPE);
+ if (resourceType == null) {
+ LOG.warn("Received event {}, but could not get the modified/added resource type", event);
+ return;
+ }
+ if (VALIDATION_MODEL_RESOURCE_TYPE.equals(resourceType)) {
+ // retrieve the resource types covered by the newly added model
+ String resourceTypeToInvalidate = null;
try {
- // defer invalidating the cache, to prevent to many invalidation events to be sent in a row when a lot of modifications happen below the resource resolver's search paths
- Thread.sleep(500);
- } catch (InterruptedException e) {
- LOG.warn("Could not wait 500 seconds till invalidating the cache", e);
+ resourceTypeToInvalidate = getResourceTypeOfValidationModel(path);
+ } catch (Exception e) {
+ LOG.warn("Could not get covered resource type of newly added validation model at " + path, e);
+ }
+ if (resourceTypeToInvalidate != null) {
+ LOG.debug("Invalidate validation models for resource type {}, because resource at {} provides a new/modified validation model for that type", resourceType, path);
+ resourceTypesToInvalidate.add(resourceTypeToInvalidate);
+ } else {
+ LOG.debug("Resource at {} provides a new/modified validation model but could not yet determine for which resource type", path);
}
- cache.invalidate();
}
- };
- threadPool.execute(task);
+ // or paths already covered by the cache
+ for (Entry<String, List<ValidationModel>> validationModelByResourceType : validationModelCacheByResourceType.entrySet()) {
+ for (ValidationModel model : validationModelByResourceType.getValue()) {
+ if (path.startsWith(model.getSource())) {
+ LOG.debug("Invalidate validation model at {}, because resource below (at {}) has been modified", model.getSource(), path);
+ resourceTypesToInvalidate.add(validationModelByResourceType.getKey());
+ }
+ }
+ }
+ }
+ for (String resourceTypeToInvalidate : resourceTypesToInvalidate) {
+ validationModelCacheByResourceType.remove(resourceTypeToInvalidate);
+ }
+ }
+
+ private String getResourceTypeOfValidationModel(String path) throws LoginException {
+ ResourceResolver resourceResolver = null;
+ try {
+ resourceResolver = rrf.getServiceResourceResolver(null);
+ Resource modelResource = resourceResolver.getResource(path);
+ ValueMap properties = modelResource.adaptTo(ValueMap.class);
+ if (properties == null) {
+ throw new IllegalStateException("Could not adapt resource at " + path + " to a ValueMap");
+ }
+ return properties.get(VALIDATED_RESOURCE_TYPE, null);
+ } finally {
+ if (resourceResolver != null) {
+ resourceResolver.close();
+ }
+ }
}
- /**
- * 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.
- *
- * @param relativeResourceType
- * {@inheritDoc}
- * @param validatorsMap
- * {@inheritDoc}
- * @return {@inheritDoc}
- * @throws {@inheritDoc}
+ /*
+ * (non-Javadoc)
+ * @see org.apache.sling.validation.model.spi.ValidationModelProvider#getModels(java.lang.String, java.util.Map)
*/
@Override
+ public @Nonnull List<ValidationModel> getModels(@Nonnull String relativeResourceType, @Nonnull Map<String, Validator<?>> validatorsMap) {
+ List<ValidationModel> cacheEntry = validationModelCacheByResourceType.get(relativeResourceType);
+ if (cacheEntry == null) {
+ cacheEntry = doGetModels(relativeResourceType, validatorsMap);
+ validationModelCacheByResourceType.put(relativeResourceType, cacheEntry);
+ }
+ return cacheEntry;
+ }
+
+ /**
+ * Searches for validation models bound to a specific resource type through a search query.
+ *
+ * @param relativeResourceType the resource type to look for
+ * @param validatorsMap all known validators in a map (key=id of validator). Only one of those should be used in the returned validation models.
+ * @return a List of {@link ValidationModel}s. Never {@code null}, but might be empty collection in case no
+ * model for the given resource type could be found. Returns the models below "/apps" before the models below "/libs".
+ * @throws IllegalStateException in case a validation model is found but it is invalid */
@Nonnull
- public Collection<ValidationModel> getModels(@Nonnull String relativeResourceType, @Nonnull Map<String, Validator<?>> validatorsMap) {
- ValidationModelImpl vm;
- Collection<ValidationModel> validationModels = new ArrayList<ValidationModel>();
+ private List<ValidationModel> doGetModels(@Nonnull String relativeResourceType, @Nonnull Map<String, Validator<?>> validatorsMap) {
+ List<ValidationModel> validationModels = new ArrayList<ValidationModel>();
ResourceResolver resourceResolver = null;
try {
resourceResolver = rrf.getServiceResourceResolver(null);
@@ -192,22 +241,18 @@ public class ResourceValidationModelProv
while (models.hasNext()) {
Resource model = models.next();
LOG.debug("Found validation model resource {}.", model.getPath());
- String jcrPath = model.getPath();
+ String resourcePath = model.getPath();
try {
+ ValidationModelBuilder modelBuilder = new ValidationModelBuilder();
ValueMap validationModelProperties = model.adaptTo(ValueMap.class);
- 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()) {
- throw new IllegalArgumentException("Neither children nor properties set.");
- } else {
- vm = new ValidationModelImpl(resourceProperties, relativeResourceType,
- applicablePaths, children);
- validationModels.add(vm);
- }
+ modelBuilder.addApplicablePaths(validationModelProperties.get(ResourceValidationModelProviderImpl.APPLICABLE_PATHS, String[].class));
+ Resource propertiesResource = model.getChild(ResourceValidationModelProviderImpl.PROPERTIES);
+ modelBuilder.resourceProperties(buildProperties(validatorsMap, propertiesResource));
+ modelBuilder.childResources(buildChildren(model, model, validatorsMap));
+ ValidationModel vm = modelBuilder.build(relativeResourceType, resourcePath);
+ validationModels.add(vm);
} catch (IllegalArgumentException e) {
- throw new IllegalStateException("Found invalid validation model in '" + jcrPath + "': "
+ throw new IllegalStateException("Found invalid validation model in '" + resourcePath + "': "
+ e.getMessage(), e);
}
}
@@ -227,24 +272,22 @@ public class ResourceValidationModelProv
}
}
}
-
- /**
- * Creates a set of the properties that a resource is expected to have, together with the associated validators.
+
+ /** Creates a set of the properties that a resource is expected to have, together with the associated validators.
*
- * @param validatorsMap a map containing {@link Validator}s as values and their id's as keys
+ * @param validatorsMap a map containing {@link Validator}s as values and their id's as keys
* @param propertiesResource the resource identifying the properties node from a validation model's structure (might be {@code null})
* @return a set of properties or an empty set if no properties are defined
- * @see ResourceProperty
- */
+ * @see ResourceProperty */
private @Nonnull List<ResourceProperty> buildProperties(@Nonnull Map<String, Validator<?>> validatorsMap, Resource propertiesResource) {
List<ResourceProperty> properties = new ArrayList<ResourceProperty>();
if (propertiesResource != null) {
for (Resource property : propertiesResource.getChildren()) {
String fieldName = property.getName();
ValueMap propertyValueMap = property.adaptTo(ValueMap.class);
- 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);
+ Boolean propertyMultiple = propertyValueMap.get(ResourceValidationModelProviderImpl.PROPERTY_MULTIPLE, false);
+ Boolean propertyRequired = !propertyValueMap.get(ResourceValidationModelProviderImpl.OPTIONAL, false);
+ String nameRegex = propertyValueMap.get(ResourceValidationModelProviderImpl.NAME_REGEX, null);
Resource validators = property.getChild(ResourceValidationModelProviderImpl.VALIDATORS);
List<ParameterizedValidator> parameterizedValidators = new ArrayList<ParameterizedValidator>();
if (validators != null) {
@@ -261,7 +304,8 @@ public class ResourceValidationModelProv
throw new IllegalArgumentException("Could not find validator with id '" + validatorId + "'");
}
// get arguments for validator
- String[] validatorArguments = validatorProperties.get(ResourceValidationModelProviderImpl.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) {
@@ -277,25 +321,24 @@ public class ResourceValidationModelProv
parameterizedValidators.add(new ParameterizedValidatorImpl(validator, validatorArgumentsMap, severity));
}
}
- ResourceProperty f = new ResourcePropertyImpl(fieldName, nameRegex, propertyMultiple, propertyRequired, parameterizedValidators);
+ ResourceProperty f = new ResourcePropertyImpl(fieldName, nameRegex, propertyMultiple, propertyRequired,
+ parameterizedValidators);
properties.add(f);
}
}
return properties;
}
- /**
- * Searches children resources from a {@code modelResource}, starting from the {@code rootResource}. If one needs all the children
+ /** Searches children resources from a {@code modelResource}, starting from the {@code rootResource}. If one needs all the children
* resources of a model, then the {@code modelResource} and the {@code rootResource} should be identical.
*
- * @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
- * 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
- */
+ * @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 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) {
+ @Nonnull Map<String, Validator<?>> validatorsMap) {
List<ChildResource> children = new ArrayList<ChildResource>();
Resource childrenResource = rootResource.getChild(ResourceValidationModelProviderImpl.CHILDREN);
if (childrenResource != null) {
@@ -313,8 +356,10 @@ public class ResourceValidationModelProv
// otherwise fall back to the name
nameRegex = null;
}
- 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));
+ boolean isRequired = !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/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=1785131&r1=1785130&r2=1785131&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 Thu Mar 2 13:27:50 2017
@@ -21,8 +21,8 @@ package org.apache.sling.validation.impl
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Dictionary;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
@@ -30,21 +30,18 @@ import javax.annotation.Nonnull;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.sling.api.resource.LoginException;
-import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.validation.impl.model.ResourcePropertyBuilder;
import org.apache.sling.validation.impl.model.ValidationModelBuilder;
+import org.apache.sling.validation.impl.util.ResourcePropertyNameMatcher;
import org.apache.sling.validation.impl.util.examplevalidators.DateValidator;
import org.apache.sling.validation.impl.util.examplevalidators.StringValidator;
import org.apache.sling.validation.model.ResourceProperty;
import org.apache.sling.validation.model.ValidationModel;
import org.apache.sling.validation.model.spi.ValidationModelProvider;
import org.apache.sling.validation.spi.Validator;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
-import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -55,9 +52,6 @@ import org.mockito.runners.MockitoJUnitR
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.event.Event;
-
-import edu.umd.cs.findbugs.annotations.When;
@RunWith(MockitoJUnitRunner.class)
public class ValidationModelRetrieverImplTest {
@@ -86,18 +80,20 @@ public class ValidationModelRetrieverImp
*
*/
class TestModelProvider implements ValidationModelProvider {
- int counter = 0;
-
+ private @Nonnull final String source;
+ public TestModelProvider(@Nonnull String source) {
+ this.source = source;
+ }
+
@Override
- public @Nonnull Collection<ValidationModel> getModels(@Nonnull String relativeResourceType,
+ public @Nonnull List<ValidationModel> getModels(@Nonnull String relativeResourceType,
@Nonnull Map<String, Validator<?>> validatorsMap) {
// make sure the date validator is passed along
Assert.assertThat(validatorsMap,
Matchers.<String, Validator<?>> hasEntry(DATE_VALIDATOR_ID, dateValidator));
- Collection<ValidationModel> models = new ArrayList<ValidationModel>();
- Collection<String> applicablePaths = (Collection<String>) applicablePathPerResourceType
- .get(relativeResourceType);
+ List<ValidationModel> models = new ArrayList<ValidationModel>();
+ Collection<String> applicablePaths = applicablePathPerResourceType.get(relativeResourceType);
if (applicablePaths != null) {
for (String applicablePath : applicablePaths) {
ValidationModelBuilder modelBuilder = new ValidationModelBuilder();
@@ -105,46 +101,21 @@ public class ValidationModelRetrieverImp
modelBuilder.addApplicablePath(applicablePath);
}
modelBuilder.resourceProperty(new ResourcePropertyBuilder().build(relativeResourceType));
- models.add(modelBuilder.build(relativeResourceType));
+ models.add(modelBuilder.build(relativeResourceType, source));
}
}
- counter++;
return models;
}
}
- /**
- * Custom Hamcrest matcher which matches Resource Properties based on the equality only on their name.
- */
- private static final class ResourcePropertyNameMatcher extends TypeSafeMatcher<ResourceProperty> {
-
- private final String expectedName;
-
- public ResourcePropertyNameMatcher(String name) {
- expectedName = name;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("ResourceProperty with name=" + expectedName);
- }
-
- @Override
- protected boolean matchesSafely(ResourceProperty resourceProperty) {
- return expectedName.equals(resourceProperty.getName());
- }
- }
-
@Before
public void setup() throws LoginException {
dateValidator = new DateValidator();
applicablePathPerResourceType = new ArrayListValuedHashMap<>();
validationModelRetriever = new ValidationModelRetrieverImpl();
- modelProvider = new TestModelProvider();
- // service id must be set (even if service ranking is not set)
- Map<String, Object> properties = new HashMap<String, Object>();
- properties.put(Constants.SERVICE_ID, 1L);
- validationModelRetriever.addModelProvider(modelProvider, properties);
+ modelProvider = new TestModelProvider("source1");
+ validationModelRetriever.modelProviders = new ArrayList<>();
+ validationModelRetriever.modelProviders.add(modelProvider);
Mockito.doReturn(1l).when(providingBundle).getBundleId();
Mockito.doReturn(providingBundle).when(validatorServiceReference).getBundle();
Mockito.doReturn(providingBundle).when(newValidatorServiceReference).getBundle();
@@ -214,36 +185,6 @@ public class ValidationModelRetrieverImp
}
@Test
- public void testGetCachedModel() {
- applicablePathPerResourceType.put("test/type", "/content/site1");
- // call two times, the second time the counter must be the same (because provider is not called)
- ValidationModel model = validationModelRetriever.getModel("test/type", "/content/site1", false);
- Assert.assertNotNull(model);
- Assert.assertEquals(1, modelProvider.counter);
- model = validationModelRetriever.getModel("test/type", "/content/site1", false);
- Assert.assertNotNull(model);
- Assert.assertEquals(1, modelProvider.counter);
-
- model = validationModelRetriever.getModel("invalid/type", "/content/site1", false);
- Assert.assertNull(model);
- Assert.assertEquals(2, modelProvider.counter);
- model = validationModelRetriever.getModel("invalid/type", "/content/site1", false);
- Assert.assertNull(model);
- Assert.assertEquals(2, modelProvider.counter);
- }
-
- @Test
- public void testGetCachedInvalidation() {
- applicablePathPerResourceType.put("test/type", "/content/site1");
- validationModelRetriever.getModel("test/type", "/content/site1", false);
- Assert.assertEquals(1, modelProvider.counter);
- validationModelRetriever.handleEvent(new Event(ValidationModelRetrieverImpl.CACHE_INVALIDATION_EVENT_TOPIC, (Dictionary<String, ?>) null));
- // after cache invalidation the provider is called again
- validationModelRetriever.getModel("test/type", "/content/site1", false);
- Assert.assertEquals(2, modelProvider.counter);
- }
-
- @Test
public void testGetModelWithResourceInheritance() {
// in case no super type is known, just return model
applicablePathPerResourceType.put("test/type", "/content/site1");
@@ -270,8 +211,6 @@ public class ValidationModelRetrieverImp
model = validationModelRetriever.getModel("test/type", "/content/site1", true);
Assert.assertNull("Found model although no model has been specified (neither in base nor in super type)", model);
- validationModelRetriever.validationModelsCache.clear();
-
// only supertype has model being set
applicablePathPerResourceType.put("test/supertype", "/content/site1");
model = validationModelRetriever.getModel("test/type", "/content/site1", true);
@@ -290,4 +229,34 @@ public class ValidationModelRetrieverImp
Assert.assertNotNull(model);
Assert.assertThat(model.getResourceProperties(), Matchers.contains(new ResourcePropertyNameMatcher("test/type")));
}
+
+ @Test
+ public void testGetModelWithMultipleProvidersHigherRanking() {
+ ValidationModelProvider modelProvider2 = new TestModelProvider("source2");
+ validationModelRetriever.modelProviders.clear();
+ validationModelRetriever.modelProviders.add(modelProvider);
+ validationModelRetriever.modelProviders.add(modelProvider2);
+ // each provider must return the same applicable path but different
+ applicablePathPerResourceType.put("test/type", "/content/site1");
+
+ ValidationModel model = validationModelRetriever.getModel("test/type", "/content/site1/somepage", false);
+ Assert.assertNotNull(model);
+ Assert.assertEquals("source2", model.getSource());
+
+ }
+
+ @Test
+ public void testGetModelWithMultipleProvidersLowerRanking() {
+ ValidationModelProvider modelProvider2 = new TestModelProvider("source2");
+ validationModelRetriever.modelProviders.clear();
+ validationModelRetriever.modelProviders.add(modelProvider2);
+ validationModelRetriever.modelProviders.add(modelProvider);
+ // each provider must return the same applicable path but different
+ applicablePathPerResourceType.put("test/type", "/content/site1");
+
+ ValidationModel model = validationModelRetriever.getModel("test/type", "/content/site1/somepage", false);
+ Assert.assertNotNull(model);
+ Assert.assertEquals("source1", model.getSource());
+
+ }
}
Modified: sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/ValidationServiceImplTest.java Thu Mar 2 13:27:50 2017
@@ -102,7 +102,7 @@ public class ValidationServiceImplTest {
public void testValueMapWithWrongDataType() throws Exception {
propertyBuilder.validator(new DateValidator());
modelBuilder.resourceProperty(propertyBuilder.build("field1"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("field1", "1");
@@ -126,7 +126,7 @@ public class ValidationServiceImplTest {
};
propertyBuilder.validator(myValidator);
modelBuilder.resourceProperty(propertyBuilder.build("field1"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("field1", "1");
@@ -141,7 +141,7 @@ public class ValidationServiceImplTest {
modelBuilder.resourceProperty(propertyBuilder.build("field2"));
modelBuilder.resourceProperty(propertyBuilder.build("field3"));
modelBuilder.resourceProperty(propertyBuilder.build("field4"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
// this should not be detected as missing property
HashMap<String, Object> hashMap = new HashMap<String, Object>();
@@ -156,7 +156,7 @@ public class ValidationServiceImplTest {
@Test()
public void testValueMapWithMissingOptionalValue() throws Exception {
modelBuilder.resourceProperty(propertyBuilder.optional().build("field1"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("field2", "1");
@@ -170,7 +170,7 @@ public class ValidationServiceImplTest {
propertyBuilder.optional();
propertyBuilder.validator(new RegexValidator(), 2, RegexValidator.REGEX_PARAM, "abc");
modelBuilder.resourceProperty(propertyBuilder.build("field1"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("field1", "");
@@ -188,7 +188,7 @@ public class ValidationServiceImplTest {
final String TEST_REGEX = "^test$";
propertyBuilder.validator(new RegexValidator(), 0, RegexValidator.REGEX_PARAM, TEST_REGEX);
modelBuilder.resourceProperty(propertyBuilder.build("field2"));
- ValidationModel vm = modelBuilder.build("sling/validation/test");
+ ValidationModel vm = modelBuilder.build("sling/validation/test", "some source");
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("field1", "HelloWorld");
@@ -213,7 +213,7 @@ public class ValidationServiceImplTest {
modelChild = new ChildResourceImpl("optionalChild", null, false, Collections.singletonList(property), Collections.emptyList());
modelBuilder.childResource(modelChild);
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
ResourceResolver rr = context.resourceResolver();
Resource nonExistingResource = new NonExistingResource(rr, "non-existing-resource");
ValidationResult vr = validationService.validate(nonExistingResource, vm);
@@ -237,7 +237,7 @@ public class ValidationServiceImplTest {
modelChild = new ChildResourceImpl("optionalChild", null, false, Collections.singletonList(property), Collections.emptyList());
modelBuilder.childResource(modelChild);
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
ResourceResolver rr = context.resourceResolver();
Resource nonExistingResource = new SyntheticResource(rr, "someresource", "resourceType");
ValidationResult vr = validationService.validate(nonExistingResource, vm);
@@ -260,7 +260,7 @@ public class ValidationServiceImplTest {
Collections.singletonList(modelGrandChild));
modelBuilder.childResource(modelChild);
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
// create a resource
ResourceResolver rr = context.resourceResolver();
@@ -288,7 +288,7 @@ public class ValidationServiceImplTest {
ChildResource child = new ChildResourceImpl("child", null, false, Collections.singletonList(property),
Collections.<ChildResource> emptyList());
modelBuilder.childResource(child);
- ValidationModel vm = modelBuilder.build("type");
+ ValidationModel vm = modelBuilder.build("type", "some source");
// create a resource (lacking the optional "child" sub resource)
ResourceResolver rr = context.resourceResolver();
@@ -310,7 +310,7 @@ public class ValidationServiceImplTest {
ChildResource modelChild = new ChildResourceImpl("child", null, true, Collections.singletonList(property),
Collections.singletonList(modelGrandChild));
modelBuilder.childResource(modelChild);
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
// create a resource
ResourceResolver rr = context.resourceResolver();
@@ -345,7 +345,7 @@ public class ValidationServiceImplTest {
};
propertyBuilder.validator(extendedValidator); // accept any digits
modelBuilder.resourceProperty(propertyBuilder.build("field1"));
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
// create a resource
ResourceResolver rr = context.resourceResolver();
@@ -371,7 +371,7 @@ public class ValidationServiceImplTest {
modelBuilder.childResource(modelChild);
modelBuilder.childResource(siblingChild);
- ValidationModel vm = modelBuilder.build("sometype");
+ ValidationModel vm = modelBuilder.build("sometype", "some source");
ResourceResolver rr = context.resourceResolver();
Resource testResource = ResourceUtil.getOrCreateResource(rr, "/apps/validation/1/resource",
@@ -405,7 +405,7 @@ public class ValidationServiceImplTest {
modelBuilder.resourceProperty(propertyBuilder.build("otherfield"));
propertyBuilder.nameRegex("optionalfield.*").optional();
modelBuilder.resourceProperty(propertyBuilder.build("optionalfield"));
- ValidationModel vm = modelBuilder.build("type");
+ ValidationModel vm = modelBuilder.build("type", "some source");
// create a resource
ResourceResolver rr = context.resourceResolver();
@@ -430,7 +430,7 @@ public class ValidationServiceImplTest {
propertyBuilder.validator(new RegexValidator(), 0, RegexValidator.REGEX_PARAM, "\\d"); // accept any digits
propertyBuilder.multiple();
modelBuilder.resourceProperty(propertyBuilder.build("field"));
- ValidationModel vm = modelBuilder.build("type");
+ ValidationModel vm = modelBuilder.build("type", "some source");
ResourceResolver rr = context.resourceResolver();
Resource testResource = ResourceUtil.getOrCreateResource(rr, "/content/validation/1/resource",
@@ -446,10 +446,10 @@ public class ValidationServiceImplTest {
@Test()
public void testValidateResourceRecursively() throws Exception {
modelBuilder.resourceProperty(propertyBuilder.build("field1"));
- final ValidationModel vm1 = modelBuilder.build("resourcetype1");
+ final ValidationModel vm1 = modelBuilder.build("resourcetype1", "some source");
modelBuilder = new ValidationModelBuilder();
modelBuilder.resourceProperty(propertyBuilder.build("field2"));
- final ValidationModel vm2 = modelBuilder.build("resourcetype2");
+ final ValidationModel vm2 = modelBuilder.build("resourcetype2", "some source");
// set model retriever
validationService.modelRetriever = new ValidationModelRetriever() {
Modified: sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/model/MergedValidationModelTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/model/MergedValidationModelTest.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/model/MergedValidationModelTest.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/model/MergedValidationModelTest.java Thu Mar 2 13:27:50 2017
@@ -19,14 +19,11 @@
package org.apache.sling.validation.impl.model;
import java.util.Arrays;
-import java.util.regex.Pattern;
-import org.apache.sling.validation.model.ChildResource;
-import org.apache.sling.validation.model.ResourceProperty;
+import org.apache.sling.validation.impl.util.ChildResourceNameRegexMatcher;
+import org.apache.sling.validation.impl.util.ResourcePropertyNameRegexMatcher;
import org.apache.sling.validation.model.ValidationModel;
-import org.hamcrest.Description;
import org.hamcrest.Matchers;
-import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -41,23 +38,25 @@ public class MergedValidationModelTest {
public void setup() {
modelBuilder = new ValidationModelBuilder();
propertyBuilder = new ResourcePropertyBuilder();
+ // each model needs at least one property or childresource
+ modelBuilder.resourceProperty(propertyBuilder.build("nameToOverwrite"));
childResourceBuilder = new ChildResourceBuilder();
}
@Test(expected = IllegalArgumentException.class)
public void testMoreSpecificApplicationPathInModelToMerge() {
modelBuilder.addApplicablePath("/base/path").addApplicablePath("/base/path2");
- ValidationModel baseValidationModel = modelBuilder.build("base");
+ ValidationModel baseValidationModel = modelBuilder.build("base", "some source");
modelBuilder.setApplicablePath("/base/path3");
- new MergedValidationModel(baseValidationModel, modelBuilder.build("superType"));
+ new MergedValidationModel(baseValidationModel, modelBuilder.build("superType", "some source"));
}
@Test
public void testLessSpecificApplicationPathInModelToMerge() {
modelBuilder.addApplicablePath("/base/path").addApplicablePath("/base/path2");
- ValidationModel baseValidationModel = modelBuilder.build("base");
+ ValidationModel baseValidationModel = modelBuilder.build("base", "some source");
modelBuilder.setApplicablePath("/base");
- ValidationModel mergedModel = new MergedValidationModel(baseValidationModel, modelBuilder.build("superType"));
+ ValidationModel mergedModel = new MergedValidationModel(baseValidationModel, modelBuilder.build("superType", "some source"));
Assert.assertThat(Arrays.asList(mergedModel.getApplicablePaths()),
Matchers.contains("/base/path", "/base/path2"));
}
@@ -67,7 +66,7 @@ public class MergedValidationModelTest {
modelBuilder.resourceProperty(propertyBuilder.nameRegex("overwrittenNameToOverwrite").build("nameToOverwrite"));
modelBuilder.childResource(childResourceBuilder.nameRegex("overwrittenNameToOverwrite")
.build("nameToOverwrite"));
- ValidationModel baseValidationModel = modelBuilder.build("base");
+ ValidationModel baseValidationModel = modelBuilder.build("base", "some source");
modelBuilder = new ValidationModelBuilder();
modelBuilder.resourceProperty(propertyBuilder.nameRegex("originalNameToOverwrite").build("nameToOverwrite"));
modelBuilder.childResource(childResourceBuilder.nameRegex("originalNameToOverwrite").build("nameToOverwrite"));
@@ -75,7 +74,7 @@ public class MergedValidationModelTest {
"nameNotOverwritten"));
modelBuilder.childResource(childResourceBuilder.nameRegex("originalNameNotOverwritten").build(
"nameNotOverwritten"));
- ValidationModel mergedModel = new MergedValidationModel(baseValidationModel, modelBuilder.build("superType"));
+ ValidationModel mergedModel = new MergedValidationModel(baseValidationModel, modelBuilder.build("superType", "some source"));
Assert.assertThat(mergedModel.getResourceProperties(), Matchers.containsInAnyOrder(
new ResourcePropertyNameRegexMatcher("overwrittenNameToOverwrite"),
new ResourcePropertyNameRegexMatcher("originalNameNotOverwritten")));
@@ -85,63 +84,9 @@ public class MergedValidationModelTest {
@Test
public void testValidatedResourceTypes() {
- ValidationModel mergedModel = new MergedValidationModel(modelBuilder.build("base"),
- modelBuilder.build("superType"));
+ ValidationModel mergedModel = new MergedValidationModel(modelBuilder.build("base", "some source"),
+ modelBuilder.build("superType", "some source"));
Assert.assertThat(mergedModel.getValidatedResourceType(), Matchers.equalTo("base"));
}
- /**
- * Custom Hamcrest matcher which matches Resource Properties based on the equality only on their namePatterns.
- */
- private static final class ResourcePropertyNameRegexMatcher extends TypeSafeMatcher<ResourceProperty> {
-
- private final String expectedNameRegex;
-
- public ResourcePropertyNameRegexMatcher(String nameRegex) {
- expectedNameRegex = nameRegex;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("ResourceProperty with namePattern=" + expectedNameRegex);
- }
-
- @Override
- protected boolean matchesSafely(ResourceProperty resourceProperty) {
- Pattern namePattern = resourceProperty.getNamePattern();
- if (namePattern == null) {
- return false;
- } else {
- return expectedNameRegex.equals(namePattern.toString());
- }
- }
-
- }
-
- /**
- * Custom Hamcrest matcher which matches ChildResource based on the equality only on their namePatterns.
- */
- private static final class ChildResourceNameRegexMatcher extends TypeSafeMatcher<ChildResource> {
-
- private final String expectedNameRegex;
-
- public ChildResourceNameRegexMatcher(String nameRegex) {
- expectedNameRegex = nameRegex;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("ChildResource with namePattern=" + expectedNameRegex);
- }
-
- @Override
- protected boolean matchesSafely(ChildResource childResource) {
- Pattern namePattern = childResource.getNamePattern();
- if (namePattern == null) {
- return false;
- } else {
- return expectedNameRegex.equals(namePattern.toString());
- }
- }
- }
}
Modified: sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java?rev=1785131&r1=1785130&r2=1785131&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java (original)
+++ sling/trunk/bundles/extensions/validation/core/src/test/java/org/apache/sling/validation/impl/resourcemodel/ResourceValidationModelProviderImplTest.java Thu Mar 2 13:27:50 2017
@@ -222,9 +222,10 @@ public class ResourceValidationModelProv
@Test
public void testGetValidationModels() throws Exception {
// build two models manually (which are identical except for the applicable path)
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ResourcePropertyBuilder resourcePropertyBuilder = new ResourcePropertyBuilder();
+ ValidationModel model1 = modelBuilder.resourceProperty(resourcePropertyBuilder.build("property1")).build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
modelBuilder.setApplicablePath("/content/site2");
- ValidationModel model2 = modelBuilder.build("sling/validation/test");
+ ValidationModel model2 = modelBuilder.build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel2");
// build models in JCR
createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
@@ -238,7 +239,7 @@ public class ResourceValidationModelProv
@Test
public void testGetValidationModelsOutsideSearchPath() throws Exception {
// build two models manually (which are identical except for the applicable path)
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ValidationModel model1 = modelBuilder.build("sling/validation/test", "some source");
Resource contentValidatorsRoot = ResourceUtil.getOrCreateResource(rr, "/content",
(Map<String, Object>) null, "sling:Folder", true);
@@ -263,7 +264,7 @@ public class ResourceValidationModelProv
ResourceProperty childproperty = resourcePropertyBuilder.build("child1property");
modelBuilder.childResource(new ChildResourceImpl("child1", null, true,
Collections.singletonList(childproperty), Collections.<ChildResource> emptyList()));
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ValidationModel model1 = modelBuilder.build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
// build models in JCR
createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
@@ -276,11 +277,11 @@ public class ResourceValidationModelProv
@Test
public void testGetValidationModelsWithOverlay() throws Exception {
// create two models manually (which are identical except for the applicable path)
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ValidationModel model1 = modelBuilder.build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
modelBuilder.setApplicablePath("/content/site2");
- ValidationModel model2 = modelBuilder.build("sling/validation/test");
+ ValidationModel model2 = modelBuilder.build("sling/validation/test", appsValidatorsRoot.getPath() + "/testValidationModel1");
- // create two models in the JCR: one in libs and one in apps (distinguishable via applicablePath)
+ // create two models: one in libs and one in apps (distinguishable via applicablePath)
createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
createValidationModelResource(rr, appsValidatorsRoot.getPath(), "testValidationModel1", model2);
@@ -292,26 +293,45 @@ public class ResourceValidationModelProv
@Test(expected = IllegalStateException.class)
public void testGetValidationModelsWithInvalidValidator() throws Exception {
// create one default model
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ValidationModel model1 = modelBuilder.build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
// clear validator map to make the referenced validator unknown
validatorMap.clear();
modelProvider.getModels("sling/validation/test", validatorMap);
}
-
+
@Test(expected = IllegalStateException.class)
public void testGetValidationModelsWithMissingChildrenAndProperties() throws Exception {
// create a model with neither children nor properties
modelBuilder = new ValidationModelBuilder();
modelBuilder.addApplicablePath("content/site1");
- ValidationModel model1 = modelBuilder.build("sling/validation/test");
+ ValidationModel model1 = modelBuilder.build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
modelProvider.getModels("sling/validation/test", validatorMap);
}
+ @Test
+ public void testCachingOfGetValidationModels() throws Exception {
+ // build one model
+ ResourcePropertyBuilder resourcePropertyBuilder = new ResourcePropertyBuilder();
+ ValidationModel model1 = modelBuilder.resourceProperty(resourcePropertyBuilder.build("property1")).build("sling/validation/test", libsValidatorsRoot.getPath() + "/testValidationModel1");
+ modelBuilder.setApplicablePath("/content/site2");
+
+ // build models in JCR
+ createValidationModelResource(rr, libsValidatorsRoot.getPath(), "testValidationModel1", model1);
+
+ // check that both models are returned
+ Collection<ValidationModel> models = modelProvider.getModels("sling/validation/test", validatorMap);
+ Assert.assertThat(models, Matchers.containsInAnyOrder(model1));
+
+ // the 2nd time the same instance should be returned
+ Collection<ValidationModel> models2 = modelProvider.getModels("sling/validation/test", validatorMap);
+ Assert.assertEquals("Due to caching both models should be actually the same instance", System.identityHashCode(models), System.identityHashCode(models2));
+ }
+
private Resource createValidationModelResource(ResourceResolver rr, String root, String name, ValidationModel model)
throws Exception {
Map<String, Object> modelProperties = new HashMap<String, Object>();