class PackageTypeValidator implements NodePathValidator, FilterValidator, PropertiesValidator, MetaInfPathValidator, DocumentViewXmlValidator {

    @Override
    public @Nullable Collection<ValidationMessage> validate(@NotNull NodeContext nodeContext) {
        // ignore uncovered nodePaths
        if (!filter.covers(nodeContext.getNodePath())) {
            return null;
        }
        Collection<ValidationMessage> messages = new LinkedList<>();
        switch (type) {
        case CONTENT:
            if (isAppContent(nodeContext.getNodePath())) {
                messages.add(new ValidationMessage(severity, String.format(MESSAGE_APP_CONTENT, type)));
            }
            if (isOsgiBundleOrConfiguration(nodeContext.getNodePath(), true)) {
                messages.add(new ValidationMessage(severity, String.format(MESSAGE_OSGI_BUNDLE_OR_CONFIG, type)));
            }
            break;
        case APPLICATION:
            if (!isAppContent(nodeContext.getNodePath())) {
                messages.add(new ValidationMessage(severity, String.format(MESSAGE_NO_APP_CONTENT_FOUND, type)));
            }
            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(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
            break;
        }
        return messages;
    }

    public  PackageTypeValidator(@NotNull WorkspaceFilter workspaceFilter, @NotNull ValidationMessageSeverity severity,
            @NotNull ValidationMessageSeverity severityForNoPackageType, @NotNull ValidationMessageSeverity severityForLegacyType,
            boolean prohibitMutableContent, boolean prohibitImmutableContent, boolean allowComplexFilterRulesInApplicationPackages,
            @NotNull PackageType type, @NotNull Pattern jcrInstallerNodePathRegex, @NotNull Pattern additionalJcrInstallerFileNodePathRegex,
            @Nullable ValidationContext containerValidationContext);

}