jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From k...@apache.org
Subject svn commit: r1874872 [1/2] - in /jackrabbit/commons/filevault/trunk/vault-validation/src: main/java/org/apache/jackrabbit/vault/validation/ main/java/org/apache/jackrabbit/vault/validation/impl/util/ main/java/org/apache/jackrabbit/vault/validation/spi...
Date Fri, 06 Mar 2020 07:27:44 GMT
Author: kwin
Date: Fri Mar  6 07:27:44 2020
New Revision: 1874872

URL: http://svn.apache.org/viewvc?rev=1874872&view=rev
Log:
JCRVLT-415 fix false-positive for jackrabbit-emptyelements validator

Allow to validate folders as well
Improve SPI to always pass filePath and basePath
improve PackageTypeValidator to accept also parent folders of OSGi
bundles/configs and subpackages for container packages

Added:
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodeContext.java
      - copied, changed from r1874779, jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/NodeContextImpl.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/NodeContextNodePathMatcher.java
      - copied, changed from r1874779, jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java
Modified:
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutor.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutorFactory.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationViolation.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/impl/util/DocumentViewXmlContentHandler.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/DocumentViewXmlValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericJcrDataValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericMetaInfDataValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/JcrPathValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/MetaInfPathValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodePathValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/ValidationMessage.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/AdvancedFilterValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidator.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorFactory.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/DocumentViewParserValidatorTest.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationExecutorTest.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/ValidationViolationTest.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidatorTest.java
    jackrabbit/commons/filevault/trunk/vault-validation/src/test/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorTest.java

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutor.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutor.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutor.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutor.java Fri Mar  6 07:27:44 2020
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.function.BiPredicate;
 import java.util.stream.Collectors;
 
 import org.apache.commons.io.FilenameUtils;
@@ -48,6 +47,7 @@ import org.apache.jackrabbit.vault.valid
 import org.apache.jackrabbit.vault.validation.spi.impl.AdvancedFilterValidator;
 import org.apache.jackrabbit.vault.validation.spi.impl.AdvancedPropertiesValidator;
 import org.apache.jackrabbit.vault.validation.spi.impl.DocumentViewParserValidator;
+import org.apache.jackrabbit.vault.validation.spi.util.NodeContextImpl;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -59,7 +59,7 @@ import org.slf4j.LoggerFactory;
  * This class is thread-safe (i.e. methods can be used from different threads on the same instance). 
  * @see ValidationExecutorFactory
  */
-public class ValidationExecutor {
+public final class ValidationExecutor {
 
     private final Map<String, DocumentViewXmlValidator> documentViewXmlValidators;
     private final Map<String, NodePathValidator> nodePathValidators;
@@ -69,7 +69,7 @@ public class ValidationExecutor {
     private final Map<String, JcrPathValidator> jcrPathValidators;
     private final Map<String, FilterValidator> filterValidators;
     private final Map<String, PropertiesValidator> propertiesValidators;
-    private final Map<String, Validator> validatorsById;
+    private final @NotNull Map<String, Validator> validatorsById;
 
     /**
      * the default logger
@@ -206,7 +206,7 @@ public class ValidationExecutor {
             for (Map.Entry<String, NodePathValidator> entry : nodePathValidators.entrySet()) {
                 enrichedMessages.add(new ValidationViolation(entry.getKey(), ValidationMessageSeverity.DEBUG, "Validate..."));
                 try {
-                    Collection<ValidationMessage> messages = entry.getValue().validate(nodePathAndLineNumber.getKey());
+                    Collection<ValidationMessage> messages = entry.getValue().validate(new NodeContextImpl(nodePathAndLineNumber.getKey(), filePath, basePath));
                     if (messages != null && !messages.isEmpty()) {
                         enrichedMessages.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, basePath, nodePathAndLineNumber.getKey(),
                                 nodePathAndLineNumber.getValue().intValue(), 0));
@@ -219,10 +219,10 @@ public class ValidationExecutor {
         return enrichedMessages;
     }
 
-    private Collection<ValidationViolation> validateGenericMetaInfData(@Nullable InputStream input, @NotNull Path filePath, Path basePath) throws IOException {
+    private Collection<ValidationViolation> validateGenericMetaInfData(@Nullable InputStream input, @NotNull Path filePath, @NotNull Path basePath) throws IOException {
         Collection<ValidationViolation> enrichedMessages = new LinkedList<>();
         for (Map.Entry<String, MetaInfPathValidator> entry : metaInfPathValidators.entrySet()) {
-            Collection<ValidationMessage> messages = entry.getValue().validateMetaInfPath(filePath, input == null);
+            Collection<ValidationMessage> messages = entry.getValue().validateMetaInfPath(filePath, basePath, input == null);
             if (messages != null && !messages.isEmpty()) {
                 enrichedMessages.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, basePath, null, 0, 0));
             }
@@ -234,16 +234,17 @@ public class ValidationExecutor {
                 for (Map.Entry<String, GenericMetaInfDataValidator> entry : genericMetaInfDataValidators.entrySet()) {
                     try {
                         GenericMetaInfDataValidator validator = entry.getValue();
-                        if (validator.shouldValidateMetaInfData(filePath)) {
+                        if (validator.shouldValidateMetaInfData(filePath, basePath)) {
                             if (resettableInputStream == null) {
-                                if (isAnotherValidatorFulfillingPathPredicate(genericMetaInfDataValidators.values(), GenericMetaInfDataValidator::shouldValidateMetaInfData, validator, filePath)) {
+                                boolean isAnotherValidatorInterested = genericMetaInfDataValidators.values().stream().filter(t-> !t.equals(validator)).anyMatch(x -> x.shouldValidateMetaInfData(filePath, basePath));
+                                if (isAnotherValidatorInterested) {
                                     currentInput = resettableInputStream = new ResettableInputStream(input);
                                 }
                             } else {
                                 resettableInputStream.reset();
                             }
                             enrichedMessages.add(new ValidationViolation(entry.getKey(), ValidationMessageSeverity.DEBUG, "Validate..."));
-                            Collection<ValidationMessage> messages = validator.validateMetaInfData(currentInput, filePath);
+                            Collection<ValidationMessage> messages = validator.validateMetaInfData(currentInput, filePath, basePath);
                             if (messages != null && !messages.isEmpty()) {
                                 enrichedMessages.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, basePath, null, 0, 0));
                             }
@@ -263,11 +264,11 @@ public class ValidationExecutor {
         return enrichedMessages;
     }
 
-    private Collection<ValidationViolation> validateGenericJcrData(@Nullable InputStream input, @NotNull Path filePath, Path basePath) throws IOException {
+    private Collection<ValidationViolation> validateGenericJcrData(@Nullable InputStream input, @NotNull Path filePath, @NotNull Path basePath) throws IOException {
         Map<String, Integer> nodePathsAndLineNumbers = new HashMap<>();
         Collection<ValidationViolation> enrichedMessages = new LinkedList<>();
         for (Map.Entry<String, JcrPathValidator> entry : jcrPathValidators.entrySet()) {
-            Collection<ValidationMessage> messages = entry.getValue().validateJcrPath(filePath, input == null);
+            Collection<ValidationMessage> messages = entry.getValue().validateJcrPath(filePath, basePath, input == null);
             if (messages != null && !messages.isEmpty()) {
                 enrichedMessages.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, basePath, null, 0, 0));
             }
@@ -280,16 +281,17 @@ public class ValidationExecutor {
                 for (Map.Entry<String, GenericJcrDataValidator> entry : genericJcrDataValidators.entrySet()) {
                     try {
                         GenericJcrDataValidator validator = entry.getValue();
-                        if (validator.shouldValidateJcrData(filePath)) {
+                        if (validator.shouldValidateJcrData(filePath, basePath)) {
                             if (resettableInputStream == null) {
-                                if (isAnotherValidatorFulfillingPathPredicate(genericJcrDataValidators.values(), GenericJcrDataValidator::shouldValidateJcrData, validator, filePath)) {
+                                boolean isAnotherValidatorInterested = genericJcrDataValidators.values().stream().filter(t-> !t.equals(validator)).anyMatch(x -> x.shouldValidateJcrData(filePath, basePath));
+                                if (isAnotherValidatorInterested) {
                                     currentInput = resettableInputStream = new ResettableInputStream(input);
                                 }
                             } else {
                                 resettableInputStream.reset();
                             }
                             enrichedMessages.add(new ValidationViolation(entry.getKey(), ValidationMessageSeverity.DEBUG, "Validate..."));
-                            Collection<ValidationMessage> messages = validator.validateJcrData(currentInput, filePath, nodePathsAndLineNumbers);
+                            Collection<ValidationMessage> messages = validator.validateJcrData(currentInput, filePath, basePath, nodePathsAndLineNumbers);
                             if (messages != null && !messages.isEmpty()) {
                                 enrichedMessages.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, basePath, null, 0, 0));
                             }
@@ -332,10 +334,6 @@ public class ValidationExecutor {
         return PlatformNameFormat.getRepositoryPath(platformPath, true);
     }
 
-    private static <T extends Validator> boolean isAnotherValidatorFulfillingPathPredicate(Collection<T> validators, BiPredicate<T,Path> predicate, T currentValidator, Path filePath) {
-        return validators.stream().filter(t -> !t.equals(currentValidator)).anyMatch(x -> predicate.test(x, filePath));
-    }
-
     static <T> Map<String, T> filterValidatorsByClass(Map<String, Validator> allValidators, Class<T> type) {
         return allValidators.entrySet().stream()
                 .filter(x -> type.isInstance(x.getValue()))

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutorFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutorFactory.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutorFactory.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationExecutorFactory.java Fri Mar  6 07:27:44 2020
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Creates {@link ValidationExecutor}s. Holds a number of {@link ValidatorFactory} instances.
  */
-public class ValidationExecutorFactory {
+public final class ValidationExecutorFactory {
 
     /** All registered ValidatorFactories in the correct order (sorted by their ranking) */
     final List<ValidatorFactory> validatorFactories;

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationViolation.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationViolation.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationViolation.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/ValidationViolation.java Fri Mar  6 07:27:44 2020
@@ -20,21 +20,19 @@ import java.nio.file.Path;
 import java.util.Collection;
 import java.util.LinkedList;
 
-import org.apache.jackrabbit.vault.validation.spi.ValidatorFactory;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessage;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
+import org.apache.jackrabbit.vault.validation.spi.ValidatorFactory;
+import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * A ValidationViolation is a {@link ValidationMessage} enriched with additional meta information like
- * validator id, file path and node path.
+ * validator id
  */
-public class ValidationViolation extends ValidationMessage {
+public final class ValidationViolation extends ValidationMessage {
 
     private final String validatorId; // may only be null if message was not bound to a validator
-    private final Path filePath; // may be null
-    private final Path basePath; // may be null
-    private final String nodePath; // may be null
 
     public static final Collection<ValidationViolation> wrapMessages(String validatorId, Collection<? extends ValidationMessage> messages, Path filePath, Path basePath, String nodePath, int line, int column) {
         Collection<ValidationViolation> violations = new LinkedList<>();
@@ -51,9 +49,9 @@ public class ValidationViolation extends
             // take parameters from underlying violation and only overwrite if not set in delegate
             return new ValidationViolation(delegate.validatorId != null ? delegate.validatorId : validatorId, 
                     delegate,
-                    delegate.filePath != null ? delegate.filePath : filePath,
-                    delegate.basePath != null ? delegate.basePath : basePath,
-                    delegate.nodePath != null ? delegate.nodePath : nodePath, 
+                    delegate.getFilePath()!= null ? delegate.getFilePath() : filePath,
+                    delegate.getBasePath() != null ? delegate.getBasePath() : basePath,
+                    delegate.getNodePath() != null ? delegate.getNodePath() : nodePath, 
                     delegate.getLine() != 0 ? delegate.getLine() : line,
                     delegate.getColumn() != 0 ? delegate.getColumn() : column,
                     delegate.getThrowable());
@@ -64,31 +62,28 @@ public class ValidationViolation extends
 
     ValidationViolation(String validatorId, ValidationMessage message, Path filePath, Path basePath, String nodePath, int line, int column, Throwable t) {
         // potentially overwrite line, column and throwable from wrapped message (but only if not yet set there)
-        super(message.getSeverity(), message.getMessage(), message.getLine() != 0 ?  message.getLine() : line, message.getColumn() != 0 ? message.getColumn() : column, message.getThrowable() != null ? message.getThrowable() : t);
+        super(message.getSeverity(), message.getMessage(), message.getNodePath() != null ? message.getNodePath() : nodePath, message.getFilePath() != null ? message.getFilePath() : filePath, message.getBasePath() != null ? message.getBasePath() : basePath, message.getLine() != 0 ?  message.getLine() : line, message.getColumn() != 0 ? message.getColumn() : column, message.getThrowable() != null ? message.getThrowable() : t);
         
         this.validatorId = validatorId;
-        this.filePath = filePath;
-        this.basePath = basePath;
-        this.nodePath = nodePath;
     }
 
     private ValidationViolation(String validatorId, ValidationMessage message) {
         this(validatorId, message, null, null, null, 0, 0, null);
     }
 
-    public ValidationViolation(String validatorId, ValidationMessageSeverity severity, String message) {
+    public ValidationViolation(String validatorId, @NotNull ValidationMessageSeverity severity, @NotNull String message) {
         this(validatorId, new ValidationMessage(severity, message));
     }
 
-    public ValidationViolation(ValidationMessageSeverity severity, String message) {
+    public ValidationViolation(@NotNull ValidationMessageSeverity severity, @NotNull String message) {
         this(null, new ValidationMessage(severity, message));
     }
 
-    public ValidationViolation(ValidationMessageSeverity severity, String message, Path filePath, Path basePath, String nodePath, int line, int column, Throwable t) {
+    public ValidationViolation(@NotNull ValidationMessageSeverity severity, @NotNull String message, Path filePath, Path basePath, String nodePath, int line, int column, Throwable t) {
         this(null, new ValidationMessage(severity, message), filePath, basePath, nodePath, line, column, t);
     }
 
-    public ValidationViolation(String validatorId, ValidationMessageSeverity severity, String message, Path filePath, Path basePath, String nodePath, int line, int column, Throwable t) {
+    public ValidationViolation(String validatorId, @NotNull ValidationMessageSeverity severity, @NotNull String message, Path filePath, Path basePath, String nodePath, int line, int column, Throwable t) {
         this(validatorId, new ValidationMessage(severity, message), filePath, basePath, nodePath, line, column, t);
     }
 
@@ -96,19 +91,12 @@ public class ValidationViolation extends
      * Returns the file path bound to this message.
      * @return the absolute file path or {@code null} if the message does not belong to a file
      */
-    public @Nullable Path getFilePath() {
-        if (basePath != null && filePath != null) {
-            return basePath.resolve(filePath);
+    public @Nullable Path getAbsoluteFilePath() {
+        Path basePath = getBasePath();
+        if (basePath != null && getFilePath() != null) {
+            return basePath.resolve(getFilePath());
         }
-        return filePath;
-    }
-
-    /**
-     * Returns the node path bound to this message.
-     * @return the node path or {@code null} if the message does not belong to a specific node
-     */
-    public @Nullable String getNodePath() {
-        return nodePath;
+        return getFilePath();
     }
 
     /**
@@ -119,12 +107,11 @@ public class ValidationViolation extends
         return validatorId;
     }
 
+    
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = super.hashCode();
-        result = prime * result + ((filePath == null) ? 0 : filePath.hashCode());
-        result = prime * result + ((nodePath == null) ? 0 : nodePath.hashCode());
         result = prime * result + ((validatorId == null) ? 0 : validatorId.hashCode());
         return result;
     }
@@ -138,16 +125,6 @@ public class ValidationViolation extends
         if (getClass() != obj.getClass())
             return false;
         ValidationViolation other = (ValidationViolation) obj;
-        if (filePath == null) {
-            if (other.filePath != null)
-                return false;
-        } else if (!filePath.equals(other.filePath))
-            return false;
-        if (nodePath == null) {
-            if (other.nodePath != null)
-                return false;
-        } else if (!nodePath.equals(other.nodePath))
-            return false;
         if (validatorId == null) {
             if (other.validatorId != null)
                 return false;
@@ -158,8 +135,8 @@ public class ValidationViolation extends
 
     @Override
     public String toString() {
-        return "ValidationViolation [" + (filePath != null ? "filePath=" + filePath + ", " : "")
-                + (nodePath != null ? "nodePath=" + nodePath + ", " : "") + (validatorId != null ? "validatorId=" + validatorId + ", " : "")
+        return "ValidationViolation [" 
+                + (validatorId != null ? "validatorId=" + validatorId + ", " : "")
                 + "super=" + super.toString() + "]";
     }
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/impl/util/DocumentViewXmlContentHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/impl/util/DocumentViewXmlContentHandler.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/impl/util/DocumentViewXmlContentHandler.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/impl/util/DocumentViewXmlContentHandler.java Fri Mar  6 07:27:44 2020
@@ -26,7 +26,6 @@ import java.util.List;
 import java.util.Map;
 
 import javax.jcr.NamespaceException;
-import javax.xml.namespace.QName;
 
 import org.apache.jackrabbit.spi.Name;
 import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
@@ -42,6 +41,7 @@ import org.apache.jackrabbit.vault.valid
 import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessage;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
+import org.apache.jackrabbit.vault.validation.spi.util.NodeContextImpl;
 import org.jetbrains.annotations.NotNull;
 import org.xml.sax.Attributes;
 import org.xml.sax.Locator;
@@ -51,10 +51,11 @@ import org.xml.sax.helpers.DefaultHandle
 /** TODO: reuse more logic from DocViewSAXImporter (https://issues.apache.org/jira/browse/JCRVLT-357) */
 public class DocumentViewXmlContentHandler extends DefaultHandler implements NamespaceResolver {
 
-    private final @NotNull Map<String, Integer> nodePathsAndLineNumbers;
+    private final @NotNull Map<@NotNull String, @NotNull Integer> nodePathsAndLineNumbers;
     private String rootNodeName;
     private String rootNodeParentPath; // must not end with "/"
-    private final Path filePath;
+    private final @NotNull Path filePath;
+    private final @NotNull Path basePath;
     private Locator locator;
     private Deque<String> elementNameStack;
     private Deque<DocViewNode> nodeStack;
@@ -77,11 +78,13 @@ public class DocumentViewXmlContentHandl
     /**
      * 
      * @param filePath the relative file to the docview file (relative to the jcr_root folder)
+     * @param basePath the absolute file path of the the jcr_root folder (to which {@code filePath} is relative)
      * @param rootNodePath the node path of the root node covered by this docview file
      * @param documentViewXmlValidators the validators to call for this docview file
      */
-    public DocumentViewXmlContentHandler(Path filePath, String rootNodePath, Map<String, DocumentViewXmlValidator> documentViewXmlValidators) {
+    public DocumentViewXmlContentHandler(@NotNull Path filePath, @NotNull Path basePath, String rootNodePath, Map<String, DocumentViewXmlValidator> documentViewXmlValidators) {
         this.filePath = filePath;
+        this.basePath = basePath;
         if (rootNodePath.equals("/")) {
             rootNodePath = "";
         }
@@ -193,7 +196,7 @@ public class DocumentViewXmlContentHandl
             violations.add(new ValidationViolation(ValidationMessageSeverity.DEBUG, "Validate node '" + node + "' start"));
             for (Map.Entry<String, DocumentViewXmlValidator> entry : validators.entrySet()) {
                 try {
-                    Collection<ValidationMessage> messages = entry.getValue().validate(node, nodePath.toString(), filePath, elementNameStack.size() <= 1);
+                    Collection<ValidationMessage> messages = entry.getValue().validate(node, new NodeContextImpl(nodePath.toString(), filePath, basePath), elementNameStack.size() <= 1);
                     if (messages != null && !messages.isEmpty()) {
                         violations.addAll(ValidationViolation.wrapMessages(entry.getKey(), messages, filePath, null, nodePath.toString(),
                                 locator.getLineNumber(), locator.getColumnNumber()));
@@ -211,7 +214,7 @@ public class DocumentViewXmlContentHandl
         }
     }
 
-    private DocViewNode getDocViewNode(Name name, String label, Attributes attributes) {
+    private @NotNull DocViewNode getDocViewNode(Name name, String label, Attributes attributes) {
         Map<String, DocViewProperty> propertyMap = new HashMap<>();
         
         String uuid = null;

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java Fri Mar  6 07:27:44 2020
@@ -17,7 +17,7 @@
 /**
  * The FileVault validation framework API. Provides classes to execute validations on FileVault packages.
  */
-@Version("1.0.1")
+@Version("2.0.0")
 package org.apache.jackrabbit.vault.validation;
 
 import org.osgi.annotation.versioning.Version;

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/DocumentViewXmlValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/DocumentViewXmlValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/DocumentViewXmlValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/DocumentViewXmlValidator.java Fri Mar  6 07:27:44 2020
@@ -49,6 +49,27 @@ public interface DocumentViewXmlValidato
      * @param filePath the relative file path of the docview file containing this node
      * @param isRoot {@code true} in case this is the root node of the docview file otherwise {@code false}
      * @return validation messages or {@code null}
+     * @deprecated Use {@link #validate(DocViewNode, NodeContext, boolean)} instead
      */
-    @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull String nodePath, @NotNull Path filePath, boolean isRoot);
+    @Deprecated
+    default @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull String nodePath, @NotNull Path filePath, boolean isRoot) {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Called for the beginning of each new JCR document view node.
+     * Deserialization of the node information was already done when this method is called!
+     * The node and attribute names have the string representation outlined in {@link Name} (i.e. including the namespace uri in the format <code>{namespaceURI}localPart</code>).
+     * This is also referred to as <a href="https://docs.adobe.com/docs/en/spec/jcr/2.0/3_Repository_Model.html#3.2.5.1%20Expanded%20Form">JCR name expanded form</a>.
+     * To construct such names either use {@link NameUtil} or use the constants from {@link NameConstants}.
+     * 
+     * The node's label refers to the XML element name specifying the node. There shouldn't be any checks derived from it, but only from the expanded name.
+     * @param node the node which should be validated
+     * @param nodeContext the information about the node context (like path)
+     * @param isRoot {@code true} in case this is the root node of the docview file otherwise {@code false}
+     * @return validation messages or {@code null}
+     */
+    default @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull NodeContext nodeContext, boolean isRoot) {
+        return validate(node, nodeContext.getNodePath(), nodeContext.getFilePath(), isRoot);
+    }
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericJcrDataValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericJcrDataValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericJcrDataValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericJcrDataValidator.java Fri Mar  6 07:27:44 2020
@@ -23,6 +23,7 @@ import java.util.Collection;
 import java.util.Map;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.osgi.annotation.versioning.ProviderType;
 
 /**
@@ -42,14 +43,47 @@ public interface GenericJcrDataValidator
      * @param nodePathsAndLineNumbers a map which should be filled with all node path and their according line numbers if nodes are detected in the given input
      * @return a collection of validation messages or {@code null}
      * @throws IOException in case the input stream could not be accessed
+     * @deprecated Use {@link #validateJcrData(InputStream, Path, Path, Map)} instead.
      */
-    Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException;
+    @Deprecated
+    default @Nullable Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException {
+        throw new UnsupportedOperationException();
+    }
 
     /**
      * Called for each file below jcr_root.
+     * Only called in case {@link #shouldValidateJcrData(Path)} returned {@code true} for the given path.
+     * 
+     * @param input the input stream of the file which ends up below jcr_root in the package located at filePath
+     * @param filePath file path relative to the jcr_root directory (i.e. does not start with {@code jcr_root})
+     * @param basePath the absolute file path of jcr_root (base for {@code filePath)})
+     * @param nodePathsAndLineNumbers a map which should be filled with all node path and their according line numbers if nodes are detected in the given input
+     * @return a collection of validation messages or {@code null}
+     * @throws IOException in case the input stream could not be accessed
+     */
+    default @Nullable Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Path basePath, @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException {
+        return validateJcrData(input, filePath, nodePathsAndLineNumbers);
+    }
+
+    /**
+     * Called for each file below jcr_root.
+     * 
+     * @param filePath file path relative to the jcr_root directory (i.e. does not start with {@code jcr_root})
+     * @return {@code true} in case the file should be validated, otherwise {@code false}
+     */
+    @Deprecated
+    default boolean shouldValidateJcrData(@NotNull Path filePath) {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Called for each file below jcr_root.
      * 
      * @param filePath file path relative to the jcr_root directory (i.e. does not start with {@code jcr_root})
+     * @param basePath the absolute file path of jcr_root (base for {@code filePath)})
      * @return {@code true} in case the file should be validated, otherwise {@code false}
      */
-    boolean shouldValidateJcrData(@NotNull Path filePath);
+    default boolean shouldValidateJcrData(@NotNull Path filePath, @NotNull Path basePath) {
+        return shouldValidateJcrData(filePath);
+    }
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericMetaInfDataValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericMetaInfDataValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericMetaInfDataValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/GenericMetaInfDataValidator.java Fri Mar  6 07:27:44 2020
@@ -18,8 +18,10 @@ package org.apache.jackrabbit.vault.vali
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.channels.ShutdownChannelGroupException;
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.Map;
 
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -37,22 +39,53 @@ public interface GenericMetaInfDataValid
 
     /**
      * Called for each file below META-INF.
-     * Only called in case {@link #shouldValidateMetaInfData(Path)} returned true for the given path.
+     * Only called in case {@link #shouldValidateMetaInfData(Path, Path)} returned {@code true} for the given path.
      *
      * @param input the input stream of the META-INF file located at filePath
      * @param filePath file path relative to the META-INF directory (i.e. does not start with {@code META-INF})
      * @return a collection of validation messages or {@code null}
      * @throws IOException in case the input stream could not be accessed
+     * @deprecated Use {@link #validateMetaInfData(InputStream, Path, Path)} instead
      */
-    @Nullable Collection<ValidationMessage> validateMetaInfData(@NotNull InputStream input, @NotNull Path filePath) throws IOException;
+    @Deprecated
+    default @Nullable Collection<ValidationMessage> validateMetaInfData(@NotNull InputStream input, @NotNull Path filePath) throws IOException {
+        throw new UnsupportedOperationException();
+    }
 
     /**
      * Called for each file below META-INF.
+     * Only called in case {@link #shouldValidateMetaInfData(Path, Path)} returned {@code true} for the given path.
+     * 
+     * @param input the input stream of the file which ends up below jcr_root in the package located at filePath
+     * @param filePath file path relative to the META-INF directory (i.e. does not start with {@code META-INF})
+     * @param basePath the absolute file path of the META-INF directory (base for {@code filePath)})
+     * @return a collection of validation messages or {@code null}
+     * @throws IOException in case the input stream could not be accessed
+     */
+    default @Nullable Collection<ValidationMessage> validateMetaInfData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Path basePath) throws IOException {
+        return validateMetaInfData(input, filePath);
+    }
+    
+    /**
+     * Called for each file below META-INF.
      * 
      * @param filePath file path relative to the META-INF directory (i.e. does not start with {@code META-INF})
      * @return {@code true} in case the file should be validated, otherwise {@code false}
      */
-    boolean shouldValidateMetaInfData(@NotNull Path filePath);
-
+    @Deprecated
+    default boolean shouldValidateMetaInfData(@NotNull Path filePath) {
+        throw new UnsupportedOperationException();
+    }
     
+    /**
+     * Called for each file below META-INF.
+     * 
+     * @param filePath file path relative to the META-INF directory (i.e. does not start with {@code META-INF})
+     * @param basePath the absolute file path of the META-INF directory (base for {@code filePath)})
+     * @return {@code true} in case the file should be validated, otherwise {@code false}
+     */
+    default boolean shouldValidateMetaInfData(@NotNull Path filePath, @NotNull Path basePath) {
+        return shouldValidateMetaInfData(filePath);
+    }
+
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/JcrPathValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/JcrPathValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/JcrPathValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/JcrPathValidator.java Fri Mar  6 07:27:44 2020
@@ -35,18 +35,23 @@ public interface JcrPathValidator extend
      * 
      * @param filePath the relative file/folder path to the jcr_root directory
      * @return validation messages or {@code null}
-     * @deprecated Use {@link #validateJcrPath(Path, boolean)} instead.
+     * @deprecated Use {@link #validateJcrPath(Path, Path, boolean)} instead.
      */
     @Deprecated 
-    default @Nullable Collection<ValidationMessage> validateJcrPath(@NotNull Path filePath) { return null; };
-    
+    default @Nullable Collection<ValidationMessage> validateJcrPath(@NotNull Path filePath) { 
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Called for each file/folder below jcr_root.
      * 
-     * @param filePath the relative file/folder path to the jcr_root directory
+     * @param filePath the relative file/folder path to the jcr_root directory (given in {@code basePath})
+     * @param basePath the absolute path to the jcr_root directory to which {@code filePath} is relative
      * @param isFolder {@code true} in case it is a folder, otherwise {@code false}
      * @return validation messages or {@code null}
      */
-    default @Nullable Collection<ValidationMessage> validateJcrPath(@NotNull Path filePath, boolean isFolder) { return validateJcrPath(filePath); }
+    default @Nullable Collection<ValidationMessage> validateJcrPath(@NotNull Path filePath, @NotNull Path basePath, boolean isFolder) { 
+        return validateJcrPath(filePath); 
+    }
    
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/MetaInfPathValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/MetaInfPathValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/MetaInfPathValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/MetaInfPathValidator.java Fri Mar  6 07:27:44 2020
@@ -35,19 +35,22 @@ public interface MetaInfPathValidator ex
      * 
      * @param filePath the relative file/folder path to the META-INF directory
      * @return validation messages or {@code null}
-     * @deprecated Use {@link #validateMetaInfPath(Path, boolean)} instead.
+     * @deprecated Use {@link #validateMetaInfPath(Path, Path, boolean)} instead.
      */
     @Deprecated 
-    default @Nullable Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath) { return null; };
+    default @Nullable Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath) { 
+        throw new UnsupportedOperationException();
+    }
     
     /**
      * Called for each file/folder below META-INF.
      * 
-     * @param filePath the relative file/folder path to the META-INF directory
+     * @param filePath the relative file/folder path to the META-INF directory (given in {@code basePath})
+     * @param basePath the absolute path to the META-INF directory to which {@code filePath} is relative
      * @param isFolder {@code true} in case it is a folder, otherwise {@code false}
      * @return validation messages or {@code null}
      */
-    default @Nullable Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath, boolean isFolder) { return validateMetaInfPath(filePath); }
+    default @Nullable Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath, @NotNull Path basePath, boolean isFolder) { return validateMetaInfPath(filePath); }
    
    
 }

Copied: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodeContext.java (from r1874779, jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java)
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodeContext.java?p2=jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodeContext.java&p1=jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java&r1=1874779&r2=1874872&rev=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/package-info.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodeContext.java Fri Mar  6 07:27:44 2020
@@ -14,10 +14,37 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.jackrabbit.vault.validation.spi;
+
+import java.nio.file.Path;
+
+import org.jetbrains.annotations.NotNull;
+
 /**
- * The FileVault validation framework API. Provides classes to execute validations on FileVault packages.
+ * Meta information about a node:
+ * <ul>
+ * <li>jcr path</li>
+ * <li>file path of the file which defined the node</li>
+ * </ul>
  */
-@Version("1.0.1")
-package org.apache.jackrabbit.vault.validation;
+public interface NodeContext {
+
+    /**
+     * 
+     * @return the JCR node path
+     */
+    @NotNull String getNodePath();
+
+    /**
+     * 
+     * @return the file path relative to jcr_root
+     */
+    @NotNull Path getFilePath();
+
+    /**
+     * 
+     * @return the absolute file path of jcr_root (base for {@link #getFilePath()})
+     */
+    @NotNull Path getBasePath();
 
-import org.osgi.annotation.versioning.Version;
+}
\ No newline at end of file

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodePathValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodePathValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodePathValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/NodePathValidator.java Fri Mar  6 07:27:44 2020
@@ -36,7 +36,21 @@ public interface NodePathValidator exten
      * 
      * @param nodePath the absolute node path
      * @return validation messages or {@code null}
+     * @deprecated Use {@link #validate(NodeContext)} instead!
      */
-    @Nullable Collection<ValidationMessage> validate(@NotNull String nodePath);
-   
+    @Deprecated
+    default @Nullable Collection<ValidationMessage> validate(@NotNull String nodePath) { 
+        throw new UnsupportedOperationException(); 
+    }
+    
+    /**
+     * Called for each node being found in a package.
+     * Empty node elements (in DocView files) are not included as they are only used for ordering purposes.
+     * 
+     * @param nodeContext the information about the node context
+     * @return validation messages or {@code null}
+     */
+    default @Nullable Collection<ValidationMessage> validate(@NotNull NodeContext nodeContext ) {
+        return validate(nodeContext.getNodePath());
+    }
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/ValidationMessage.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/ValidationMessage.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/ValidationMessage.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/ValidationMessage.java Fri Mar  6 07:27:44 2020
@@ -16,6 +16,8 @@
  */
 package org.apache.jackrabbit.vault.validation.spi;
 
+import java.nio.file.Path;
+
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -33,6 +35,10 @@ public class ValidationMessage {
     /** the underlying exception if there was any, may be null */
     private final Throwable throwable;
     
+    private final String nodePath; // may be null
+    private final Path filePath; // may be null
+    private final Path basePath; // may be null
+    
     public ValidationMessage(@NotNull ValidationMessageSeverity severity, @NotNull String message) {
         this(severity, message, 0, 0, null);
     }
@@ -42,15 +48,28 @@ public class ValidationMessage {
     }
 
     public ValidationMessage(@NotNull ValidationMessageSeverity severity, @NotNull String message, int line, int column, Throwable throwable) {
+        this(severity, message, null, null, line, column, throwable);
+    }
+
+    public ValidationMessage(@NotNull ValidationMessageSeverity severity, @NotNull String message, @NotNull String nodePath, @NotNull Path filePath, @NotNull Path basePath, Throwable throwable) {
+        this(severity, message, nodePath, filePath, basePath, 0, 0, throwable);
+    }
+
+    public ValidationMessage(@NotNull ValidationMessageSeverity severity, @NotNull String message, Path filePath, Path basePath, int line, int column, Throwable throwable) {
+        this(severity, message, null, filePath, basePath, line, column, throwable);
+    }
+
+    public ValidationMessage(@NotNull ValidationMessageSeverity severity, @NotNull String message, String nodePath, Path filePath, Path basePath, int line, int column, Throwable throwable) {
         this.severity = severity;
         this.message = message;
         this.line = line;
         this.column = column;
         this.throwable = throwable;
+        this.filePath = filePath;
+        this.basePath = basePath;
+        this.nodePath = nodePath;
     }
     
-    
-    
     /**
      * Returns the severity of this message.
      * @return the severity of this message
@@ -91,13 +110,33 @@ public class ValidationMessage {
         return throwable;
     }
 
+    
+    public @Nullable Path getFilePath() {
+        return filePath;
+    }
+
+    public @Nullable Path getBasePath() {
+        return basePath;
+    }
+
+    /**
+     * Returns the node path bound to this message.
+     * @return the node path or {@code null} if the message does not belong to a specific node
+     */
+    public @Nullable String getNodePath() {
+        return nodePath;
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
+        result = prime * result + ((basePath == null) ? 0 : basePath.hashCode());
         result = prime * result + column;
+        result = prime * result + ((filePath == null) ? 0 : filePath.hashCode());
         result = prime * result + line;
         result = prime * result + ((message == null) ? 0 : message.hashCode());
+        result = prime * result + ((nodePath == null) ? 0 : nodePath.hashCode());
         result = prime * result + ((severity == null) ? 0 : severity.hashCode());
         return result;
     }
@@ -111,12 +150,27 @@ public class ValidationMessage {
         if (getClass() != obj.getClass())
             return false;
         ValidationMessage other = (ValidationMessage) obj;
+        if (basePath == null) {
+            if (other.basePath != null)
+                return false;
+        } else if (!basePath.equals(other.basePath))
+            return false;
         if (column != other.column)
             return false;
+        if (filePath == null) {
+            if (other.filePath != null)
+                return false;
+        } else if (!filePath.equals(other.filePath))
+            return false;
         if (line != other.line)
             return false;
         if (!message.equals(other.message))
             return false;
+        if (nodePath == null) {
+            if (other.nodePath != null)
+                return false;
+        } else if (!nodePath.equals(other.nodePath))
+            return false;
         if (severity != other.severity)
             return false;
         return true;
@@ -126,7 +180,9 @@ public class ValidationMessage {
     public String toString() {
         return "ValidationMessage [" + (severity != null ? "severity=" + severity + ", " : "")
                 + (message != null ? "message=" + message + ", " : "") + "line=" + line + ", column=" + column + ", "
-                + (throwable != null ? "throwable=" + throwable : "") + "]";
+                + (throwable != null ? "throwable=" + throwable + ", " : "") + (nodePath != null ? "nodePath=" + nodePath + ", " : "")
+                + (filePath != null ? "filePath=" + filePath + ", " : "") + (basePath != null ? "basePath=" + basePath : "") + "]";
     }
 
+
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/AdvancedFilterValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/AdvancedFilterValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/AdvancedFilterValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/AdvancedFilterValidator.java Fri Mar  6 07:27:44 2020
@@ -84,10 +84,10 @@ public final class AdvancedFilterValidat
 
     private final boolean isSubPackage;
     private final Collection<String> validRoots;
-    private final ValidationMessageSeverity defaultSeverity;
-    private final ValidationMessageSeverity severityForUncoveredAncestorNode;
-    private final ValidationMessageSeverity severityForUncoveredFilterRootAncestors;
-    private final ValidationMessageSeverity severityForOrphanedFilterEntries;
+    private final @NotNull ValidationMessageSeverity defaultSeverity;
+    private final @NotNull ValidationMessageSeverity severityForUncoveredAncestorNode;
+    private final @NotNull ValidationMessageSeverity severityForUncoveredFilterRootAncestors;
+    private final @NotNull ValidationMessageSeverity severityForOrphanedFilterEntries;
     private final Collection<PackageInfo> dependenciesMetaInfo;
     private final WorkspaceFilter filter;
     private Map<String, FilterValidator> filterValidators;
@@ -300,7 +300,7 @@ public final class AdvancedFilterValidat
         return FILTER_XML_PATH.equals(filePath);
     }
 
-    private void removeFromOrphanedFilterEntries(String nodePath) {
+    private void removeFromOrphanedFilterEntries(@NotNull String nodePath) {
         // find all filter roots which match
         Iterator<java.util.Map.Entry<PathFilterSet, List<Entry<PathFilter>>>> iter = orphanedFilterSets.entrySet().iterator();
         while (iter.hasNext()) {

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/DocumentViewParserValidator.java Fri Mar  6 07:27:44 2020
@@ -69,7 +69,7 @@ public class DocumentViewParserValidator
     }
 
     @Override
-    public Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException {
+    public Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Path basePath, @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException {
         Collection<ValidationMessage> messages = new LinkedList<>();
         // TODO: support other formats like sysview xml or generic xml
         // (https://jackrabbit.apache.org/filevault/vaultfs.html#Deserialization)
@@ -80,7 +80,7 @@ public class DocumentViewParserValidator
         Path documentViewXmlRootPath = getDocumentViewXmlRootPath(bufferedInput, filePath);
         if (documentViewXmlRootPath != null) {
             try {
-                messages.addAll(validateDocumentViewXml(bufferedInput, filePath, ValidationExecutor.filePathToNodePath(documentViewXmlRootPath),
+                messages.addAll(validateDocumentViewXml(bufferedInput, filePath, basePath, ValidationExecutor.filePathToNodePath(documentViewXmlRootPath),
                             nodePathsAndLineNumbers));
             } catch (SAXException e) {
                 throw new IOException("Could not parse xml", e);
@@ -136,11 +136,11 @@ public class DocumentViewParserValidator
         return rootPath;
     }
 
-    protected Collection<ValidationMessage> validateDocumentViewXml(InputStream input, Path filePath, String rootNodePath,
+    protected Collection<ValidationMessage> validateDocumentViewXml(InputStream input, Path filePath, Path basePath, String rootNodePath,
             Map<String, Integer> nodePathsAndLineNumbers) throws IOException, SAXException {
         List<ValidationMessage> enrichedMessages = new LinkedList<>();
         XMLReader xr = saxParser.getXMLReader();
-        final DocumentViewXmlContentHandler handler = new DocumentViewXmlContentHandler(filePath, rootNodePath,
+        final DocumentViewXmlContentHandler handler = new DocumentViewXmlContentHandler(filePath, basePath, rootNodePath,
                 docViewValidators);
         enrichedMessages.add(new ValidationMessage(ValidationMessageSeverity.DEBUG, "Detected DocView..."));
         xr.setContentHandler(handler);

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/EmptyElementsValidator.java Fri Mar  6 07:27:44 2020
@@ -16,12 +16,9 @@
  */
 package org.apache.jackrabbit.vault.validation.spi.impl;
 
-import java.nio.file.Path;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
-import java.util.Map;
+import java.util.List;
 import java.util.stream.Collectors;
 
 import org.apache.jackrabbit.vault.fs.api.ImportMode;
@@ -29,6 +26,7 @@ import org.apache.jackrabbit.vault.fs.ap
 import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
 import org.apache.jackrabbit.vault.util.DocViewNode;
 import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
+import org.apache.jackrabbit.vault.validation.spi.NodeContext;
 import org.apache.jackrabbit.vault.validation.spi.NodePathValidator;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessage;
 import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity;
@@ -42,10 +40,10 @@ import org.jetbrains.annotations.Nullabl
  */
 public class EmptyElementsValidator implements DocumentViewXmlValidator, NodePathValidator {
 
-    protected static final String MESSAGE_EMPTY_NODES = "Found empty nodes: %s (used for ordering only) without an accompanying folder which are included in the filter with mode=replace. Either remove the empty node or add at least the 'jcr:primaryType' attribute to make this node really get replaced.";
+    protected static final String MESSAGE_EMPTY_NODES = "Found empty node (used for ordering only) without an accompanying folder which are included in the filter with mode=replace. Either remove the empty node or add at least the 'jcr:primaryType' attribute to make this node really get replaced.";
     private final ValidationMessageSeverity severity;
-    private final Map<String, Path> emptyNodePathsAndFiles;
-    private final Collection<String> nonEmptyNodePaths;
+    private final List<NodeContext> emptyNodes;
+    private final List<String> nonEmptyNodePaths;
     private final WorkspaceFilter filter;
     
     private Collection<String> affectedFilterRoots;
@@ -53,7 +51,7 @@ public class EmptyElementsValidator impl
     
     public EmptyElementsValidator(ValidationMessageSeverity severity, WorkspaceFilter filter) {
         this.severity = severity;
-        this.emptyNodePathsAndFiles = new LinkedHashMap<>();
+        this.emptyNodes = new LinkedList<>();
         this.nonEmptyNodePaths = new LinkedList<>();
         this.filter = filter;
         // collect all filter roots with import mode == replace
@@ -67,25 +65,23 @@ public class EmptyElementsValidator impl
 
     @Override
     public Collection<ValidationMessage> done() {
-        emptyNodePathsAndFiles.keySet().removeAll(nonEmptyNodePaths);
-        if (!emptyNodePathsAndFiles.isEmpty()) {
-            String nodes = emptyNodePathsAndFiles.entrySet()
-                    .stream()
-                    .map(e -> "'" + e.getKey() + "' (in '" + e.getValue() + "')")
-                    .collect(Collectors.joining(", "));
-            return Collections.singleton(new ValidationMessage(severity, String.format(MESSAGE_EMPTY_NODES, nodes)));
-        }
-        return null;
+        return emptyNodes.stream()
+            .filter(e -> nonEmptyNodePaths.stream().noneMatch(n -> n.equals(e.getNodePath())))
+            .map(e -> new ValidationMessage(severity, MESSAGE_EMPTY_NODES, e.getNodePath(), e.getFilePath(), e.getBasePath(), null))
+            .collect(Collectors.toList());
     }
 
     @Override
-    public Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull String nodePath, @NotNull Path filePath, boolean isRoot) {
-        if (isBelowAffectedFilterRoots(nodePath)) {
-            if (node.primary == null && node.mixins == null && node.props.isEmpty() && filter.contains(nodePath) && filter.getImportMode(nodePath) == ImportMode.REPLACE) {
+    public Collection<ValidationMessage> validate(@NotNull DocViewNode node, @NotNull NodeContext nodeContext, boolean isRoot) {
+        if (isBelowAffectedFilterRoots(nodeContext.getNodePath())) {
+            if (node.primary == null && node.mixins == null && node.props.isEmpty() && filter.contains(nodeContext.getNodePath()) && filter.getImportMode(nodeContext.getNodePath()) == ImportMode.REPLACE) {
                 // only relevant if no other merge mode
-                emptyNodePathsAndFiles.put(nodePath, filePath);
+                // ignore rep:policy nodes
+                if (!node.name.equals("rep:policy")) {
+                    emptyNodes.add(nodeContext);
+                }
             } else {
-                nonEmptyNodePaths.add(nodePath);
+                nonEmptyNodePaths.add(nodeContext.getNodePath());
             }
         }
         return null;
@@ -101,9 +97,9 @@ public class EmptyElementsValidator impl
     }
 
     @Override
-    public @Nullable Collection<ValidationMessage> validate(@NotNull String nodePath) {
-        if (isBelowAffectedFilterRoots(nodePath)) {
-            nonEmptyNodePaths.add(nodePath);
+    public @Nullable Collection<ValidationMessage> validate(@NotNull NodeContext nodeContext) {
+        if (isBelowAffectedFilterRoots(nodeContext.getNodePath())) {
+            nonEmptyNodePaths.add(nodeContext.getNodePath());
         }
         return null;
     }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidator.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidator.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidator.java Fri Mar  6 07:27:44 2020
@@ -21,7 +21,9 @@ import java.nio.file.Paths;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
@@ -33,6 +35,7 @@ import org.apache.jackrabbit.vault.util.
 import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator;
 import org.apache.jackrabbit.vault.validation.spi.FilterValidator;
 import org.apache.jackrabbit.vault.validation.spi.MetaInfPathValidator;
+import org.apache.jackrabbit.vault.validation.spi.NodeContext;
 import org.apache.jackrabbit.vault.validation.spi.NodePathValidator;
 import org.apache.jackrabbit.vault.validation.spi.PropertiesValidator;
 import org.apache.jackrabbit.vault.validation.spi.ValidationContext;
@@ -53,10 +56,10 @@ public final class PackageTypeValidator
     protected static final String MESSAGE_LEGACY_TYPE = "Package of type '%s' is legacy. Use one of the other types instead!";
     protected static final String MESSAGE_PACKAGE_HOOKS = "Package of type '%s' must not contain package hooks but has '%s'!";
     protected static final String MESSAGE_NO_PACKAGE_TYPE_SET = "No package type set, make sure that property 'packageType' is set in the properties.xml!";
-    protected static final String MESSAGE_OSGI_BUNDLE_OR_CONFIG = "Package of type '%s' is not supposed to contain OSGi bundles or configurations but has '%s'!";
-    protected static final String MESSAGE_NO_OSGI_BUNDLE_OR_CONFIG_OR_SUB_PACKAGE = "Package of type '%s' is not supposed to contain anything but OSGi bundles/configurations and sub packages but has '%s'!";
-    protected static final String MESSAGE_APP_CONTENT = "Package of type '%s' is not supposed to contain content inside '/libs' and '/apps' but has '%s'!";
-    protected static final String MESSAGE_NO_APP_CONTENT_FOUND = "Package of type '%s' is not supposed to contain content outside '/libs' and '/apps' but has '%s'!";
+    protected static final String MESSAGE_OSGI_BUNDLE_OR_CONFIG = "Package of type '%s' is not supposed to contain OSGi bundles or configurations!";
+    protected static final String MESSAGE_NO_OSGI_BUNDLE_OR_CONFIG_OR_SUB_PACKAGE = "Package of type '%s' is not supposed to contain anything but OSGi bundles/configurations and sub packages!";
+    protected static final String MESSAGE_APP_CONTENT = "Package of type '%s' is not supposed to contain content inside '/libs' and '/apps'!";
+    protected static final String MESSAGE_NO_APP_CONTENT_FOUND = "Package of type '%s' is not supposed to contain content outside '/libs' and '/apps'!";
     protected static final String MESSAGE_INDEX_DEFINITIONS = "Package of type '%s' is not supposed to contain Oak index definitions but has 'allowIndexDefinitions' set to true.";
     protected static final String MESSAGE_PROHIBITED_MUTABLE_PACKAGE_TYPE = "All mutable package types are prohibited and this package is of mutable type '%s'";
     protected static final String MESSAGE_PROHIBITED_IMMUTABLE_PACKAGE_TYPE = "All mutable package types are prohibited and this package is of mutable type '%s'";
@@ -72,10 +75,13 @@ public final class PackageTypeValidator
     private final boolean prohibitMutableContent;
     private final boolean prohibitImmutableContent;
     private final boolean allowComplexFilterRulesInApplicationPackages;
+    private final @NotNull WorkspaceFilter filter;
+    private List<String> validContainerNodePaths;
+    private List<NodeContext> potentiallyDisallowedContainerNodes;
 
-    public PackageTypeValidator(@NotNull ValidationMessageSeverity severity, @NotNull ValidationMessageSeverity severityForNoPackageType, @NotNull ValidationMessageSeverity severityForLegacyType,
+    public PackageTypeValidator(@NotNull WorkspaceFilter workspaceFilter, @NotNull ValidationMessageSeverity severity, @NotNull ValidationMessageSeverity severityForNoPackageType, @NotNull ValidationMessageSeverity severityForLegacyType,
             boolean prohibitMutableContent, boolean prohibitImmutableContent, boolean allowComplexFilterRulesInApplicationPackages, PackageType type, @NotNull Pattern jcrInstallerNodePathRegex, @NotNull Pattern additionalJcrInstallerFileNodePathRegex,
-            ValidationContext containerValidationContext) {
+            @Nullable ValidationContext containerValidationContext) {
         this.type = type;
         this.severity = severity;
         this.severityForNoPackageType = severityForNoPackageType;
@@ -86,6 +92,9 @@ public final class PackageTypeValidator
         this.jcrInstallerNodePathRegex = jcrInstallerNodePathRegex;
         this.additionalJcrInstallerFileNodePathRegex = additionalJcrInstallerFileNodePathRegex;
         this.containerValidationContext = containerValidationContext;
+        this.filter = workspaceFilter;
+        this.validContainerNodePaths = new LinkedList<>();
+        this.potentiallyDisallowedContainerNodes = new LinkedList<>();
     }
 
     boolean isOsgiBundleOrConfiguration(String nodePath, boolean onlyFile) {
@@ -109,40 +118,58 @@ public final class PackageTypeValidator
 
     @Override
     public @Nullable Collection<ValidationMessage> done() {
+        // check if questionable nodes are parents of valid nodes
+        List<NodeContext> invalidNodes = potentiallyDisallowedContainerNodes.stream().filter(
+                s -> validContainerNodePaths.stream().noneMatch(
+                        p -> p.startsWith(s.getNodePath() + "/")))
+                .collect(Collectors.toList());
+        if (!invalidNodes.isEmpty()) {
+            return invalidNodes.stream().map(
+                    e -> new ValidationMessage(severity, String.format(MESSAGE_NO_OSGI_BUNDLE_OR_CONFIG_OR_SUB_PACKAGE, type), e.getNodePath(), e.getFilePath(), e.getBasePath(), null))
+                    .collect(Collectors.toList());
+        }
         return null;
     }
 
     @Override
-    public @Nullable Collection<ValidationMessage> validate(@NotNull String nodePath) {
+    public @Nullable Collection<ValidationMessage> validate(@NotNull NodeContext nodeContext) {
         if (type == null) {
             return null;
         }
+        // ignore uncovered nodePaths
+        if (!filter.covers(nodeContext.getNodePath())) {
+            return null;
+        }
         Collection<ValidationMessage> messages = new LinkedList<>();
         switch (type) {
         case CONTENT:
-            if (isAppContent(nodePath)) {
-                messages.add(new ValidationMessage(severity, String.format(MESSAGE_APP_CONTENT, type, nodePath)));
+            if (isAppContent(nodeContext.getNodePath())) {
+                messages.add(new ValidationMessage(severity, String.format(MESSAGE_APP_CONTENT, type)));
             }
-            if (isOsgiBundleOrConfiguration(nodePath, true)) {
-                messages.add(new ValidationMessage(severity, String.format(MESSAGE_OSGI_BUNDLE_OR_CONFIG, type, nodePath)));
+            if (isOsgiBundleOrConfiguration(nodeContext.getNodePath(), true)) {
+                messages.add(new ValidationMessage(severity, String.format(MESSAGE_OSGI_BUNDLE_OR_CONFIG, type)));
             }
             break;
         case APPLICATION:
-            if (!isAppContent(nodePath)) {
-                messages.add(new ValidationMessage(severity, String.format(MESSAGE_NO_APP_CONTENT_FOUND, type, nodePath)));
+            if (!isAppContent(nodeContext.getNodePath())) {
+                messages.add(new ValidationMessage(severity, String.format(MESSAGE_NO_APP_CONTENT_FOUND, type)));
             }
-            if (isOsgiBundleOrConfiguration(nodePath, true)) {
-                messages.add(new ValidationMessage(severity, String.format(MESSAGE_OSGI_BUNDLE_OR_CONFIG, type, nodePath)));
+            if (isOsgiBundleOrConfiguration(nodeContext.getNodePath(), true)) {
+                messages.add(new ValidationMessage(severity, String.format(MESSAGE_OSGI_BUNDLE_OR_CONFIG, type)));
             }
             // sub packages are detected via validate(Properties) on the sub package
             break;
         case CONTAINER:
             // sling:OsgiConfig
-            if (!isOsgiBundleOrConfiguration(nodePath, false) && !isSubPackage(nodePath)) {
-                messages.add(
-                        new ValidationMessage(severity, String.format(MESSAGE_NO_OSGI_BUNDLE_OR_CONFIG_OR_SUB_PACKAGE, type, nodePath)));
+            if (isOsgiBundleOrConfiguration(nodeContext.getNodePath(), false)) {
+                validContainerNodePaths.add(nodeContext.getNodePath());
+            }
+            else if (isSubPackage(nodeContext.getNodePath())) {
+                validContainerNodePaths.add(nodeContext.getNodePath());
+            } else {
+                // only potentially disallowed, as the node may be a parent of a sub package or osgi bundle, which is allowed as well
+                potentiallyDisallowedContainerNodes.add(nodeContext);
             }
-
             break;
         case MIXED:
             // no validations currently as most relaxed type
@@ -271,7 +298,7 @@ public final class PackageTypeValidator
 
     
     @Override
-    public Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath) {
+    public Collection<ValidationMessage> validateMetaInfPath(@NotNull Path filePath, @NotNull Path basePath, boolean isFolder) {
         if (type == null) {
             return null;
         }
@@ -304,5 +331,4 @@ public final class PackageTypeValidator
         }
         return null;
     }
-
 }

Modified: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorFactory.java?rev=1874872&r1=1874871&r2=1874872&view=diff
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorFactory.java (original)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/impl/PackageTypeValidatorFactory.java Fri Mar  6 07:27:44 2020
@@ -113,7 +113,7 @@ public final class PackageTypeValidatorF
         } else {
             allowComplexFilterRulesInApplicationPackages = false;
         }
-        return new PackageTypeValidator(settings.getDefaultSeverity(), severityForNoType, severityForLegacyType, prohibitMutableContent, prohibitImmutableContent, allowComplexFilterRulesInApplicationPackages, context.getProperties().getPackageType(), jcrInstallerNodePathRegex, additionalJcrInstallerFileNodePathRegex, context.getContainerValidationContext());
+        return new PackageTypeValidator(context.getFilter(), settings.getDefaultSeverity(), severityForNoType, severityForLegacyType, prohibitMutableContent, prohibitImmutableContent, allowComplexFilterRulesInApplicationPackages, context.getProperties().getPackageType(), jcrInstallerNodePathRegex, additionalJcrInstallerFileNodePathRegex, context.getContainerValidationContext());
     }
 
     @Override

Added: jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/NodeContextImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/NodeContextImpl.java?rev=1874872&view=auto
==============================================================================
--- jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/NodeContextImpl.java (added)
+++ jackrabbit/commons/filevault/trunk/vault-validation/src/main/java/org/apache/jackrabbit/vault/validation/spi/util/NodeContextImpl.java Fri Mar  6 07:27:44 2020
@@ -0,0 +1,93 @@
+/*
+ * 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.jackrabbit.vault.validation.spi.util;
+
+import java.nio.file.Path;
+
+import org.apache.jackrabbit.vault.validation.spi.NodeContext;
+import org.jetbrains.annotations.NotNull;
+
+public final class NodeContextImpl implements NodeContext {
+    private final @NotNull String nodePath;
+    private final @NotNull Path filePath;
+    private final @NotNull Path basePath;
+
+    public NodeContextImpl(@NotNull String nodePath, @NotNull Path filePath, @NotNull Path basePath) {
+        super();
+        this.nodePath = nodePath;
+        this.filePath = filePath;
+        this.basePath = basePath;
+    }
+
+    @Override
+    public @NotNull String getNodePath() {
+        return nodePath;
+    }
+
+    @Override
+    public @NotNull Path getFilePath() {
+        return filePath;
+    }
+
+    @Override
+    public @NotNull Path getBasePath() {
+        return basePath;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((basePath == null) ? 0 : basePath.hashCode());
+        result = prime * result + ((filePath == null) ? 0 : filePath.hashCode());
+        result = prime * result + ((nodePath == null) ? 0 : nodePath.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        NodeContextImpl other = (NodeContextImpl) obj;
+        if (basePath == null) {
+            if (other.basePath != null)
+                return false;
+        } else if (!basePath.equals(other.basePath))
+            return false;
+        if (filePath == null) {
+            if (other.filePath != null)
+                return false;
+        } else if (!filePath.equals(other.filePath))
+            return false;
+        if (nodePath == null) {
+            if (other.nodePath != null)
+                return false;
+        } else if (!nodePath.equals(other.nodePath))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "NodeContextImpl [" + (nodePath != null ? "nodePath=" + nodePath + ", " : "")
+                + (filePath != null ? "filePath=" + filePath + ", " : "") + (basePath != null ? "basePath=" + basePath : "") + "]";
+    }
+}
\ No newline at end of file



Mime
View raw message