This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-repoinit-filevault-validator.git
commit c55ab69f270a8624b07d18839b2185b8c8c02d35 Author: Konrad Windszus <[email protected]> AuthorDate: Thu Dec 22 19:45:19 2022 +0100 SLING-11729 initial commit of a FileVault validator for RepoInit --- .gitignore | 4 + README.md | 46 +++++ pom.xml | 105 +++++++++++ src/it/project1/META-INF/vault/filter.xml | 20 +++ src/it/project1/invoker.properties | 17 ++ src/it/project1/pom.xml | 75 ++++++++ ...jcr.repoinit.RepositoryInitializer~test1.config | 17 ++ src/it/project1/verify.groovy | 23 +++ .../filevault/validator/RepoInitValidator.java | 192 +++++++++++++++++++++ .../validator/RepoInitValidatorFactory.java | 45 +++++ 10 files changed, 544 insertions(+) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f6424b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target/ +/.settings +/.project +/.classpath \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5f0a420 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +[](https://sling.apache.org) + +[](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-repoinit-filevault-validator/job/master/) +[](https://ci-builds.apache.org/job/Sling/job/modules/job/sling-org-apache-sling-repoinit-filevault-validator/job/master/test/?width=800&height=600) +[](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-repoinit-filevault-validator) +[](https://sonarcloud.io/dashboard?id=apache_sling-org-apache-sling-repoinit-filevault-validator) +[](https://www.javadoc.io/doc/org.apache.sling/org.apache.sling.repoinit.filevault.validator) +[](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.apache.sling%22%20a%3A%22org.apache.sling.repoinit.filevault.validator%22) +[](https://github.com/apache/sling-aggregator/blob/master/docs/groups/repoinit.md) +[](https://www.apache.org/licenses/LICENSE-2.0) + +# Apache Sling Repo Init FileVault Validator + +This module is part of the [Apache Sling](https://sling.apache.org) project. + +It implements a [FileVault validator][1] for the [Repository Initialization language][4] used in [serialized OSGi configurations][3]. +It emits validation error messages for invalid repoinit statements. + +# Usage with Maven + +You can use this validator with the [FileVault Package Maven Plugin][2] in version 1.3.0 or higher like this + +``` +<plugin> + <groupId>org.apache.jackrabbit</groupId> + <artifactId>filevault-package-maven-plugin</artifactId> + <dependencies> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.filevault.validator</artifactId> + <version><latestversion></version> + </dependency> + <!-- use the following dependency to optionally overwrite the used repoinit parser version (default=1.8.0) --> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.parser</artifactId> + <version><version of the parser in the runtime where my config is deployed to></version> + </dependency> + </dependencies> +</plugin> +``` + +[1]: https://jackrabbit.apache.org/filevault/validation.html +[2]: https://jackrabbit.apache.org/filevault-package-maven-plugin/index.html +[3]: https://sling.apache.org/documentation/bundles/configuration-installer-factory.html#configuration-serialization-formats +[4]: https://sling.apache.org/documentation/bundles/repository-initialization.html \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..58f7db0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,105 @@ +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.filevault.validator</artifactId> + <version>0.0.1-SNAPSHOT</version> + + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>49</version> + </parent> + + <properties> + <sling.java.version>8</sling.java.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.jackrabbit.vault</groupId> + <artifactId>vault-validation</artifactId> + <version>3.6.0</version> + <scope>compile</scope> + </dependency> + <!-- We use a class from the config admin implementation to read config files --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.configadmin</artifactId> + <version>1.8.12</version> + <scope>compile</scope> + </dependency> + <!-- JSON Configurations --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.cm.json</artifactId> + <version>1.0.6</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-json_1.1_spec</artifactId> + <version>1.2</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.parser</artifactId> + <version>1.8.0</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.jetbrains</groupId> + <artifactId>annotations</artifactId> + <scope>provided</scope> + </dependency> + <!-- http://metainf-services.kohsuke.org/index.html --> + <dependency> + <groupId>org.kohsuke.metainf-services</groupId> + <artifactId>metainf-services</artifactId> + <version>1.8</version> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-invoker-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>install</goal> + <goal>run</goal> + </goals> + <configuration> + <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo> + <postBuildHookScript>verify.groovy</postBuildHookScript> + <streamLogsOnFailures>true</streamLogsOnFailures> + <debug>true</debug> + <!-- reuse global repo for speeding up builds + <localRepositoryPath>target/it-repo</localRepositoryPath> --> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/src/it/project1/META-INF/vault/filter.xml b/src/it/project1/META-INF/vault/filter.xml new file mode 100644 index 0000000..c180df7 --- /dev/null +++ b/src/it/project1/META-INF/vault/filter.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<workspaceFilter version="1.0"> + <filter root="/apps/test"/> +</workspaceFilter> \ No newline at end of file diff --git a/src/it/project1/invoker.properties b/src/it/project1/invoker.properties new file mode 100644 index 0000000..021186e --- /dev/null +++ b/src/it/project1/invoker.properties @@ -0,0 +1,17 @@ +# 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. +invoker.buildResult = failure \ No newline at end of file diff --git a/src/it/project1/pom.xml b/src/it/project1/pom.xml new file mode 100644 index 0000000..dd1bcc6 --- /dev/null +++ b/src/it/project1/pom.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.filevault.validator.project1</artifactId> + <packaging>content-package</packaging> + <version>1.0.0-SNAPSHOT</version> + + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling</artifactId> + <version>49</version> + </parent> + + <build> + <plugins> + <plugin> + <groupId>org.apache.rat</groupId> + <artifactId>apache-rat-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.jackrabbit</groupId> + <artifactId>filevault-package-maven-plugin</artifactId> + <version>1.3.0</version> + <extensions>true</extensions> + <configuration> + <packageType>container</packageType> + <validatorsSettings> + <jackrabbit-filter> + <!-- define additional valid roots which are always provided in Sling --> + <options> + <validRoots>/,/libs,/apps</validRoots> + </options> + </jackrabbit-filter> + </validatorsSettings> + </configuration> + <dependencies> + <!-- override the parser dependency (explicit downgrade from 1.8.0) --> + <dependency> + <groupId>org.apache.sling</groupId> + <artifactId>org.apache.sling.repoinit.parser</artifactId> + <version>1.6.14</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>@project.groupId@</groupId> + <artifactId>@project.artifactId@</artifactId> + <version>@project.version@</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/src/it/project1/src/main/jcr_root/apps/test/config/org.apache.sling.jcr.repoinit.RepositoryInitializer~test1.config b/src/it/project1/src/main/jcr_root/apps/test/config/org.apache.sling.jcr.repoinit.RepositoryInitializer~test1.config new file mode 100644 index 0000000..6d596ba --- /dev/null +++ b/src/it/project1/src/main/jcr_root/apps/test/config/org.apache.sling.jcr.repoinit.RepositoryInitializer~test1.config @@ -0,0 +1,17 @@ +# 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. +scripts=invalid \ No newline at end of file diff --git a/src/it/project1/verify.groovy b/src/it/project1/verify.groovy new file mode 100644 index 0000000..4957ba6 --- /dev/null +++ b/src/it/project1/verify.groovy @@ -0,0 +1,23 @@ +/* + * 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. + */ + +String buildLog = new File(basedir, 'build.log').text + +assert buildLog.contains('''[ERROR] ValidationViolation: "sling-repoinit: Invalid repoinit statement(s) detected: Encountered " <STRING> "invalid "" at line 1, column 1. +Was expecting: + <EOF> + ", filePath=''' + "src${File.separator}main${File.separator}jcr_root${File.separator}apps${File.separator}test${File.separator}config${File.separator}org.apache.sling.jcr.repoinit.RepositoryInitializer~test1.config") diff --git a/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidator.java b/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidator.java new file mode 100644 index 0000000..28f6e73 --- /dev/null +++ b/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidator.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.repoinit.filevault.validator; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.apache.felix.cm.json.ConfigurationReader; +import org.apache.jackrabbit.spi.Name; +import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; +import org.apache.jackrabbit.util.Text; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.apache.jackrabbit.vault.util.DocViewProperty2; +import org.apache.jackrabbit.vault.validation.spi.DocumentViewXmlValidator; +import org.apache.jackrabbit.vault.validation.spi.GenericJcrDataValidator; +import org.apache.jackrabbit.vault.validation.spi.NodeContext; +import org.apache.jackrabbit.vault.validation.spi.ValidationMessage; +import org.apache.jackrabbit.vault.validation.spi.ValidationMessageSeverity; +import org.apache.sling.repoinit.parser.RepoInitParsingException; +import org.apache.sling.repoinit.parser.impl.RepoInitParserService; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class RepoInitValidator implements DocumentViewXmlValidator, GenericJcrDataValidator { + + private final RepoInitParserService parser; + + public RepoInitValidator() { + parser = new RepoInitParserService(); + } + enum OsgiConfigurationSerialization { + CFG, + CFG_JSON, + CONFIG + } + + private static final String OSGI_CONFIG_NAME = "org\\.apache\\.sling\\.jcr\\.repoinit\\.RepositoryInitializer(~|-).*"; + + private static final Pattern OSGI_CONFIG_NODE_NAME_PATTERN = Pattern.compile(OSGI_CONFIG_NAME); + + /** + * https://sling.apache.org/documentation/bundles/configuration-installer-factory.html#configuration-serialization-formats + */ + private static final Pattern OSGI_CONFIG_FILE_NAME_PATTERN = Pattern.compile(OSGI_CONFIG_NAME + "\\.(config|cfg\\.json|cfg)"); + + @Nullable + public Collection<ValidationMessage> done() { + return null; + } + + @Override + public @Nullable Collection<ValidationMessage> validate(@NotNull DocViewNode2 node, @NotNull NodeContext nodeContext, + boolean isRoot) { + if ("sling:OsgiConfig".equals(node.getPrimaryType().orElse("")) && OSGI_CONFIG_NODE_NAME_PATTERN.matcher(Text.getName(nodeContext.getNodePath())).matches()) { + Optional<DocViewProperty2> scriptsProperty = node.getProperty(NameFactoryImpl.getInstance().create(Name.NS_DEFAULT_URI, "scripts")); + if (scriptsProperty.isPresent()) { + try { + return validateStatements(scriptsProperty.get().getStringValues()); + } catch (IOException e) { + return Collections.singleton(new ValidationMessage(ValidationMessageSeverity.ERROR, "IOException while parsing " + nodeContext.getFilePath() +" : " + e.getMessage(), e)); + } + } + } + return null; + } + + + @Override + @Nullable + public Collection<ValidationMessage> validateJcrData(@NotNull InputStream input, @NotNull Path filePath, @NotNull Path basePath, + @NotNull Map<String, Integer> nodePathsAndLineNumbers) throws IOException { + Map<String, Object> config = deserializeOsgiConfiguration(getType(filePath.getFileName().toString()), input); + return validateConfig(config); + } + + public boolean shouldValidateJcrData(@NotNull Path filePath, @NotNull Path basePath) { + return isOsgiConfig(filePath); + } + + private OsgiConfigurationSerialization getType(String fileName) { + if (fileName.endsWith(".cfg.json")) { + return OsgiConfigurationSerialization.CFG_JSON; + } else if (fileName.endsWith(".config")) { + return OsgiConfigurationSerialization.CONFIG; + } else if (fileName.endsWith(".cfg")) { + return OsgiConfigurationSerialization.CONFIG; + } else { + throw new IllegalArgumentException("Given file name " + fileName + " does not represent a known OSGi configuration serialization"); + } + } + + private boolean isOsgiConfig(@NotNull Path filePath) { + // TODO: check depth of config node + String fileName = filePath.getFileName().toString(); + return OSGI_CONFIG_FILE_NAME_PATTERN.matcher(fileName).matches(); + } + + Map<String, Object> deserializeOsgiConfiguration(@NotNull OsgiConfigurationSerialization serializationType, @NotNull InputStream input) throws IOException { + switch(serializationType) { + case CONFIG: + Properties properties = new Properties(); + properties.load(input); + return convertToMap(properties); + case CFG: + return convertToMap(org.apache.felix.cm.file.ConfigurationHandler.read(input)); + case CFG_JSON: + Reader reader = new InputStreamReader(input, StandardCharsets.UTF_8); + ConfigurationReader configReader = org.apache.felix.cm.json.Configurations.buildReader().build(reader); + return convertToMap(configReader.readConfiguration()); + } + return null; + } + + private Collection<ValidationMessage> validateConfig(Map<String, Object> config) throws IOException { + // https://sling.apache.org/documentation/bundles/repository-initialization.html#providing-repoinit-statements-from-osgi-factory-configurations + // only evaluate scripts for now, references might have unresolvable URLs at the time of building (https://sling.apache.org/documentation/bundles/repository-initialization.html#references-to-urls-providing-raw-repoinit-statements) + Object scripts = config.get("scripts"); + if (scripts == null) { + return null; + } + if (scripts instanceof String[]) { + return validateStatements(Arrays.asList((String[])scripts)); + } else if (scripts instanceof String) { + return validateStatements((String)scripts).map(Collections::singletonList).orElse(null); + } else { + return Collections.singletonList(new ValidationMessage(ValidationMessageSeverity.ERROR, "OSGi config property 'scripts' must be of type String or String[]")); + } + } + + private Collection<ValidationMessage> validateStatements(Collection<String> scripts) throws IOException { + List<ValidationMessage> validationMsgs = new ArrayList<>(); + for (String statements : scripts) { + validateStatements(statements).ifPresent(validationMsgs::add); + } + return validationMsgs; + } + + private Optional<ValidationMessage> validateStatements(String statements) throws IOException { + try (Reader reader = new StringReader(statements)) { + parser.parse(reader); + } catch (RepoInitParsingException e) { + return Optional.of(new ValidationMessage(ValidationMessageSeverity.ERROR, "Invalid repoinit statement(s) detected: " + e.getMessage(), e)); + } + return Optional.empty(); + } + + static Map<String, Object> convertToMap(Dictionary<String, ?> dictionary) { + List<String> keys = Collections.list(dictionary.keys()); + return keys.stream().collect(Collectors.toMap(Function.identity(), dictionary::get)); + } + + static Map<String, Object> convertToMap(Properties properties) { + return properties.entrySet().stream().collect( + Collectors.toMap( + e -> String.valueOf(e.getKey()), + e -> String.valueOf(e.getValue()), + (prev, next) -> next, HashMap::new + )); + } +} diff --git a/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidatorFactory.java b/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidatorFactory.java new file mode 100644 index 0000000..f471750 --- /dev/null +++ b/src/main/java/org/apache/sling/repoinit/filevault/validator/RepoInitValidatorFactory.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.repoinit.filevault.validator; + +import org.apache.jackrabbit.vault.validation.spi.ValidationContext; +import org.apache.jackrabbit.vault.validation.spi.Validator; +import org.apache.jackrabbit.vault.validation.spi.ValidatorFactory; +import org.apache.jackrabbit.vault.validation.spi.ValidatorSettings; +import org.jetbrains.annotations.NotNull; +import org.kohsuke.MetaInfServices; + +@MetaInfServices +public class RepoInitValidatorFactory implements ValidatorFactory { + + public Validator createValidator(@NotNull ValidationContext context, @NotNull ValidatorSettings settings) { + return new RepoInitValidator(); + } + + public boolean shouldValidateSubpackages() { + return false; + } + + public @NotNull String getId() { + return "sling-repoinit"; + } + + public int getServiceRanking() { + return 0; + } + +}
