getAllChecklists() {
/**
* Compute the checklist plan for progress checks, given a list of override specs to apply.
- *
+ *
* Intended Algorithm:
* from selected checklists, stream specs
- * - apply overrides
- * - drop skipped specs
- * - collect overlaid
+ * - apply overrides
+ * - drop skipped specs
+ * - collect overlaid
* from overrides, stream as remaining specs
- * - drop skipped specs
- * - drop if already applied as overlay
- * - apply as overlay to inactive checklist specs if possible
- * - apply inheritance from any checklist spec if necessary
- * - add result if not abstract
+ * - drop skipped specs
+ * - drop if already applied as overlay
+ * - apply as overlay to inactive checklist specs if possible
+ * - apply inheritance from any checklist spec if necessary
+ * - add result if not abstract
*
* @param checkOverrides the list of check overrides
* @return a final list of {@link CheckSpec}s to use for a scan
diff --git a/core/src/main/java/net/adamcin/oakpal/core/CoreConstants.java b/core/src/main/java/net/adamcin/oakpal/core/CoreConstants.java
new file mode 100644
index 000000000..568a2966f
--- /dev/null
+++ b/core/src/main/java/net/adamcin/oakpal/core/CoreConstants.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2020 Mark Adamcin
+ *
+ * Licensed 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 net.adamcin.oakpal.core;
+
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+/**
+ * Hosts constants for interface types as static singleton getter methods defined by associated interfaces.
+ * This reduces the impact on semantic versioning rules of adding or modifying interface constants. A similar pattern is
+ * followed on concrete classes when they must define JSON keys, but each concrete class owns its own constants
+ * interfaces.
+ */
+public final class CoreConstants {
+ private CoreConstants() {
+ /* no constructor */
+ }
+
+ /**
+ * Json keys for CheckReport. Use {@link CoreConstants#checkReportKeys()} to access singleton.
+ */
+ @ProviderType
+ public interface CheckReportKeys {
+ String checkName();
+
+ String violations();
+ }
+
+ private static final CheckReportKeys CHECK_REPORT_KEYS = new CheckReportKeys() {
+ @Override
+ public String checkName() {
+ return "checkName";
+ }
+
+ @Override
+ public String violations() {
+ return "violations";
+ }
+ };
+
+ @NotNull
+ public static CheckReportKeys checkReportKeys() {
+ return CHECK_REPORT_KEYS;
+ }
+}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/DefaultErrorListener.java b/core/src/main/java/net/adamcin/oakpal/core/DefaultErrorListener.java
index 8215cb4ef..8d9bb5dd2 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/DefaultErrorListener.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/DefaultErrorListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,24 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ReportCollector;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
+import net.adamcin.oakpal.api.ViolationReporter;
import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.PathNotFoundException;
import java.net.URL;
+import java.text.MessageFormat;
import java.util.Collection;
+import java.util.MissingResourceException;
import java.util.Optional;
+import java.util.ResourceBundle;
/**
* Default implementation which reports all exceptions as violations.
@@ -33,10 +43,52 @@ public class DefaultErrorListener implements ErrorListener {
private final ReportCollector collector = new ReportCollector();
+ private ResourceBundle resourceBundle;
+
protected void reportViolation(final Violation violation) {
this.collector.reportViolation(violation);
}
+ @Override
+ public void setResourceBundle(final ResourceBundle resourceBundle) {
+ this.resourceBundle = resourceBundle;
+ }
+
+ /**
+ * Used by {@link #getString(String)} to retrieve localized messages.
+ * NOTE: If this method is called before a non-null ResourceBundle has been injected via
+ * {@link ViolationReporter#setResourceBundle(ResourceBundle)}, it will try to get a fallback ResourceBundle
+ * by calling {@link ResourceBundle#getBundle(String)}, which invokes the default classloader and locale behavior,
+ * using {@link ViolationReporter#getResourceBundleBaseName()} as the resource bundle base name.
+ *
+ * @return the resource bundle
+ * @see ResourceBundle#getBundle(String)
+ * @see ViolationReporter#getResourceBundleBaseName()
+ */
+ @NotNull
+ protected ResourceBundle getResourceBundle() throws MissingResourceException {
+ if (this.resourceBundle == null) {
+ this.resourceBundle = ResourceBundle.getBundle(getResourceBundleBaseName());
+ }
+ return this.resourceBundle;
+ }
+
+ /**
+ * Lookup a localized string from the resource bundle.
+ *
+ * @param key the i18n key
+ * @return the localized string
+ * @throws MissingResourceException if an attempt is made to load a missing ResourceBundle
+ */
+ @NotNull
+ protected String getString(@NotNull final String key) {
+ if (getResourceBundle().containsKey(key)) {
+ return getResourceBundle().getString(key);
+ } else {
+ return key;
+ }
+ }
+
@Override
public Collection getReportedViolations() {
return collector.getReportedViolations();
@@ -47,10 +99,10 @@ public void onNodeTypeRegistrationError(final Throwable e, final URL resource) {
if (e.getCause() != null) {
onNodeTypeRegistrationError(e.getCause(), resource);
} else {
- final String message = String.format("NodeType registration error (%s): %s \"%s\"",
+ final String message = MessageFormat.format(getString("NodeType registration error ({0}): {1} \"{2}\""),
String.valueOf(resource), e.getClass().getName(), e.getMessage());
LOGGER.trace("[onNodeTypeRegistrationError] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message));
}
}
@@ -59,10 +111,10 @@ public void onJcrNamespaceRegistrationError(final Throwable e, final String pref
if (e.getCause() != null) {
onJcrNamespaceRegistrationError(e.getCause(), prefix, uri);
} else {
- final String message = String.format("JCR namespace registration error (%s=%s): %s \"%s\"",
+ final String message = MessageFormat.format(getString("JCR namespace registration error ({0}={1}): {2} \"{3}\""),
prefix, uri, e.getClass().getName(), e.getMessage());
LOGGER.trace("[onJcrNamespaceRegistrationError] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message));
}
}
@@ -71,10 +123,10 @@ public void onJcrPrivilegeRegistrationError(final Throwable e, final String jcrP
if (e.getCause() != null) {
onJcrPrivilegeRegistrationError(e.getCause(), jcrPrivilege);
} else {
- final String message = String.format("JCR privilege registration error (%s): %s \"%s\"",
+ final String message = MessageFormat.format(getString("JCR privilege registration error ({0}): {1} \"{2}\""),
jcrPrivilege, e.getClass().getName(), e.getMessage());
LOGGER.trace("[onJcrPrivilegeRegistrationError] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message));
}
}
@@ -83,59 +135,62 @@ public void onForcedRootCreationError(final Throwable e, final ForcedRoot forced
if (e.getCause() != null) {
onForcedRootCreationError(e.getCause(), forcedRoot);
} else {
- final String message = String.format("Forced root creation error (%s): %s \"%s\"",
+ final String message = MessageFormat.format(getString("Forced root creation error ({0}): {1} \"{2}\""),
forcedRoot, e.getClass().getName(), e.getMessage());
LOGGER.trace("[onForcedRootCreationError] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message));
}
}
@Override
public void onListenerException(final Exception e, final ProgressCheck listener, final PackageId packageId) {
- final String message = String.format("Listener error (%s): %s \"%s\"",
+ final String message = MessageFormat.format(getString("Listener error ({0}): {1} \"{2}\""),
Optional.ofNullable(listener).map(lstr -> lstr.getClass().getName()).orElse(null),
e.getClass().getName(), e.getMessage());
LOGGER.trace("[onListenerException] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message, packageId));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message, packageId));
}
@Override
public void onSubpackageException(final Exception e, final PackageId packageId) {
- final String message = String.format("Package error: %s \"%s\"", e.getClass().getName(), e.getMessage());
+ final String message = MessageFormat.format(getString("Package error: {0} \"{1}\""),
+ e.getClass().getName(), e.getMessage());
LOGGER.trace("[onSubpackageException] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message, packageId));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message, packageId));
}
@Override
public void onImporterException(final Exception e, final PackageId packageId, final String path) {
// Ignore PathNotFoundException, as it is thrown A LOT
if (!(e instanceof PathNotFoundException)) {
- final String message = String.format("%s - Importer error: %s \"%s\"", path, e.getClass().getName(), e.getMessage());
+ final String message = MessageFormat.format(getString("{0} - Importer error: {1} \"{2}\""),
+ path, e.getClass().getName(), e.getMessage());
LOGGER.trace("[onImporterException] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message, packageId));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message, packageId));
}
}
@Override
public void onListenerPathException(final Exception e, final ProgressCheck handler,
final PackageId packageId, final String path) {
- final String message = String.format("%s - Listener error: %s \"%s\"", path, e.getClass().getName(), e.getMessage());
+ final String message = MessageFormat.format(getString("{0} - Listener error: {1} \"{2}\""),
+ path, e.getClass().getName(), e.getMessage());
LOGGER.trace("[onListenerPathException] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message, packageId));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message, packageId));
}
@Override
public void onInstallHookError(final Throwable e, final PackageId packageId) {
- final String message = String.format("InstallHook error: %s \"%s\"",
+ final String message = MessageFormat.format(getString("InstallHook error: {0} \"{1}\""),
Optional.ofNullable(e.getCause()).orElse(e).getClass().getName(), e.getMessage());
LOGGER.trace("[onInstallHookError] stack trace for: " + message, e);
- reportViolation(new SimpleViolation(Violation.Severity.MAJOR, message, packageId));
+ reportViolation(new SimpleViolation(Severity.MAJOR, message, packageId));
}
@Override
public void onProhibitedInstallHookRegistration(final PackageId packageId) {
reportViolation(
- new SimpleViolation(Violation.Severity.MAJOR,
- "Policy prohibits the use of InstallHooks in packages", packageId));
+ new SimpleViolation(Severity.MAJOR,
+ getString("Policy prohibits the use of InstallHooks in packages"), packageId));
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/DefaultPackagingService.java b/core/src/main/java/net/adamcin/oakpal/core/DefaultPackagingService.java
index 4c6a717ce..42e9dc7b7 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/DefaultPackagingService.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/DefaultPackagingService.java
@@ -35,7 +35,6 @@
* {@link PackagingService#getPackageManager(Session)} method to avoid the nasty stack trace.
* See recommendation here: https://issues.apache.org/jira/browse/JCRVLT-285
*/
-@SuppressWarnings("CQRules:CQBP-84--dependencies") // suppress warnings
final class DefaultPackagingService implements Packaging {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultPackagingService.class);
private static final String JCR_PACK_MAN_IMPL_CLASS = "org.apache.jackrabbit.vault.packaging.impl.JcrPackageManagerImpl";
diff --git a/core/src/main/java/net/adamcin/oakpal/core/ErrorListener.java b/core/src/main/java/net/adamcin/oakpal/core/ErrorListener.java
index 3f267f6ef..0485ee93f 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/ErrorListener.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/ErrorListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,18 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ScanListener;
+import net.adamcin.oakpal.api.ViolationReporter;
import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.osgi.annotation.versioning.ConsumerType;
import java.net.URL;
/**
* A single error handler is used during an OakPAL scan.
*/
+@ConsumerType
public interface ErrorListener extends ScanListener, ViolationReporter {
/**
diff --git a/core/src/main/java/net/adamcin/oakpal/core/ForcedRoot.java b/core/src/main/java/net/adamcin/oakpal/core/ForcedRoot.java
index 178c562a2..572e78347 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/ForcedRoot.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/ForcedRoot.java
@@ -16,8 +16,10 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.JsonObjectConvertible;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
import javax.json.JsonObject;
import java.util.Arrays;
@@ -28,19 +30,49 @@
import java.util.function.Function;
import java.util.stream.Stream;
-import static net.adamcin.oakpal.core.Fun.inferTest1;
-import static net.adamcin.oakpal.core.Fun.streamIt;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfStrings;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
+import static net.adamcin.oakpal.api.Fun.inferTest1;
+import static net.adamcin.oakpal.api.Fun.streamIt;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfStrings;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static net.adamcin.oakpal.api.JavaxJson.optArray;
/**
* Encapsulation of details necessary to force creation of a particular root path.
*/
-public final class ForcedRoot implements JavaxJson.ObjectConvertible, Comparable {
- static final String KEY_PATH = "path";
- static final String KEY_PRIMARY_TYPE = "primaryType";
- static final String KEY_MIXIN_TYPES = "mixinTypes";
+public final class ForcedRoot implements JsonObjectConvertible, Comparable {
+ /**
+ * Json keys for ForcedRoot. Use {@link #keys()} to access singleton.
+ */
+ @ProviderType
+ public interface JsonKeys {
+ String path();
+
+ String primaryType();
+
+ String mixinTypes();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String path() {
+ return "path";
+ }
+
+ @Override
+ public String primaryType() {
+ return "primaryType";
+ }
+
+ @Override
+ public String mixinTypes() {
+ return "mixinTypes";
+ }
+ };
+
+ @NotNull
+ public static ForcedRoot.JsonKeys keys() {
+ return KEYS;
+ }
@Nullable
private String path;
@@ -51,6 +83,7 @@ public final class ForcedRoot implements JavaxJson.ObjectConvertible, Comparable
@NotNull
private List mixinTypes = Collections.emptyList();
+
public @Nullable String getPath() {
return path;
}
@@ -113,14 +146,15 @@ public final boolean hasPath() {
* @return a new forced root
*/
public static @NotNull ForcedRoot fromJson(final @NotNull JsonObject json) {
+ final JsonKeys keys = keys();
final ForcedRoot forcedRoot = new ForcedRoot();
- if (json.containsKey(KEY_PATH)) {
- forcedRoot.setPath(json.getString(KEY_PATH));
+ if (json.containsKey(keys.path())) {
+ forcedRoot.setPath(json.getString(keys.path()));
}
- if (json.containsKey(KEY_PRIMARY_TYPE)) {
- forcedRoot.setPrimaryType(json.getString(KEY_PRIMARY_TYPE));
+ if (json.containsKey(keys.primaryType())) {
+ forcedRoot.setPrimaryType(json.getString(keys.primaryType()));
}
- optArray(json, KEY_MIXIN_TYPES).ifPresent(jsonArray -> {
+ optArray(json, keys.mixinTypes()).ifPresent(jsonArray -> {
forcedRoot.setMixinTypes(mapArrayOfStrings(jsonArray, Function.identity()));
});
return forcedRoot;
@@ -145,9 +179,10 @@ public final boolean hasPath() {
@Override
public JsonObject toJson() {
- return obj().key(KEY_PATH).opt(this.path)
- .key(KEY_PRIMARY_TYPE).opt(this.primaryType)
- .key(KEY_MIXIN_TYPES).opt(this.mixinTypes)
+ final JsonKeys keys = keys();
+ return obj().key(keys.path()).opt(this.path)
+ .key(keys.primaryType()).opt(this.primaryType)
+ .key(keys.mixinTypes()).opt(this.mixinTypes)
.get();
}
@@ -176,4 +211,6 @@ public int hashCode() {
public String toString() {
return toJson().toString();
}
+
+
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/InitStage.java b/core/src/main/java/net/adamcin/oakpal/core/InitStage.java
index d54eea136..6e11bfee9 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/InitStage.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/InitStage.java
@@ -23,9 +23,7 @@
import org.apache.jackrabbit.spi.QNodeTypeDefinition;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
-import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
import org.apache.jackrabbit.spi.commons.nodetype.NodeTypeDefinitionFactory;
-import org.apache.jackrabbit.spi.commons.privilege.PrivilegeDefinitionImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -47,15 +45,11 @@
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.mapEntry;
-import static net.adamcin.oakpal.core.Fun.onEntry;
-import static net.adamcin.oakpal.core.Fun.result1;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.uncheckVoid1;
+
+import static net.adamcin.oakpal.api.Fun.onEntry;
+import static net.adamcin.oakpal.api.Fun.result1;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.Fun.uncheckVoid1;
import static net.adamcin.oakpal.core.OakMachine.NT_UNDECLARED;
/**
diff --git a/core/src/main/java/net/adamcin/oakpal/core/JcrNs.java b/core/src/main/java/net/adamcin/oakpal/core/JcrNs.java
index 676d5da21..f021ec529 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/JcrNs.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/JcrNs.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,21 +16,47 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.JsonObjectConvertible;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
import javax.json.JsonObject;
import java.util.Objects;
import java.util.Optional;
-import static net.adamcin.oakpal.core.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.key;
/**
* Config DTO for JCR Namespace Prefix to URI Mappings.
*/
-public final class JcrNs implements JavaxJson.ObjectConvertible, Comparable {
- static final String KEY_PREFIX = "prefix";
- static final String KEY_URI = "uri";
+public final class JcrNs implements JsonObjectConvertible, Comparable {
+ /**
+ * Json keys for JcrNs. Use {@link #keys()} to access singleton.
+ */
+ @ProviderType
+ public interface JsonKeys {
+ String prefix();
+
+ String uri();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String prefix() {
+ return "prefix";
+ }
+
+ @Override
+ public String uri() {
+ return "uri";
+ }
+ };
+
+ @NotNull
+ public static JcrNs.JsonKeys keys() {
+ return KEYS;
+ }
private String prefix;
private String uri;
@@ -68,12 +94,12 @@ public void setUri(String uri) {
* @return a new JCR NS mapping
*/
public static @Nullable JcrNs fromJson(final @NotNull JsonObject json) {
- if (!json.containsKey(KEY_PREFIX) || !json.containsKey(KEY_URI)) {
+ if (!json.containsKey(KEYS.prefix()) || !json.containsKey(KEYS.uri())) {
return null;
}
JcrNs jcrNs = new JcrNs();
- jcrNs.setPrefix(json.getString(KEY_PREFIX, ""));
- jcrNs.setUri(json.getString(KEY_URI, ""));
+ jcrNs.setPrefix(json.getString(KEYS.prefix(), ""));
+ jcrNs.setUri(json.getString(KEYS.uri(), ""));
return jcrNs;
}
@@ -107,7 +133,8 @@ public int hashCode() {
@Override
public JsonObject toJson() {
- return key(KEY_PREFIX, getPrefix()).key(KEY_URI, getUri()).get();
+ final JsonKeys keys = keys();
+ return key(keys.prefix(), getPrefix()).key(keys.uri(), getUri()).get();
}
@Override
@@ -120,4 +147,6 @@ public int compareTo(final @NotNull JcrNs o) {
return Optional.of(getPrefix().compareTo(o.getPrefix()))
.filter(comp -> comp != 0).orElseGet(() -> getUri().compareTo(o.getUri()));
}
+
+
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/JsonCnd.java b/core/src/main/java/net/adamcin/oakpal/core/JsonCnd.java
index 892f5519d..138448112 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/JsonCnd.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/JsonCnd.java
@@ -16,6 +16,9 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.Fun;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.Result;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.commons.cnd.Lexer;
import org.apache.jackrabbit.commons.query.qom.Operator;
@@ -98,28 +101,28 @@
import java.util.stream.StreamSupport;
import static java.util.Optional.ofNullable;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.constantly1;
-import static net.adamcin.oakpal.core.Fun.inSet;
-import static net.adamcin.oakpal.core.Fun.inferTest1;
-import static net.adamcin.oakpal.core.Fun.mapEntry;
-import static net.adamcin.oakpal.core.Fun.mapKey;
-import static net.adamcin.oakpal.core.Fun.mapValue;
-import static net.adamcin.oakpal.core.Fun.onEntry;
-import static net.adamcin.oakpal.core.Fun.testKey;
-import static net.adamcin.oakpal.core.Fun.testValue;
-import static net.adamcin.oakpal.core.Fun.toEntry;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.uncheck2;
-import static net.adamcin.oakpal.core.Fun.uncheckVoid1;
-import static net.adamcin.oakpal.core.Fun.uncheckVoid2;
-import static net.adamcin.oakpal.core.Fun.zipKeysWithValueFunc;
-import static net.adamcin.oakpal.core.JavaxJson.JSON_VALUE_STRING;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfStrings;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
-import static net.adamcin.oakpal.core.JavaxJson.unwrap;
-import static net.adamcin.oakpal.core.JavaxJson.wrap;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.constantly1;
+import static net.adamcin.oakpal.api.Fun.inSet;
+import static net.adamcin.oakpal.api.Fun.inferTest1;
+import static net.adamcin.oakpal.api.Fun.mapEntry;
+import static net.adamcin.oakpal.api.Fun.mapKey;
+import static net.adamcin.oakpal.api.Fun.mapValue;
+import static net.adamcin.oakpal.api.Fun.onEntry;
+import static net.adamcin.oakpal.api.Fun.testKey;
+import static net.adamcin.oakpal.api.Fun.testValue;
+import static net.adamcin.oakpal.api.Fun.toEntry;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.Fun.uncheck2;
+import static net.adamcin.oakpal.api.Fun.uncheckVoid1;
+import static net.adamcin.oakpal.api.Fun.uncheckVoid2;
+import static net.adamcin.oakpal.api.Fun.zipKeysWithValueFunc;
+import static net.adamcin.oakpal.api.JavaxJson.JSON_VALUE_STRING;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfStrings;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static net.adamcin.oakpal.api.JavaxJson.optArray;
+import static net.adamcin.oakpal.api.JavaxJson.unwrap;
+import static net.adamcin.oakpal.api.JavaxJson.wrap;
/**
* Methods and types used to encode/decode QNodeTypeDefinitions as JSON for use in checklists.
diff --git a/core/src/main/java/net/adamcin/oakpal/core/Locator.java b/core/src/main/java/net/adamcin/oakpal/core/Locator.java
index ade839093..10bf54b02 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/Locator.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/Locator.java
@@ -16,6 +16,9 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+
import javax.json.JsonObject;
import javax.json.JsonValue;
import java.net.URL;
@@ -163,6 +166,5 @@ public static List loadFromCheckSpecs(final List check
}
}
return allChecks;
-
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/NamespaceMappingRequest.java b/core/src/main/java/net/adamcin/oakpal/core/NamespaceMappingRequest.java
index 46b24df26..68333bc96 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/NamespaceMappingRequest.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/NamespaceMappingRequest.java
@@ -1,5 +1,6 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.Result;
import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
@@ -12,8 +13,8 @@
import java.util.Set;
import java.util.stream.Collectors;
-import static net.adamcin.oakpal.core.Fun.inSet;
-import static net.adamcin.oakpal.core.Fun.result1;
+import static net.adamcin.oakpal.api.Fun.inSet;
+import static net.adamcin.oakpal.api.Fun.result1;
/**
* Given all the JCR namespace gymnastics that have to be performed for {@link JsonCnd} and webster, dealing with
diff --git a/core/src/main/java/net/adamcin/oakpal/core/OakMachine.java b/core/src/main/java/net/adamcin/oakpal/core/OakMachine.java
index 21d59eca4..12947a1c0 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/OakMachine.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/OakMachine.java
@@ -16,6 +16,9 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.Fun;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.JackrabbitRepository;
import org.apache.jackrabbit.commons.cnd.DefinitionBuilderFactory;
@@ -74,8 +77,8 @@
import java.util.jar.Manifest;
import java.util.stream.Collectors;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.uncheckVoid1;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.Fun.uncheckVoid1;
/**
* Entry point for OakPAL Acceptance Library. See {@link ProgressCheck} for the event listener interface.
@@ -468,7 +471,7 @@ public interface InspectBody {
}
/**
- * Functional interface for {@link Builder#withSubpackageSilencer(SubpackageSilencer)}.
+ * Functional interface for {@code Builder.withSubpackageSilencer(SubpackageSilencer)}.
*/
@FunctionalInterface
public interface SubpackageSilencer extends BiPredicate {
@@ -936,7 +939,7 @@ public void onMessage(Mode mode, String action, String path) {
Node node = session.getNode(path);
handlers.forEach(handler -> {
try {
- handler.importedPath(packageId, path, node);
+ handler.importedPath(packageId, path, node, PathAction.fromShortCode(action));
} catch (final Exception e) {
OakMachine.this.getErrorListener().onListenerPathException(e, handler, packageId, path);
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/OakpalPlan.java b/core/src/main/java/net/adamcin/oakpal/core/OakpalPlan.java
index 56020b14a..9697480a7 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/OakpalPlan.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/OakpalPlan.java
@@ -1,11 +1,18 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.Fun;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.JsonObjectConvertible;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.api.ViolationReporter;
import org.apache.jackrabbit.spi.PrivilegeDefinition;
import org.apache.jackrabbit.spi.QNodeTypeDefinition;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
import org.apache.jackrabbit.util.Text;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -18,14 +25,16 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Optional;
+import java.util.ResourceBundle;
import java.util.stream.Collectors;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.inferTest1;
-import static net.adamcin.oakpal.core.Fun.result1;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.inferTest1;
+import static net.adamcin.oakpal.api.Fun.result1;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
/**
* A plan is a reproducible execution plan, similar in design to a Checklist, but with the following differences:
@@ -34,7 +43,80 @@
* 3. Can reference pre-install packages by URL.
* 4. Can not aggregate multiple plans per execution.
*/
-public final class OakpalPlan implements JavaxJson.ObjectConvertible {
+public final class OakpalPlan implements JsonObjectConvertible {
+ @ProviderType
+ public interface JsonKeys {
+ String checklists();
+
+ String checks();
+
+ String forcedRoots();
+
+ String jcrNamespaces();
+
+ String jcrNodetypes();
+
+ String jcrPrivileges();
+
+ String preInstallUrls();
+
+ String enablePreInstallHooks();
+
+ String installHookPolicy();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String checklists() {
+ return "checklists";
+ }
+
+ @Override
+ public String checks() {
+ return "checks";
+ }
+
+ @Override
+ public String forcedRoots() {
+ return "forcedRoots";
+ }
+
+ @Override
+ public String jcrNamespaces() {
+ return "jcrNamespaces";
+ }
+
+ @Override
+ public String jcrNodetypes() {
+ return "jcrNodetypes";
+ }
+
+ @Override
+ public String jcrPrivileges() {
+ return "jcrPrivileges";
+ }
+
+ @Override
+ public String preInstallUrls() {
+ return "preInstallUrls";
+ }
+
+ @Override
+ public String enablePreInstallHooks() {
+ return "enablePreInstallHooks";
+ }
+
+ @Override
+ public String installHookPolicy() {
+ return "installHookPolicy";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
private static final Logger LOGGER = LoggerFactory.getLogger(OakpalPlan.class);
/**
* Preferred default plan when a custom classpath is specified without specifying a plan name. This is also
@@ -55,16 +137,6 @@ public final class OakpalPlan implements JavaxJson.ObjectConvertible {
*/
public static final String DEFAULT_PLAN_NAME = "plan.json";
- public static final String KEY_CHECKLISTS = "checklists";
- public static final String KEY_CHECKS = "checks";
- public static final String KEY_FORCED_ROOTS = "forcedRoots";
- public static final String KEY_JCR_NAMESPACES = "jcrNamespaces";
- public static final String KEY_JCR_NODETYPES = "jcrNodetypes";
- public static final String KEY_JCR_PRIVILEGES = "jcrPrivileges";
- public static final String KEY_PREINSTALL_URLS = "preInstallUrls";
- public static final String KEY_ENABLE_PRE_INSTALL_HOOKS = "enablePreInstallHooks";
- public static final String KEY_INSTALL_HOOK_POLICY = "installHookPolicy";
-
private final URL base;
private final String name;
private final JsonObject originalJson;
@@ -190,15 +262,15 @@ public JsonObject toJson() {
final NamespaceMapping mapping = JsonCnd.toNamespaceMapping(jcrNamespaces);
return JavaxJson.obj()
- .key(KEY_PREINSTALL_URLS).opt(preInstallStrings)
- .key(KEY_CHECKLISTS).opt(checklists)
- .key(KEY_CHECKS).opt(checks)
- .key(KEY_FORCED_ROOTS).opt(forcedRoots)
- .key(KEY_JCR_NODETYPES).opt(JsonCnd.toJson(jcrNodetypes, mapping))
- .key(KEY_JCR_PRIVILEGES).opt(JsonCnd.privilegesToJson(jcrPrivileges, mapping))
- .key(KEY_JCR_NAMESPACES).opt(jcrNamespaces)
- .key(KEY_ENABLE_PRE_INSTALL_HOOKS).opt(enablePreInstallHooks, false)
- .key(KEY_INSTALL_HOOK_POLICY).opt(installHookPolicy)
+ .key(keys().preInstallUrls()).opt(preInstallStrings)
+ .key(keys().checklists()).opt(checklists)
+ .key(keys().checks()).opt(checks)
+ .key(keys().forcedRoots()).opt(forcedRoots)
+ .key(keys().jcrNodetypes()).opt(JsonCnd.toJson(jcrNodetypes, mapping))
+ .key(keys().jcrPrivileges()).opt(JsonCnd.privilegesToJson(jcrPrivileges, mapping))
+ .key(keys().jcrNamespaces()).opt(jcrNamespaces)
+ .key(keys().enablePreInstallHooks()).opt(enablePreInstallHooks, false)
+ .key(keys().installHookPolicy()).opt(installHookPolicy)
.get();
}
@@ -236,6 +308,11 @@ public OakMachine.Builder toOakMachineBuilder(final @Nullable ErrorListener erro
throw new Exception("Error while loading progress checks.", e);
}
+ final Locale locale = Locale.getDefault();
+ for (final ProgressCheck progressCheck : allChecks) {
+ initResourceBundle(progressCheck, locale, classLoader);
+ }
+
return new OakMachine.Builder()
.withErrorListener(errorListener)
.withProgressChecks(allChecks)
@@ -247,43 +324,51 @@ public OakMachine.Builder toOakMachineBuilder(final @Nullable ErrorListener erro
.withEnablePreInstallHooks(enablePreInstallHooks);
}
+ void initResourceBundle(final ViolationReporter reporter, final Locale locale, final ClassLoader classLoader) {
+ if (reporter.getResourceBundleBaseName() != null) {
+ Fun.result0(() -> ResourceBundle
+ .getBundle(reporter.getResourceBundleBaseName(), locale, classLoader)).get()
+ .forEach(reporter::setResourceBundle);
+ }
+ }
private static OakpalPlan fromJson(final @NotNull Builder builder,
final @NotNull JsonObject json) {
- if (hasNonNull(json, KEY_PREINSTALL_URLS) && builder.base != null) {
- builder.withPreInstallUrls(JavaxJson.mapArrayOfStrings(json.getJsonArray(KEY_PREINSTALL_URLS),
+ if (hasNonNull(json, keys().preInstallUrls()) && builder.base != null) {
+ builder.withPreInstallUrls(JavaxJson.mapArrayOfStrings(json.getJsonArray(keys().preInstallUrls()),
uncheck1(url -> new URL(builder.base, url))));
}
- if (hasNonNull(json, KEY_CHECKLISTS)) {
- builder.withChecklists(JavaxJson.mapArrayOfStrings(json.getJsonArray(KEY_CHECKLISTS)));
+ if (hasNonNull(json, keys().checklists())) {
+ builder.withChecklists(JavaxJson.mapArrayOfStrings(json.getJsonArray(keys().checklists())));
}
- if (hasNonNull(json, KEY_CHECKS)) {
- builder.withChecks(JavaxJson.mapArrayOfObjects(json.getJsonArray(KEY_CHECKS), CheckSpec::fromJson));
+ if (hasNonNull(json, keys().checks())) {
+ builder.withChecks(JavaxJson.mapArrayOfObjects(json.getJsonArray(keys().checks()), CheckSpec::fromJson));
}
- if (hasNonNull(json, KEY_FORCED_ROOTS)) {
- builder.withForcedRoots(JavaxJson.mapArrayOfObjects(json.getJsonArray(KEY_FORCED_ROOTS), ForcedRoot::fromJson));
+ if (hasNonNull(json, keys().forcedRoots())) {
+ builder.withForcedRoots(JavaxJson.mapArrayOfObjects(json.getJsonArray(keys().forcedRoots()),
+ ForcedRoot::fromJson));
}
final NamespaceMapping mapping;
- if (hasNonNull(json, KEY_JCR_NAMESPACES)) {
- final List jcrNsList = JavaxJson.mapArrayOfObjects(json.getJsonArray(KEY_JCR_NAMESPACES),
+ if (hasNonNull(json, keys().jcrNamespaces())) {
+ final List jcrNsList = JavaxJson.mapArrayOfObjects(json.getJsonArray(keys().jcrNamespaces()),
JcrNs::fromJson);
mapping = JsonCnd.toNamespaceMapping(jcrNsList);
builder.withJcrNamespaces(jcrNsList);
} else {
mapping = JsonCnd.BUILTIN_MAPPINGS;
}
- if (hasNonNull(json, KEY_JCR_NODETYPES)) {
- builder.withJcrNodetypes(JsonCnd.getQTypesFromJson(json.getJsonObject(KEY_JCR_NODETYPES), mapping));
+ if (hasNonNull(json, keys().jcrNodetypes())) {
+ builder.withJcrNodetypes(JsonCnd.getQTypesFromJson(json.getJsonObject(keys().jcrNodetypes()), mapping));
}
- if (hasNonNull(json, KEY_JCR_PRIVILEGES)) {
- builder.withJcrPrivileges(JsonCnd.getPrivilegesFromJson(json.get(KEY_JCR_PRIVILEGES), mapping));
+ if (hasNonNull(json, keys().jcrPrivileges())) {
+ builder.withJcrPrivileges(JsonCnd.getPrivilegesFromJson(json.get(keys().jcrPrivileges()), mapping));
}
- if (hasNonNull(json, KEY_ENABLE_PRE_INSTALL_HOOKS)) {
- builder.withEnablePreInstallHooks(json.getBoolean(KEY_ENABLE_PRE_INSTALL_HOOKS));
+ if (hasNonNull(json, keys().enablePreInstallHooks())) {
+ builder.withEnablePreInstallHooks(json.getBoolean(keys().enablePreInstallHooks()));
}
- if (hasNonNull(json, KEY_INSTALL_HOOK_POLICY)) {
+ if (hasNonNull(json, keys().installHookPolicy())) {
builder.withInstallHookPolicy(InstallHookPolicy.forName(
- json.getString(KEY_INSTALL_HOOK_POLICY)));
+ json.getString(keys().installHookPolicy())));
}
return builder.build(json);
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/ProgressCheckAliasFacade.java b/core/src/main/java/net/adamcin/oakpal/core/ProgressCheckAliasFacade.java
index 4ee7c05de..2296f173f 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/ProgressCheckAliasFacade.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/ProgressCheckAliasFacade.java
@@ -16,6 +16,10 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
@@ -28,6 +32,7 @@
import java.io.File;
import java.util.Collection;
import java.util.List;
+import java.util.ResourceBundle;
import java.util.jar.Manifest;
/**
@@ -55,6 +60,16 @@ public String getCheckName() {
}
}
+ @Override
+ public @Nullable String getResourceBundleBaseName() {
+ return wrapped.getResourceBundleBaseName();
+ }
+
+ @Override
+ public void setResourceBundle(final ResourceBundle resourceBundle) {
+ wrapped.setResourceBundle(resourceBundle);
+ }
+
@Override
public void startedScan() {
wrapped.startedScan();
@@ -88,8 +103,9 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
}
@Override
- public void importedPath(final PackageId packageId, final String path, final Node node) throws RepositoryException {
- wrapped.importedPath(packageId, path, node);
+ public void importedPath(final PackageId packageId, final String path, final Node node,
+ final PathAction action) throws RepositoryException {
+ wrapped.importedPath(packageId, path, node, action);
}
@Override
diff --git a/core/src/main/java/net/adamcin/oakpal/core/ReportMapper.java b/core/src/main/java/net/adamcin/oakpal/core/ReportMapper.java
index 750786b03..59ed7f72b 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/ReportMapper.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/ReportMapper.java
@@ -16,7 +16,10 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.json.Json;
import javax.json.JsonArray;
@@ -39,20 +42,43 @@
import java.util.Collections;
import java.util.List;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfObjects;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfObjects;
+import static net.adamcin.oakpal.api.JavaxJson.optArray;
/**
* Serialize violations to/from json.
*/
public final class ReportMapper {
- public static final String KEY_REPORTS = "reports";
- public static final String KEY_CHECK_NAME = "checkName";
- public static final String KEY_VIOLATIONS = "violations";
- public static final String KEY_DESCRIPTION = "description";
- public static final String KEY_SEVERITY = "severity";
- public static final String KEY_PACKAGES = "packages";
+ @ProviderType
+ public interface JsonKeys {
+ String reports();
+
+ String checkName();
+
+ String violations();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String reports() {
+ return "reports";
+ }
+
+ @Override
+ public String checkName() {
+ return "checkName";
+ }
+
+ @Override
+ public String violations() {
+ return "violations";
+ }
+ };
+
+ public static JsonKeys keys() {
+ return KEYS;
+ }
private ReportMapper() {
/* No instantiation */
@@ -61,6 +87,7 @@ private ReportMapper() {
/**
* Functional interface that indicates that the consuming method will open AND close the stream for reading.
*/
+ @ProviderType
@FunctionalInterface
public interface ReaderSupplier {
Reader open() throws IOException;
@@ -69,6 +96,7 @@ public interface ReaderSupplier {
/**
* Functional interface that indicates that the consuming method will open AND close the stream for writing.
*/
+ @ProviderType
@FunctionalInterface
public interface WriterSupplier {
Writer open() throws IOException;
@@ -87,7 +115,7 @@ public static List readReports(final @NotNull ReaderSupplier reader
JsonObject json = jsonReader.readObject();
- List reports = optArray(json, KEY_REPORTS)
+ List reports = optArray(json, keys().reports())
.map(jsonReports -> mapArrayOfObjects(jsonReports, ReportMapper::reportFromJson))
.orElseGet(Collections::emptyList);
@@ -142,12 +170,13 @@ public static JsonArray reportsToJson(final @NotNull Collection rep
}
/**
- * Transforms a collection of CheckReports to a JsonArray assigned to a key {@link #KEY_REPORTS} in an outer object.
+ * Transforms a collection of CheckReports to a JsonArray assigned to a key {@link JsonKeys#reports()} in
+ * an outer object.
*
* @param reports the reports to serialize
* @return a JsonObject with a JsonArray of CheckReport json objects
*/
public static JsonObject reportsToJsonObject(final @NotNull Collection reports) {
- return key(KEY_REPORTS, reportsToJson(reports)).get();
+ return key(keys().reports(), reportsToJson(reports)).get();
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/ScriptProgressCheck.java b/core/src/main/java/net/adamcin/oakpal/core/ScriptProgressCheck.java
index e6483986c..62150a7c5 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/ScriptProgressCheck.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/ScriptProgressCheck.java
@@ -16,6 +16,15 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.ReportCollector;
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
@@ -43,6 +52,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.ResourceBundle;
import java.util.Set;
import java.util.jar.Manifest;
@@ -64,8 +74,8 @@
* {@link ProgressCheck#identifySubpackage(PackageId, PackageId)}
* beforeExtract(packageId, inspectSession, packageProperties, metaInf, subpackageIds)
* {@link ProgressCheck#beforeExtract(PackageId, Session, PackageProperties, MetaInf, List)}
- * importedPath(packageId, path, node)
- * {@link ProgressCheck#importedPath(PackageId, String, Node)}
+ * importedPath(packageId, path, node, action)
+ * {@link ProgressCheck#importedPath(PackageId, String, Node, PathAction)}
* deletedPath(packageId, path, inspectSession)
* {@link ProgressCheck#deletedPath(PackageId, String, Session)}
* afterExtract(packageId, inspectSession)
@@ -105,19 +115,38 @@ public final class ScriptProgressCheck implements ProgressCheck {
this.scriptUrl = scriptUrl;
}
- private String getFilename() {
+ @Override
+ public @Nullable String getResourceBundleBaseName() {
+ return null;
+ }
+
+ @Override
+ public void setResourceBundle(final ResourceBundle resourceBundle) {
+ this.helper.setResourceBundle(resourceBundle);
+ }
+
+ ScriptHelper getHelper() {
+ return helper;
+ }
+
+ private String getScriptPath() {
if (this.scriptUrl != null) {
- final int lastSlash = this.scriptUrl.getPath().lastIndexOf("/");
- if (lastSlash >= 0 && this.scriptUrl.getPath().length() > lastSlash + 1) {
- return this.scriptUrl.getPath().substring(lastSlash + 1);
- } else {
- return this.scriptUrl.getPath();
- }
+ return this.scriptUrl.getPath();
} else {
return FILENAME_INLINE_SCRIPT;
}
}
+ private String getFilename() {
+ final String scriptPath = this.getScriptPath();
+ final int lastSlash = scriptPath.lastIndexOf("/");
+ if (lastSlash >= 0 && scriptPath.length() > lastSlash + 1) {
+ return scriptPath.substring(lastSlash + 1);
+ } else {
+ return scriptPath;
+ }
+ }
+
@Override
public String getCheckName() {
try {
@@ -224,8 +253,9 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
}
@Override
- public void importedPath(final PackageId packageId, final String path, final Node node) throws RepositoryException {
- guardSessionHandler(INVOKE_ON_IMPORTED_PATH, handle -> handle.apply(packageId, path, node));
+ public void importedPath(final PackageId packageId, final String path, final Node node,
+ final PathAction action) throws RepositoryException {
+ guardSessionHandler(INVOKE_ON_IMPORTED_PATH, handle -> handle.apply(packageId, path, node, action));
}
@Override
@@ -255,17 +285,30 @@ public final Collection getReportedViolations() {
@SuppressWarnings("WeakerAccess")
public static class ScriptHelper {
private final ReportCollector collector = new ReportCollector();
+ private ResourceBundle resourceBundle;
public void minorViolation(String description, PackageId... packageIds) {
- collector.reportViolation(new SimpleViolation(Violation.Severity.MINOR, description, packageIds));
+ collector.reportViolation(new SimpleViolation(Severity.MINOR, description, packageIds));
}
public void majorViolation(String description, PackageId... packageIds) {
- collector.reportViolation(new SimpleViolation(Violation.Severity.MAJOR, description, packageIds));
+ collector.reportViolation(new SimpleViolation(Severity.MAJOR, description, packageIds));
}
public void severeViolation(String description, PackageId... packageIds) {
- collector.reportViolation(new SimpleViolation(Violation.Severity.SEVERE, description, packageIds));
+ collector.reportViolation(new SimpleViolation(Severity.SEVERE, description, packageIds));
+ }
+
+ private void setResourceBundle(final ResourceBundle resourceBundle) {
+ this.resourceBundle = resourceBundle;
+ }
+
+ public String getString(final String key) {
+ if (key != null && resourceBundle != null && resourceBundle.containsKey(key)) {
+ return resourceBundle.getString(key);
+ } else {
+ return key;
+ }
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/SimpleProgressCheck.java b/core/src/main/java/net/adamcin/oakpal/core/SimpleProgressCheck.java
deleted file mode 100644
index e419ae99b..000000000
--- a/core/src/main/java/net/adamcin/oakpal/core/SimpleProgressCheck.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2018 Mark Adamcin
- *
- * Licensed 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 net.adamcin.oakpal.core;
-
-import org.apache.jackrabbit.vault.packaging.PackageId;
-
-import java.util.Collection;
-
-/**
- * Simple implementation of a {@link ProgressCheck} with convenient methods for reporting and collecting violations.
- */
-public class SimpleProgressCheck implements ProgressCheck {
- protected final ReportCollector collector = new ReportCollector();
-
- protected void reportViolation(final Violation violation) {
- collector.reportViolation(violation);
- }
-
- protected final void reportViolation(final Violation.Severity severity,
- final String description,
- final PackageId... packages) {
- this.reportViolation(new SimpleViolation(severity, description, packages));
- }
-
- protected final void minorViolation(final String description, final PackageId... packages) {
- this.reportViolation(new SimpleViolation(Violation.Severity.MINOR, description, packages));
- }
-
- protected final void majorViolation(final String description, final PackageId... packages) {
- this.reportViolation(new SimpleViolation(Violation.Severity.MAJOR, description, packages));
- }
-
- protected final void severeViolation(final String description, final PackageId... packages) {
- this.reportViolation(new SimpleViolation(Violation.Severity.SEVERE, description, packages));
- }
-
- @Override
- public void startedScan() {
- collector.clearViolations();
- }
-
- @Override
- public Collection getReportedViolations() {
- return collector.getReportedViolations();
- }
-}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/SimpleReport.java b/core/src/main/java/net/adamcin/oakpal/core/SimpleReport.java
index 9b514f9cb..05e852234 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/SimpleReport.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/SimpleReport.java
@@ -16,6 +16,9 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
import org.jetbrains.annotations.NotNull;
import javax.json.JsonObject;
@@ -27,10 +30,8 @@
import java.util.Optional;
import java.util.stream.Collectors;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfObjects;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_CHECK_NAME;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_VIOLATIONS;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfObjects;
+import static net.adamcin.oakpal.api.JavaxJson.optArray;
/**
* Simple POJO implementing a {@link CheckReport}, used for deserialization.
@@ -94,8 +95,8 @@ public static SimpleReport generateReport(final @NotNull ErrorListener reporter)
}
public static SimpleReport fromJson(final @NotNull JsonObject jsonReport) {
- String vCheckName = jsonReport.getString(KEY_CHECK_NAME, "");
- List violations = optArray(jsonReport, KEY_VIOLATIONS)
+ String vCheckName = jsonReport.getString(CoreConstants.checkReportKeys().checkName(), "");
+ List violations = optArray(jsonReport, CoreConstants.checkReportKeys().violations())
.map(array -> mapArrayOfObjects(array, ReportMapper::violationFromJson))
.orElseGet(Collections::emptyList);
diff --git a/core/src/main/java/net/adamcin/oakpal/core/SimpleViolation.java b/core/src/main/java/net/adamcin/oakpal/core/SimpleViolation.java
deleted file mode 100644
index 65b297e4b..000000000
--- a/core/src/main/java/net/adamcin/oakpal/core/SimpleViolation.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2018 Mark Adamcin
- *
- * Licensed 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 net.adamcin.oakpal.core;
-
-import org.apache.jackrabbit.vault.packaging.PackageId;
-
-import javax.json.JsonObject;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfStrings;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_DESCRIPTION;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_PACKAGES;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_SEVERITY;
-
-/**
- * Simple implementation of a {@link Violation}.
- */
-public final class SimpleViolation implements Violation {
- private final Severity severity;
- private final String description;
- private final List packages;
-
- public SimpleViolation(final Severity severity, final String description, final PackageId... packages) {
- this(severity, description, packages != null ? Arrays.asList(packages) : null);
- }
-
- public SimpleViolation(final Severity severity, final String description, final List packages) {
- this.severity = severity;
- this.description = description;
- this.packages = Collections.unmodifiableList(
- packages != null ? new ArrayList<>(packages) : Collections.emptyList());
- }
-
- @Override
- public Severity getSeverity() {
- return severity;
- }
-
- @Override
- public Collection getPackages() {
- return packages;
- }
-
- @Override
- public String getDescription() {
- return description;
- }
-
- public static SimpleViolation fromReported(final Violation violation) {
- Severity severity = violation.getSeverity();
- String description = violation.getDescription();
- List packages = new ArrayList<>(violation.getPackages());
- return new SimpleViolation(severity, description, packages);
- }
-
- public static SimpleViolation fromJson(final JsonObject jsonViolation) {
- String vSeverity = jsonViolation.getString(KEY_SEVERITY, Violation.Severity.MINOR.name());
- Violation.Severity severity = Violation.Severity.valueOf(vSeverity);
- String description = jsonViolation.getString(KEY_DESCRIPTION, "");
- List packages = optArray(jsonViolation, KEY_PACKAGES)
- .map(array -> mapArrayOfStrings(array, PackageId::fromString, true))
- .orElseGet(Collections::emptyList);
-
- return new SimpleViolation(severity, description, packages);
- }
-
- @Override
- public String toString() {
- return "SimpleViolation{" +
- "severity=" + severity +
- ", description='" + description + '\'' +
- ", packages=" + packages +
- '}';
- }
-
- @Override
- public boolean equals(final Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- SimpleViolation that = (SimpleViolation) o;
- return severity == that.severity &&
- Objects.equals(description, that.description) &&
- packages.equals(that.packages);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(severity, description, packages);
- }
-}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/Util.java b/core/src/main/java/net/adamcin/oakpal/core/Util.java
index 854069107..d5f56cf73 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/Util.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/Util.java
@@ -19,6 +19,7 @@
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Domain;
+import net.adamcin.oakpal.api.Fun;
import net.adamcin.oakpal.core.jcrfacade.SessionFacade;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
diff --git a/core/src/main/java/net/adamcin/oakpal/core/Violation.java b/core/src/main/java/net/adamcin/oakpal/core/Violation.java
deleted file mode 100644
index 62984c1cd..000000000
--- a/core/src/main/java/net/adamcin/oakpal/core/Violation.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2018 Mark Adamcin
- *
- * Licensed 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 net.adamcin.oakpal.core;
-
-import aQute.bnd.annotation.ConsumerType;
-import org.apache.jackrabbit.vault.packaging.PackageId;
-import org.jetbrains.annotations.NotNull;
-
-import javax.json.JsonObject;
-import java.util.Collection;
-import java.util.function.Predicate;
-
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_DESCRIPTION;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_PACKAGES;
-import static net.adamcin.oakpal.core.ReportMapper.KEY_SEVERITY;
-
-/**
- * Report type for validations.
- */
-@ConsumerType
-public interface Violation extends JavaxJson.ObjectConvertible {
-
- /**
- * Levels of severity for violations detected during package scans.
- */
- enum Severity {
- /**
- * Unlikely to disrupt application functionality. Appropriate for reporting violations of
- * code or style conventions, or inconsistency between modes of installation.
- */
- MINOR(2),
-
- /**
- * Likely to be the source of component instability. Appropriate for importer errors, mistaken
- * assumptions about root path dependencies or namespaces, or failures related to unit testing of
- * application packages.
- */
- MAJOR(1),
-
- /**
- * Likely to be the source of platform instability. Appropriate for reporting cross-package filter
- * overlap, destructive ACL handling modes, destruction of authorable content, or security violations.
- */
- SEVERE(0);
-
- private final int ordinal;
-
- Severity(int ordinal) {
- this.ordinal = ordinal;
- }
-
- /**
- * Runtime throwing function to lookup severity codes by name.
- *
- * @param name the severity level name
- * @return the associated severity level
- */
- public static Severity byName(final @NotNull String name) {
- for (Severity value : values()) {
- if (value.name().equalsIgnoreCase(name)) {
- return value;
- }
- }
- throw new IllegalArgumentException("Unknown severity level: " + name);
- }
-
- public boolean isLessSevereThan(Severity other) {
- return this.ordinal > other.ordinal;
- }
-
- public Predicate meetsMinimumSeverity() {
- return other -> !other.isLessSevereThan(this);
- }
-
- public Severity maxSeverity(final @NotNull Severity other) {
- return this.isLessSevereThan(other) ? other : this;
- }
- }
-
- /**
- * Describe the severity of the violation.
- *
- * @return the severity of the violation
- */
- Severity getSeverity();
-
- /**
- * Provides a list of one or more Packages responsible for the violation.
- *
- * @return a list of package IDs responsible for the violation.
- */
- Collection getPackages();
-
- /**
- * Describes the nature of the violation.
- *
- * @return the description
- */
- String getDescription();
-
- /**
- * Serializes the Violation to a JsonObject.
- *
- * @return the json representation of the violation
- */
- @Override
- default JsonObject toJson() {
- return obj()
- .key(KEY_SEVERITY).opt(this.getSeverity())
- .key(KEY_DESCRIPTION).opt(this.getDescription())
- .key(KEY_PACKAGES).opt(this.getPackages()).get();
- }
-}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/AcHandling.java b/core/src/main/java/net/adamcin/oakpal/core/checks/AcHandling.java
index 8e2ed1305..4c1882c4e 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/AcHandling.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/AcHandling.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,15 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -33,10 +34,10 @@
import java.util.List;
import static java.util.Optional.ofNullable;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfStrings;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfStrings;
import static org.apache.jackrabbit.vault.fs.io.AccessControlHandling.IGNORE;
import static org.apache.jackrabbit.vault.fs.io.AccessControlHandling.MERGE;
import static org.apache.jackrabbit.vault.fs.io.AccessControlHandling.MERGE_PRESERVE;
@@ -69,18 +70,44 @@
*
*/
public final class AcHandling implements ProgressCheckFactory {
- public static final String CONFIG_ALLOWED_MODES = "allowedModes";
- public static final String CONFIG_LEVEL_SET = "levelSet";
+ @ProviderType
+ public interface JsonKeys {
+ String allowedModes();
+
+ String levelSet();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String allowedModes() {
+ return "allowedModes";
+ }
+
+ @Override
+ public String levelSet() {
+ return "levelSet";
+ }
+ };
+
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_ALLOWED_MODES = keys().allowedModes();
+ @Deprecated
+ public static final String CONFIG_LEVEL_SET = keys().levelSet();
+
static final ACHandlingLevelSet DEFAULT_LEVEL_SET = ACHandlingLevelSet.NO_UNSAFE;
@Override
public ProgressCheck newInstance(final JsonObject config) {
- if (hasNonNull(config, CONFIG_ALLOWED_MODES)) {
- List allowedModes = mapArrayOfStrings(arrayOrEmpty(config, CONFIG_ALLOWED_MODES),
+ if (hasNonNull(config, keys().allowedModes())) {
+ List allowedModes = mapArrayOfStrings(arrayOrEmpty(config, keys().allowedModes()),
compose(String::toUpperCase, AccessControlHandling::valueOf), true);
return new Check(ACHandlingLevelSet.EXPLICIT, allowedModes);
- } else if (hasNonNull(config, CONFIG_LEVEL_SET)) {
- ACHandlingLevelSet levelSet = ACHandlingLevelSet.valueOf(config.getString(CONFIG_LEVEL_SET).toUpperCase());
+ } else if (hasNonNull(config, keys().levelSet())) {
+ ACHandlingLevelSet levelSet = ACHandlingLevelSet.valueOf(config.getString(keys().levelSet()).toUpperCase());
return new Check(levelSet, Collections.emptyList());
} else {
return new Check(DEFAULT_LEVEL_SET, Collections.emptyList());
@@ -129,21 +156,17 @@ public List getAllowedModes() {
}
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
final ACHandlingLevelSet levelSet;
final List allowedModes;
Check(final ACHandlingLevelSet levelSet,
final List allowedModes) {
+ super(AcHandling.class);
this.levelSet = levelSet;
this.allowedModes = allowedModes;
}
- @Override
- public String getCheckName() {
- return AcHandling.class.getSimpleName();
- }
-
@Override
public void beforeExtract(final PackageId packageId, final Session inspectSession,
final PackageProperties packageProperties, final MetaInf metaInf,
@@ -155,16 +178,19 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
AccessControlHandling packageMode = ofNullable(packageProperties.getACHandling()).orElse(IGNORE);
if (this.levelSet == ACHandlingLevelSet.EXPLICIT) {
if (!allowedModes.contains(packageMode)) {
- reportViolation(Violation.Severity.MAJOR,
- String.format("acHandling mode %s is forbidden. acHandling values in allowedModes are %s",
- packageMode, allowedModes), packageId);
+ reporting(builder -> builder
+ .withSeverity(Severity.MAJOR)
+ .withDescription("acHandling mode {0} is forbidden. acHandling values in allowedModes are {1}")
+ .withArgument(packageMode, allowedModes)
+ .withPackage(packageId));
}
} else {
if (!this.levelSet.getAllowedModes().contains(packageMode)) {
- reportViolation(Violation.Severity.MAJOR,
- String.format("acHandling mode %s is forbidden. allowed acHandling values in levelSet:%s are %s",
- packageMode, this.levelSet.name().toLowerCase(), this.levelSet.getAllowedModes()),
- packageId);
+ reporting(builder -> builder
+ .withSeverity(Severity.MAJOR)
+ .withDescription("acHandling mode {0} is forbidden. allowed acHandling values in levelSet:{1} are {2}")
+ .withArgument(packageMode, this.levelSet.name().toLowerCase(), this.levelSet.getAllowedModes())
+ .withPackage(packageId));
}
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.java b/core/src/main/java/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.java
new file mode 100644
index 000000000..9db832148
--- /dev/null
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.java
@@ -0,0 +1,249 @@
+/*
+ * #%L
+ * ACS AEM Commons Bundle
+ * %%
+ * Copyright (C) 2013 - 2019 Adobe
+ * %%
+ * Licensed 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.
+ * #L%
+ */
+package net.adamcin.oakpal.core.checks;
+
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
+import org.apache.jackrabbit.oak.spi.mount.Mount;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.apache.jackrabbit.vault.packaging.registry.impl.JcrPackageRegistry;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+
+/**
+ * Report packages which affect paths in more than one composite node store.
+ * {@code config} items:
+ *
+ * - {@code severity}
+ * - (default: {@link Severity#MAJOR}) specify the severity of violations reported
+ * by this check.
+ * - {@code scopePackageIds} ({@link Rule[]})
+ * - (default: include all) List of scope rules matching PackageId values (group:name:version) for inclusion in the scope for
+ * composite store alignment check.
+ * - {@code mounts} ({@code {"name": "path1" [, "path2", ...] }} )
+ * - (default: {@code {"apps": ["/apps", "/libs"]}}) In a JSON Object, define a named {@link Mount} for each key,
+ * with the list of paths to assign to the mount. The default mount (named {@code }) is implicitly defined and
+ * cannot be overridden. By default, this value is configured to simulate future standard oak deployments where the /apps
+ * and /libs root paths are mounted from a separate read-only node store at runtime.
+ * .
+ *
+ */
+public final class CompositeStoreAlignment implements ProgressCheckFactory {
+ @ProviderType
+ public interface JsonKeys {
+ String severity();
+
+ String scopePackageIds();
+
+ String mounts();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String severity() {
+ return "severity";
+ }
+
+ @Override
+ public String scopePackageIds() {
+ return "scopePackageIds";
+ }
+
+ @Override
+ public String mounts() {
+ return "mounts";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_SEVERITY = keys().severity();
+ @Deprecated
+ public static final String CONFIG_SCOPE_PACKAGE_IDS = keys().scopePackageIds();
+ @Deprecated
+ public static final String CONFIG_MOUNTS = keys().mounts();
+
+ @Override
+ public ProgressCheck newInstance(final JsonObject config) throws Exception {
+ final Severity severity = Severity.valueOf(config.getString(keys().severity(),
+ Severity.MAJOR.name()).toUpperCase());
+ final List scopePackageIds = Rule.fromJsonArray(arrayOrEmpty(config, keys().scopePackageIds()));
+ final MountInfoProvider defaultProvider = Mounts.defaultMountInfoProvider();
+ final MountInfoProvider configProvider;
+ if (config.containsKey(keys().mounts())) {
+ Mounts.Builder builder = Mounts.newBuilder();
+ final JsonObject mountsObj = config.getJsonObject(keys().mounts());
+ for (Map.Entry mountEntry : mountsObj.entrySet()) {
+ if (defaultProvider.getDefaultMount().getName().equals(mountEntry.getKey())) {
+ continue;
+ }
+ if (mountEntry.getValue().getValueType() == JsonValue.ValueType.ARRAY) {
+ List paths = JavaxJson.mapArrayOfStrings(mountEntry.getValue().asJsonArray());
+ builder.mount(mountEntry.getKey(), paths.toArray(new String[0]));
+ } else if (mountEntry.getValue().getValueType() == JsonValue.ValueType.STRING) {
+ builder.mount(mountEntry.getKey(), ((JsonString) mountEntry.getValue()).getString());
+ }
+ }
+ configProvider = builder.build();
+ } else {
+ configProvider = Mounts.newBuilder().mount("apps", "/apps", "/libs").build();
+ }
+
+ return new Check(severity, scopePackageIds, configProvider);
+ }
+
+ static final class Check extends SimpleProgressCheckFactoryCheck {
+ private final Severity severity;
+ private final List scopePackageIds;
+ private final MountInfoProvider mounts;
+
+ private final Map> subPackages = new HashMap<>();
+ private final Map> affectedMounts = new HashMap<>();
+ private transient Set currentPackageMounts = new LinkedHashSet<>();
+
+ Check(final Severity severity, final List scopePackageIds, final MountInfoProvider mounts) {
+ super(CompositeStoreAlignment.class);
+ this.severity = severity;
+ this.scopePackageIds = scopePackageIds;
+ this.mounts = mounts;
+ }
+
+ @Override
+ public void identifyPackage(final PackageId packageId, final File file) {
+ subPackages.put(packageId, new ArrayList<>());
+ }
+
+ @Override
+ public void identifySubpackage(final PackageId packageId, final PackageId parentId) {
+ subPackages.put(packageId, new ArrayList<>());
+ subPackages.getOrDefault(parentId, Collections.emptyList()).add(packageId);
+ }
+
+ @Override
+ public void afterExtract(PackageId packageId, Session inspectSession) throws RepositoryException {
+ affectedMounts.put(packageId, new LinkedHashSet<>(currentPackageMounts));
+ currentPackageMounts.clear();
+ }
+
+ /**
+ * Always ignore:
+ * 1. the root path because every package potentially marks it as imported
+ * 2. /etc, /etc/packages, or paths that start with /etc/packages/, because packages with subpackages will import
+ * these paths, even if they are installed to a different JcrPackageRegistry.
+ *
+ * @param path the imported or deleted path to handle
+ */
+ private void handlePath(final String path) {
+ if (!mounts.hasNonDefaultMounts()
+ || path.equals("/")
+ || path.equals("/etc")
+ || path.equals(JcrPackageRegistry.DEFAULT_PACKAGE_ROOT_PATH)
+ || path.startsWith(JcrPackageRegistry.DEFAULT_PACKAGE_ROOT_PATH_PREFIX)) {
+ return;
+ }
+ currentPackageMounts.add(mounts.getMountByPath(path));
+ }
+
+ @Override
+ public void importedPath(final PackageId packageId,
+ final String path,
+ final Node node,
+ final PathAction actionType) throws RepositoryException {
+ handlePath(path);
+ }
+
+ @Override
+ public void deletedPath(final PackageId packageId,
+ final String path,
+ final Session inspectSession) throws RepositoryException {
+ handlePath(path);
+ }
+
+ private Set getMountsAffectedByPackage(final PackageId packageId) {
+ return new HashSet<>(affectedMounts.getOrDefault(packageId, Collections.emptySet()));
+ }
+
+ private Set getMountsAffectedByPackageGraph(final PackageId root) {
+ Set allAffectedMounts = new HashSet<>(getMountsAffectedByPackage(root));
+ for (PackageId subPackageId : subPackages.getOrDefault(root, Collections.emptyList())) {
+ allAffectedMounts.addAll(getMountsAffectedByPackageGraph(subPackageId));
+ }
+ return allAffectedMounts;
+ }
+
+ @Override
+ public void finishedScan() {
+ for (PackageId affectingPackageId : affectedMounts.keySet()) {
+ if (Rule.lastMatch(scopePackageIds, affectingPackageId.toString()).isExclude()) {
+ continue;
+ }
+ final Set affectedByPackage = getMountsAffectedByPackage(affectingPackageId);
+ if (affectedByPackage.size() > 1) {
+ reporting(violation -> violation
+ .withSeverity(severity)
+ .withPackage(affectingPackageId)
+ .withDescription("package content not aligned to a single composite store mount ({0})")
+ .withArgument(affectedByPackage.stream()
+ .map(Mount::getName).collect(Collectors.joining(" " + getString("and") + " "))));
+ } else if (affectedByPackage.size() > 0) { // filter out container packages only contain subpackages
+ final Set affectedByPackageGraph = getMountsAffectedByPackageGraph(affectingPackageId);
+ if (affectedByPackageGraph.size() > 1) {
+ reporting(violation -> violation
+ .withSeverity(severity)
+ .withPackage(affectingPackageId)
+ .withDescription("recursive package installation not aligned to a single composite store mount ({0})")
+ .withArgument(affectedByPackageGraph.stream()
+ .map(Mount::getName).collect(Collectors.joining(" " + getString("and") + " "))));
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/Echo.java b/core/src/main/java/net/adamcin/oakpal/core/checks/Echo.java
index 6c5d48c1d..76e1d760b 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/Echo.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/Echo.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,14 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ConsumerType;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -38,6 +40,7 @@
/**
* Simple verbose package check that logs all scan events to standard out. Extend to override methods.
*/
+@ConsumerType
public class Echo implements ProgressCheck {
private final AtomicLong lastEvent = new AtomicLong(System.nanoTime());
@@ -111,9 +114,15 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
echo("beforeExtract(packageId: %s, ..., subpackages: %s)", packageId, subpackages);
}
- @Override
+ @Deprecated
public void importedPath(final PackageId packageId, final String path, final Node node) throws RepositoryException {
- echo("importedPath(packageId: %s, path: %s, ...)", packageId, path);
+ importedPath(packageId, path, node, PathAction.UNKNOWN);
+ }
+
+ @Override
+ public void importedPath(final PackageId packageId, final String path, final Node node, final PathAction action)
+ throws RepositoryException {
+ echo("importedPath(packageId: %s, path: %s, ..., action: %s)", packageId, path, action);
}
@Override
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectAces.java b/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectAces.java
index efeb475ea..395e49ec9 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectAces.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectAces.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,19 +16,21 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.Fun;
-import net.adamcin.oakpal.core.JavaxJson;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.Result;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.Fun;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +40,6 @@
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.Privilege;
import javax.json.JsonObject;
-import javax.json.JsonValue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -54,15 +55,15 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.composeTest;
-import static net.adamcin.oakpal.core.Fun.inSet;
-import static net.adamcin.oakpal.core.Fun.inferTest1;
-import static net.adamcin.oakpal.core.Fun.mapEntry;
-import static net.adamcin.oakpal.core.Fun.result0;
-import static net.adamcin.oakpal.core.Fun.uncheck0;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.zipKeysWithValueFunc;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.composeTest;
+import static net.adamcin.oakpal.api.Fun.inSet;
+import static net.adamcin.oakpal.api.Fun.inferTest1;
+import static net.adamcin.oakpal.api.Fun.mapEntry;
+import static net.adamcin.oakpal.api.Fun.result0;
+import static net.adamcin.oakpal.api.Fun.uncheck0;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.Fun.zipKeysWithValueFunc;
/**
* ExpectAces: assert the existence or non-existence of specific access control entries after extracting a package.
@@ -121,39 +122,120 @@
* definition so indicates. Otherwise the comma-separated values are treated as an opaque string.
*/
public final class ExpectAces implements ProgressCheckFactory {
+ @ProviderType
+ public interface JsonKeys {
+ String principal();
+
+ String principals();
+
+ String expectedAces();
+
+ String notExpectedAces();
+
+ String afterPackageIdRules();
+
+ String severity();
+
+ String type();
+
+ String privileges();
+
+ String path();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String principal() {
+ return "principal";
+ }
+
+ @Override
+ public String principals() {
+ return "principals";
+ }
+
+ @Override
+ public String expectedAces() {
+ return "expectedAces";
+ }
+
+ @Override
+ public String notExpectedAces() {
+ return "notExpectedAces";
+ }
+
+ @Override
+ public String afterPackageIdRules() {
+ return "afterPackageIdRules";
+ }
+
+ @Override
+ public String severity() {
+ return "severity";
+ }
+
+ @Override
+ public String type() {
+ return "type";
+ }
+
+ @Override
+ public String privileges() {
+ return "privileges";
+ }
+
+ @Override
+ public String path() {
+ return "path";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_PRINCIPAL = keys().principal();
+ @Deprecated
+ public static final String CONFIG_PRINCIPALS = keys().principals();
+ @Deprecated
+ public static final String CONFIG_EXPECTED_ACES = keys().expectedAces();
+ @Deprecated
+ public static final String CONFIG_NOT_EXPECTED_ACES = keys().notExpectedAces();
+ @Deprecated
+ public static final String CONFIG_AFTER_PACKAGE_ID_RULES = keys().afterPackageIdRules();
+ @Deprecated
+ public static final String ACE_PARAM_TYPE = keys().type();
+ @Deprecated
+ public static final String ACE_PARAM_PRIVILEGES = keys().privileges();
+ @Deprecated
+ public static final String ACE_PARAM_PATH = keys().path();
+
private static final Logger LOGGER = LoggerFactory.getLogger(ExpectAces.class);
- public static final String CONFIG_PRINCIPAL = "principal";
- static final String CONFIG_PRINCIPALS = "principals";
- public static final String CONFIG_EXPECTED_ACES = "expectedAces";
- public static final String CONFIG_NOT_EXPECTED_ACES = "notExpectedAces";
- public static final String CONFIG_AFTER_PACKAGE_ID_RULES = "afterPackageIdRules";
- static final String CONFIG_SEVERITY = "severity";
- static final Violation.Severity DEFAULT_SEVERITY = Violation.Severity.MAJOR;
- public static final String ACE_PARAM_TYPE = "type";
- public static final String ACE_PARAM_PRIVILEGES = "privileges";
- public static final String ACE_PARAM_PATH = "path";
+ static final Severity DEFAULT_SEVERITY = Severity.MAJOR;
public static final String DELIM_PARAM = ";";
public static final String DELIM_VALUE = "=";
public static final String DELIM_LIST = ",";
@Override
public ProgressCheck newInstance(final JsonObject config) throws Exception {
- final String principal = config.getString(CONFIG_PRINCIPAL, "").trim();
- final String[] principals = JavaxJson.mapArrayOfStrings(JavaxJson.arrayOrEmpty(config, CONFIG_PRINCIPALS))
+ final String principal = config.getString(keys().principal(), "").trim();
+ final String[] principals = JavaxJson.mapArrayOfStrings(JavaxJson.arrayOrEmpty(config, keys().principals()))
.stream().map(String::trim).filter(inferTest1(String::isEmpty).negate()).toArray(String[]::new);
final String[] precedingPrincipals = principal.isEmpty() ? principals : new String[]{principal};
- final List expectedAces = parseAceCriteria(config, precedingPrincipals, CONFIG_EXPECTED_ACES);
- final List notExpectedAces = parseAceCriteria(config, precedingPrincipals, CONFIG_NOT_EXPECTED_ACES);
- final Violation.Severity severity = Violation.Severity.valueOf(
- config.getString(CONFIG_SEVERITY, DEFAULT_SEVERITY.name()).toUpperCase());
+ final List expectedAces = parseAceCriteria(config, precedingPrincipals, keys().expectedAces());
+ final List notExpectedAces = parseAceCriteria(config, precedingPrincipals, keys().notExpectedAces());
+ final Severity severity = Severity.valueOf(
+ config.getString(keys().severity(), DEFAULT_SEVERITY.name()).toUpperCase());
return new Check(expectedAces, notExpectedAces,
- Rule.fromJsonArray(JavaxJson.arrayOrEmpty(config, CONFIG_AFTER_PACKAGE_ID_RULES)), severity);
+ Rule.fromJsonArray(JavaxJson.arrayOrEmpty(config, keys().afterPackageIdRules())), severity);
}
static boolean isPrincipalSpec(final @NotNull String spec) {
- return spec.contains(CONFIG_PRINCIPAL + "=");
+ return spec.contains(keys().principal() + "=");
}
static boolean isGeneralSpec(final @NotNull String spec) {
@@ -193,29 +275,25 @@ static List parseAceCriteria(final @NotNull JsonObject config,
return allCriterias;
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
final List expectedAces;
final List notExpectedAces;
final Map> expectedViolators = new LinkedHashMap<>();
final Map> notExpectedViolators = new LinkedHashMap<>();
final List afterPackageIdRules;
- final Violation.Severity severity;
+ final Severity severity;
Check(final @NotNull List expectedAces,
final @NotNull List notExpectedAces,
final @NotNull List afterPackageIdRules,
- final @NotNull Violation.Severity severity) {
+ final @NotNull Severity severity) {
+ super(ExpectAces.class);
this.expectedAces = expectedAces;
this.notExpectedAces = notExpectedAces;
this.afterPackageIdRules = afterPackageIdRules;
this.severity = severity;
}
- @Override
- public String getCheckName() {
- return ExpectAces.class.getSimpleName();
- }
-
@Override
public void startedScan() {
super.startedScan();
@@ -274,15 +352,21 @@ public void afterExtract(final PackageId packageId, final Session inspectSession
public void finishedScan() {
for (Map.Entry> violatorsEntry : expectedViolators.entrySet()) {
if (!violatorsEntry.getValue().isEmpty()) {
- this.reportViolation(severity, "expected: " + violatorsEntry.getKey().toString(),
- violatorsEntry.getValue().toArray(new PackageId[0]));
+ this.reporting(violation -> violation
+ .withSeverity(severity)
+ .withDescription("expected: {0}")
+ .withArgument(violatorsEntry.getKey().toString())
+ .withPackages(violatorsEntry.getValue()));
}
}
expectedViolators.clear();
for (Map.Entry> violatorsEntry : notExpectedViolators.entrySet()) {
if (!violatorsEntry.getValue().isEmpty()) {
- this.reportViolation(severity, "unexpected: " + violatorsEntry.getKey().toString(),
- violatorsEntry.getValue().toArray(new PackageId[0]));
+ this.reporting(violation -> violation
+ .withSeverity(severity)
+ .withDescription("unexpected: {0}")
+ .withArgument(violatorsEntry.getKey().toString())
+ .withPackages(violatorsEntry.getValue()));
}
}
notExpectedViolators.clear();
@@ -415,32 +499,32 @@ static Result parse(final @NotNull String principal, final @NotNull
.map(Fun.mapValue(Optional::get))
.collect(Fun.entriesToMap());
- final String effectivePrincipal = valueMap.getOrDefault(CONFIG_PRINCIPAL, principal).trim();
+ final String effectivePrincipal = valueMap.getOrDefault(keys().principal(), principal).trim();
if (effectivePrincipal.isEmpty()) {
return Result.failure("principal must be non-empty: " + spec);
}
- keys.remove(CONFIG_PRINCIPAL);
+ keys.remove(keys().principal());
- if (!valueMap.containsKey(ACE_PARAM_TYPE)) {
- return Result.failure(ACE_PARAM_TYPE + " is a required ace parameter: " + spec);
+ if (!valueMap.containsKey(keys().type())) {
+ return Result.failure(keys().type() + " is a required ace parameter: " + spec);
}
- final Type type = Type.forName(valueMap.get(ACE_PARAM_TYPE));
+ final Type type = Type.forName(valueMap.get(keys().type()));
if (type == null) {
- return Result.failure(valueMap.get(ACE_PARAM_TYPE) + " is not a valid value for parameter " + ACE_PARAM_TYPE + ": " + spec);
+ return Result.failure(valueMap.get(keys().type()) + " is not a valid value for parameter " + keys().type() + ": " + spec);
}
- keys.remove(ACE_PARAM_TYPE);
+ keys.remove(keys().type());
- if (!keys.contains(ACE_PARAM_PATH)) {
- return Result.failure(ACE_PARAM_PATH + " parameter is required, but can be left empty to match rep:repoPolicy aces: " + spec);
+ if (!keys.contains(keys().path())) {
+ return Result.failure(keys().path() + " parameter is required, but can be left empty to match rep:repoPolicy aces: " + spec);
}
- final String path = Optional.ofNullable(valueMap.get(ACE_PARAM_PATH)).map(String::trim).orElse("");
+ final String path = Optional.ofNullable(valueMap.get(keys().path())).map(String::trim).orElse("");
if (path.isEmpty()) {
LOGGER.debug("empty path param. spec will evaluate /rep:repoPolicy : {}", spec);
}
- keys.remove(ACE_PARAM_PATH);
+ keys.remove(keys().path());
- final String[] privileges = Stream.of(Optional.ofNullable(valueMap.get(ACE_PARAM_PRIVILEGES))
+ final String[] privileges = Stream.of(Optional.ofNullable(valueMap.get(keys().privileges()))
.orElse("").split(DELIM_LIST))
.map(String::trim)
.filter(inferTest1(String::isEmpty).negate())
@@ -449,7 +533,7 @@ static Result parse(final @NotNull String principal, final @NotNull
if (privileges.length == 0) {
return Result.failure("privileges must be specified with at least one element: " + spec);
}
- keys.remove(ACE_PARAM_PRIVILEGES);
+ keys.remove(keys().privileges());
RestrictionCriteria[] restrictions = keys.stream()
.map(Fun.zipKeysWithValueFunc(valueMap::get))
@@ -465,9 +549,11 @@ String getSpec() {
return spec;
} else {
final StringBuilder common = new StringBuilder()
- .append(ACE_PARAM_TYPE + DELIM_VALUE).append(isAllow ? "allow" : "deny")
- .append(DELIM_PARAM + ACE_PARAM_PATH + DELIM_VALUE).append(path)
- .append(DELIM_PARAM + ACE_PARAM_PRIVILEGES + DELIM_VALUE).append(String.join(DELIM_LIST, privileges));
+ .append(keys().type()).append(DELIM_VALUE).append(isAllow ? "allow" : "deny")
+ .append(DELIM_PARAM)
+ .append(keys().path()).append(DELIM_VALUE).append(path)
+ .append(DELIM_PARAM)
+ .append(keys().privileges()).append(DELIM_VALUE).append(String.join(DELIM_LIST, privileges));
for (RestrictionCriteria restriction : restrictions) {
common.append(DELIM_PARAM).append(restriction.name);
if (restriction.value != null) {
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectPaths.java b/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectPaths.java
index 23ef2c18d..3a363c3bc 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectPaths.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/ExpectPaths.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,15 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.JavaxJson;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
@@ -33,8 +35,8 @@
import java.util.List;
import java.util.Map;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.optArray;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.optArray;
/**
* ExpectPaths: assert the existence or non-existence of specific repository item paths after extracting a package.
@@ -52,50 +54,88 @@
*
*/
public final class ExpectPaths implements ProgressCheckFactory {
- public static final String CONFIG_EXPECTED_PATHS = "expectedPaths";
- public static final String CONFIG_NOT_EXPECTED_PATHS = "notExpectedPaths";
- public static final String CONFIG_AFTER_PACKAGE_ID_RULES = "afterPackageIdRules";
- static final String CONFIG_SEVERITY = "severity";
- static final Violation.Severity DEFAULT_SEVERITY = Violation.Severity.MAJOR;
+ @ProviderType
+ public interface JsonKeys {
+ String expectedPaths();
+
+ String notExpectedPaths();
+
+ String afterPackageIdRules();
+
+ String severity();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String expectedPaths() {
+ return "expectedPaths";
+ }
+
+ @Override
+ public String notExpectedPaths() {
+ return "notExpectedPaths";
+ }
+
+ @Override
+ public String afterPackageIdRules() {
+ return "afterPackageIdRules";
+ }
+
+ @Override
+ public String severity() {
+ return "severity";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_EXPECTED_PATHS = keys().expectedPaths();
+ @Deprecated
+ public static final String CONFIG_NOT_EXPECTED_PATHS = keys().notExpectedPaths();
+ @Deprecated
+ public static final String CONFIG_AFTER_PACKAGE_ID_RULES = keys().afterPackageIdRules();
+ @Deprecated
+ public static final String CONFIG_SEVERITY = keys().severity();
+ static final Severity DEFAULT_SEVERITY = Severity.MAJOR;
@Override
public ProgressCheck newInstance(final JsonObject config) {
- final List expectedPaths = optArray(config, CONFIG_EXPECTED_PATHS)
+ final List expectedPaths = optArray(config, keys().expectedPaths())
.map(JavaxJson::mapArrayOfStrings)
.orElse(Collections.emptyList());
- final List notExpectedPaths = optArray(config, CONFIG_NOT_EXPECTED_PATHS)
+ final List notExpectedPaths = optArray(config, keys().notExpectedPaths())
.map(JavaxJson::mapArrayOfStrings)
.orElse(Collections.emptyList());
- final List afterPackageIdRules = Rule.fromJsonArray(arrayOrEmpty(config, CONFIG_AFTER_PACKAGE_ID_RULES));
- final Violation.Severity severity = Violation.Severity.valueOf(
- config.getString(CONFIG_SEVERITY, DEFAULT_SEVERITY.name()).toUpperCase());
+ final List afterPackageIdRules = Rule.fromJsonArray(arrayOrEmpty(config, keys().afterPackageIdRules()));
+ final Severity severity = Severity.valueOf(
+ config.getString(keys().severity(), DEFAULT_SEVERITY.name()).toUpperCase());
return new Check(expectedPaths, notExpectedPaths, afterPackageIdRules, severity);
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
final List expectedPaths;
final List notExpectedPaths;
final List afterPackageIdRules;
- final Violation.Severity severity;
+ final Severity severity;
final Map> expectedViolators = new LinkedHashMap<>();
final Map> notExpectedViolators = new LinkedHashMap<>();
Check(final @NotNull List expectedPaths,
final @NotNull List notExpectedPaths,
final @NotNull List afterPackageIdRules,
- final @NotNull Violation.Severity severity) {
+ final @NotNull Severity severity) {
+ super(ExpectPaths.class);
this.expectedPaths = expectedPaths;
this.notExpectedPaths = notExpectedPaths;
this.afterPackageIdRules = afterPackageIdRules;
this.severity = severity;
}
- @Override
- public String getCheckName() {
- return ExpectPaths.class.getSimpleName();
- }
-
@Override
public void startedScan() {
super.startedScan();
@@ -135,15 +175,21 @@ public void afterExtract(final PackageId packageId, final Session inspectSession
public void finishedScan() {
for (Map.Entry> violatorsEntry : expectedViolators.entrySet()) {
if (!violatorsEntry.getValue().isEmpty()) {
- this.reportViolation(severity, "expected path missing: " + violatorsEntry.getKey(),
- violatorsEntry.getValue().toArray(new PackageId[0]));
+ this.reporting(violation -> violation
+ .withSeverity(severity)
+ .withDescription("expected path missing: {0}")
+ .withArgument(violatorsEntry.getKey())
+ .withPackages(violatorsEntry.getValue()));
}
}
expectedViolators.clear();
for (Map.Entry> violatorsEntry : notExpectedViolators.entrySet()) {
if (!violatorsEntry.getValue().isEmpty()) {
- this.reportViolation(severity, "unexpected path present: " + violatorsEntry.getKey(),
- violatorsEntry.getValue().toArray(new PackageId[0]));
+ this.reporting(violation -> violation
+ .withSeverity(severity)
+ .withDescription("unexpected path present: {0}")
+ .withArgument(violatorsEntry.getKey())
+ .withPackages(violatorsEntry.getValue()));
}
}
notExpectedViolators.clear();
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/FilterSets.java b/core/src/main/java/net/adamcin/oakpal/core/checks/FilterSets.java
index a3f469867..4a2551f6c 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/FilterSets.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/FilterSets.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,23 +16,25 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.fs.api.ImportMode;
import org.apache.jackrabbit.vault.fs.api.PathFilterSet;
import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.json.JsonObject;
import java.util.List;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
/**
* Sanity check for {@link WorkspaceFilter}.
@@ -40,7 +42,7 @@
* {@code config} options:
*
* - {@code importModeSeverity}
- * - (default: {@link net.adamcin.oakpal.core.Violation.Severity#MINOR}) The default {@link ImportMode} for a
+ *
- (default: {@link Severity#MINOR}) The default {@link ImportMode} for a
* filter set is {@link ImportMode#REPLACE}. FileVault also supports {@link ImportMode#UPDATE} and
* {@link ImportMode#MERGE}, but it also supports forcing the import mode for an entire package via
* {@link org.apache.jackrabbit.vault.fs.io.ImportOptions#setImportMode(ImportMode)}, which certain platforms use to
@@ -56,39 +58,70 @@
*
*/
public final class FilterSets implements ProgressCheckFactory {
- public static final String CONFIG_IMPORT_MODE_SEVERITY = "importModeSeverity";
- public static final String CONFIG_ALLOW_EMPTY_FILTER = "allowEmptyFilter";
- public static final String CONFIG_ALLOW_ROOT_FILTER = "allowRootFilter";
- public static final Violation.Severity DEFAULT_IMPORT_MODE_SEVERITY = Violation.Severity.MINOR;
+ @ProviderType
+ public interface JsonKeys {
+ String importModeSeverity();
+
+ String allowEmptyFilter();
+
+ String allowRootFilter();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String importModeSeverity() {
+ return "importModeSeverity";
+ }
+
+ @Override
+ public String allowEmptyFilter() {
+ return "allowEmptyFilter";
+ }
+
+ @Override
+ public String allowRootFilter() {
+ return "allowRootFilter";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_IMPORT_MODE_SEVERITY = keys().importModeSeverity();
+ @Deprecated
+ public static final String CONFIG_ALLOW_EMPTY_FILTER = keys().allowEmptyFilter();
+ @Deprecated
+ public static final String CONFIG_ALLOW_ROOT_FILTER = keys().allowRootFilter();
+
+ public static final Severity DEFAULT_IMPORT_MODE_SEVERITY = Severity.MINOR;
@Override
public ProgressCheck newInstance(final JsonObject config) {
- final Violation.Severity importModeSeverity = Violation.Severity
- .valueOf(config.getString(CONFIG_IMPORT_MODE_SEVERITY, DEFAULT_IMPORT_MODE_SEVERITY.name())
+ final Severity importModeSeverity = Severity
+ .valueOf(config.getString(keys().importModeSeverity(), DEFAULT_IMPORT_MODE_SEVERITY.name())
.toUpperCase());
- final boolean allowEmptyFilter = hasNonNull(config, CONFIG_ALLOW_EMPTY_FILTER)
- && config.getBoolean(CONFIG_ALLOW_EMPTY_FILTER);
- final boolean allowRootFilter = hasNonNull(config, CONFIG_ALLOW_ROOT_FILTER)
- && config.getBoolean(CONFIG_ALLOW_ROOT_FILTER);
+ final boolean allowEmptyFilter = hasNonNull(config, keys().allowEmptyFilter())
+ && config.getBoolean(keys().allowEmptyFilter());
+ final boolean allowRootFilter = hasNonNull(config, keys().allowRootFilter())
+ && config.getBoolean(keys().allowRootFilter());
return new Check(importModeSeverity, allowEmptyFilter, allowRootFilter);
}
- static final class Check extends SimpleProgressCheck {
- final Violation.Severity importModeSeverity;
+ static final class Check extends SimpleProgressCheckFactoryCheck {
+ final Severity importModeSeverity;
final boolean allowEmptyFilter;
final boolean allowRootFilter;
- Check(final Violation.Severity importModeSeverity, final boolean allowEmptyFilter, final boolean allowRootFilter) {
+ Check(final Severity importModeSeverity, final boolean allowEmptyFilter, final boolean allowRootFilter) {
+ super(FilterSets.class);
this.importModeSeverity = importModeSeverity;
this.allowEmptyFilter = allowEmptyFilter;
this.allowRootFilter = allowRootFilter;
}
- @Override
- public String getCheckName() {
- return FilterSets.class.getSimpleName();
- }
-
@Override
public void beforeExtract(final PackageId packageId, final Session inspectSession,
final PackageProperties packageProperties, final MetaInf metaInf,
@@ -96,19 +129,19 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
final WorkspaceFilter filter = metaInf.getFilter();
if (filter == null || filter.getFilterSets().isEmpty()) {
if (!allowEmptyFilter) {
- reportViolation(Violation.Severity.MAJOR,
+ reportViolation(Severity.MAJOR,
"empty workspace filter is not allowed", packageId);
}
} else {
for (PathFilterSet filterSet : filter.getFilterSets()) {
if (filterSet.getImportMode() != ImportMode.REPLACE) {
- reportViolation(importModeSeverity,
- String.format("non-default import mode %s defined for filterSet with root %s",
- filterSet.getImportMode(), filterSet.getRoot()),
- packageId);
+ reporting(violation -> violation.withSeverity(importModeSeverity)
+ .withDescription("non-default import mode {0} defined for filterSet with root {1}")
+ .withArgument(filterSet.getImportMode(), filterSet.getRoot())
+ .withPackage(packageId));
}
if (!allowRootFilter && "/".equals(filterSet.getRoot())) {
- reportViolation(Violation.Severity.MAJOR,
+ reportViolation(Severity.MAJOR,
"root filter sets are not allowed", packageId);
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/JcrProperties.java b/core/src/main/java/net/adamcin/oakpal/core/checks/JcrProperties.java
index 8d8f8ce51..e818fa658 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/JcrProperties.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/JcrProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,13 +16,19 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -30,11 +36,13 @@
import javax.jcr.nodetype.NodeTypeDefinition;
import javax.json.JsonObject;
import java.util.List;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfStrings;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfStrings;
/**
* A complex check for enforcing characteristics of JCR Properties of imported nodes and their descendants within the
@@ -44,7 +52,7 @@
*
* - {@code scopePaths} ({@link Rule}{@code []})
* - A list of rules, with each pattern matched against an import path, and the {@code type}
- * ({@link net.adamcin.oakpal.core.checks.Rule.RuleType}) of the last matching rule determines whether the matched
+ * ({@link Rule.RuleType}) of the last matching rule determines whether the matched
* path is in scope for checking the properties on the node and its descendants.
* - {@code denyNodeTypes}
* - A list of nodeType strings, which specify primary or mixin types that should be disallowed. If matched, the path is
@@ -91,42 +99,110 @@
*
*/
public final class JcrProperties implements ProgressCheckFactory {
- public static final String CONFIG_SCOPE_PATHS = "scopePaths";
- public static final String CONFIG_DENY_NODE_TYPES = "denyNodeTypes";
- public static final String CONFIG_SCOPE_NODE_TYPES = "scopeNodeTypes";
- public static final String CONFIG_PROPERTIES = "properties";
+ @ProviderType
+ public interface JsonKeys {
+ String scopePaths();
+
+ String denyNodeTypes();
+
+ String scopeNodeTypes();
+
+ String properties();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String scopePaths() {
+ return "scopePaths";
+ }
+
+ @Override
+ public String denyNodeTypes() {
+ return "denyNodeTypes";
+ }
+
+ @Override
+ public String scopeNodeTypes() {
+ return "scopeNodeTypes";
+ }
+
+ @Override
+ public String properties() {
+ return "properties";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_SCOPE_PATHS = keys().scopePaths();
+ @Deprecated
+ public static final String CONFIG_DENY_NODE_TYPES = keys().denyNodeTypes();
+ @Deprecated
+ public static final String CONFIG_SCOPE_NODE_TYPES = keys().scopeNodeTypes();
+ @Deprecated
+ public static final String CONFIG_PROPERTIES = keys().properties();
@Override
public ProgressCheck newInstance(final JsonObject config) {
- List pathScope = Rule.fromJsonArray(arrayOrEmpty(config, CONFIG_SCOPE_PATHS));
+ List pathScope = Rule.fromJsonArray(arrayOrEmpty(config, keys().scopePaths()));
- List denyNodeTypes = mapArrayOfStrings(arrayOrEmpty(config, CONFIG_DENY_NODE_TYPES));
- List nodeTypeScope = mapArrayOfStrings(arrayOrEmpty(config, CONFIG_SCOPE_NODE_TYPES));
+ List denyNodeTypes = mapArrayOfStrings(arrayOrEmpty(config, keys().denyNodeTypes()));
+ List nodeTypeScope = mapArrayOfStrings(arrayOrEmpty(config, keys().scopeNodeTypes()));
+ final ResourceBundleHolder resourceBundleHolder = new ResourceBundleHolder();
List propertyChecks = JcrPropertyConstraints
- .fromJsonArray(arrayOrEmpty(config, CONFIG_PROPERTIES));
- return new Check(pathScope, denyNodeTypes, nodeTypeScope, propertyChecks);
+ .fromJsonArray(resourceBundleHolder::getResourceBundle, arrayOrEmpty(config, keys().properties()));
+ return new Check(pathScope, denyNodeTypes, nodeTypeScope, propertyChecks, resourceBundleHolder);
+ }
+
+ static final class ResourceBundleHolder {
+ private ResourceBundle resourceBundle;
+
+ public ResourceBundle getResourceBundle() {
+ if (resourceBundle == null) {
+ resourceBundle = ResourceBundle.getBundle(JcrProperties.class.getName());
+ }
+ return resourceBundle;
+ }
+
+ public void setResourceBundle(final ResourceBundle resourceBundle) {
+ this.resourceBundle = resourceBundle;
+ }
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
private final List scopePaths;
private final List denyNodeTypes;
private final List scopeNodeTypes;
private final List propertyChecks;
+ private final ResourceBundleHolder resourceBundleHolder;
private WorkspaceFilter wspFilter;
Check(final List scopePaths,
final List denyNodeTypes,
final List scopeNodeTypes,
- final List propertyChecks) {
+ final List propertyChecks,
+ final ResourceBundleHolder resourceBundleHolder) {
+ super(JcrProperties.class);
this.scopePaths = scopePaths;
this.denyNodeTypes = denyNodeTypes;
this.scopeNodeTypes = scopeNodeTypes;
this.propertyChecks = propertyChecks;
+ this.resourceBundleHolder = resourceBundleHolder;
+ }
+
+ @Override
+ public void setResourceBundle(final ResourceBundle resourceBundle) {
+ super.setResourceBundle(resourceBundle);
+ resourceBundleHolder.setResourceBundle(resourceBundle);
}
@Override
- public String getCheckName() {
- return JcrProperties.class.getSimpleName();
+ protected @Nullable ResourceBundle getResourceBundle() throws MissingResourceException {
+ return super.getResourceBundle();
}
@Override
@@ -137,7 +213,8 @@ public void beforeExtract(final PackageId packageId, final Session inspectSessio
}
@Override
- public void importedPath(final PackageId packageId, final String path, final Node node) throws RepositoryException {
+ public void importedPath(final PackageId packageId, final String path, final Node node,
+ final PathAction action) throws RepositoryException {
if (!wspFilter.contains(path)) {
return;
}
@@ -151,14 +228,19 @@ public void importedPath(final PackageId packageId, final String path, final Nod
void checkNode(final PackageId packageId, final Node node) throws RepositoryException {
for (String denyNodeType : denyNodeTypes) {
if (node.isNodeType(denyNodeType)) {
- majorViolation(String.format("%s (t: %s, m: %s): denied node type %s",
+ final Object[] arguments = new Object[]{
node.getPath(),
node.getPrimaryNodeType().getName(),
Stream.of(node.getMixinNodeTypes())
.map(NodeTypeDefinition::getName)
.collect(Collectors.toList()),
- denyNodeType),
- packageId);
+ denyNodeType
+ };
+ reporting(violation -> violation
+ .withSeverity(Severity.MAJOR)
+ .withDescription("{0} (t: {1}, m: {2}): denied node type {3}")
+ .withArgument(arguments)
+ .withPackage(packageId));
return;
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/JcrPropertyConstraints.java b/core/src/main/java/net/adamcin/oakpal/core/checks/JcrPropertyConstraints.java
index 201b32853..edb451d99 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/JcrPropertyConstraints.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/JcrPropertyConstraints.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,13 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.SimpleViolation;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.Node;
import javax.jcr.Property;
@@ -28,15 +32,19 @@
import javax.jcr.nodetype.NodeTypeDefinition;
import javax.json.JsonArray;
import javax.json.JsonObject;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.ResourceBundle;
+import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
-import static net.adamcin.oakpal.core.JavaxJson.mapArrayOfObjects;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.mapArrayOfObjects;
/**
* Encapsulation of constraints on a JCR property for the {@link JcrProperties} check.
@@ -58,39 +66,111 @@
*
- A list of patterns to match against string values of this property. All rules are applied in sequence to each
* value of the property. If the type of the last rule to match any value is DENY, a violation is reported.
* - {@code severity}
- * - (default: {@link net.adamcin.oakpal.core.Violation.Severity#MAJOR}) specify the severity if a violation is
+ *
- (default: {@link Severity#MAJOR}) specify the severity if a violation is
* reported by this set of constraints.
*
*/
public final class JcrPropertyConstraints {
- public static final String CONFIG_NAME = "name";
- public static final String CONFIG_DENY_IF_ABSENT = "denyIfAbsent";
- public static final String CONFIG_DENY_IF_PRESENT = "denyIfPresent";
- public static final String CONFIG_DENY_IF_MULTIVALUED = "denyIfMultivalued";
- public static final String CONFIG_REQUIRE_TYPE = "requireType";
- public static final String CONFIG_VALUE_RULES = "valueRules";
- public static final String CONFIG_SEVERITY = "severity";
- public static final Violation.Severity DEFAULT_SEVERITY = Violation.Severity.MAJOR;
-
- public static JcrPropertyConstraints fromJson(final JsonObject checkJson) {
- final String name = checkJson.getString(CONFIG_NAME);
- final boolean denyIfAbsent = hasNonNull(checkJson, CONFIG_DENY_IF_ABSENT)
- && checkJson.getBoolean(CONFIG_DENY_IF_ABSENT);
- final boolean denyIfPresent = hasNonNull(checkJson, CONFIG_DENY_IF_PRESENT)
- && checkJson.getBoolean(CONFIG_DENY_IF_PRESENT);
- final boolean denyIfMultivalued = hasNonNull(checkJson, CONFIG_DENY_IF_MULTIVALUED)
- && checkJson.getBoolean(CONFIG_DENY_IF_MULTIVALUED);
- final String requireType = checkJson.getString(CONFIG_REQUIRE_TYPE, null);
- final List valueRules = Rule.fromJsonArray(arrayOrEmpty(checkJson, CONFIG_VALUE_RULES));
- final Violation.Severity severity = Violation.Severity
- .valueOf(checkJson.getString(CONFIG_SEVERITY, DEFAULT_SEVERITY.name()).toUpperCase());
-
- return new JcrPropertyConstraints(name, denyIfAbsent, denyIfPresent, denyIfMultivalued, requireType, valueRules,
- severity);
+ @ProviderType
+ public interface JsonKeys {
+ String name();
+
+ String denyIfAbsent();
+
+ String denyIfPresent();
+
+ String denyIfMultivalued();
+
+ String requireType();
+
+ String valueRules();
+
+ String severity();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String name() {
+ return "name";
+ }
+
+ @Override
+ public String denyIfAbsent() {
+ return "denyIfAbsent";
+ }
+
+ @Override
+ public String denyIfPresent() {
+ return "denyIfPresent";
+ }
+
+ @Override
+ public String denyIfMultivalued() {
+ return "denyIfMultivalued";
+ }
+
+ @Override
+ public String requireType() {
+ return "requireType";
+ }
+
+ @Override
+ public String valueRules() {
+ return "valueRules";
+ }
+
+ @Override
+ public String severity() {
+ return "severity";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_NAME = keys().name();
+ @Deprecated
+ public static final String CONFIG_DENY_IF_ABSENT = keys().denyIfAbsent();
+ @Deprecated
+ public static final String CONFIG_DENY_IF_PRESENT = keys().denyIfPresent();
+ @Deprecated
+ public static final String CONFIG_DENY_IF_MULTIVALUED = keys().denyIfMultivalued();
+ @Deprecated
+ public static final String CONFIG_REQUIRE_TYPE = keys().requireType();
+ @Deprecated
+ public static final String CONFIG_VALUE_RULES = keys().valueRules();
+ @Deprecated
+ public static final String CONFIG_SEVERITY = keys().severity();
+
+ public static final Severity DEFAULT_SEVERITY = Severity.MAJOR;
+
+ public static Function
+ fromJson(@NotNull final Supplier resourceBundleSupplier) {
+ return checkJson -> {
+ final String name = checkJson.getString(keys().name());
+ final boolean denyIfAbsent = hasNonNull(checkJson, keys().denyIfAbsent())
+ && checkJson.getBoolean(keys().denyIfAbsent());
+ final boolean denyIfPresent = hasNonNull(checkJson, keys().denyIfPresent())
+ && checkJson.getBoolean(keys().denyIfPresent());
+ final boolean denyIfMultivalued = hasNonNull(checkJson, keys().denyIfMultivalued())
+ && checkJson.getBoolean(keys().denyIfMultivalued());
+ final String requireType = checkJson.getString(keys().requireType(), null);
+ final List valueRules = Rule.fromJsonArray(arrayOrEmpty(checkJson, keys().valueRules()));
+ final Severity severity = Severity
+ .valueOf(checkJson.getString(keys().severity(), DEFAULT_SEVERITY.name()).toUpperCase());
+
+ return new JcrPropertyConstraints(name, denyIfAbsent, denyIfPresent, denyIfMultivalued, requireType, valueRules,
+ severity, resourceBundleSupplier);
+ };
}
- public static List fromJsonArray(final JsonArray rulesArray) {
- return mapArrayOfObjects(rulesArray, JcrPropertyConstraints::fromJson);
+ public static List fromJsonArray(
+ @NotNull final Supplier resourceBundleSupplier,
+ final JsonArray rulesArray) {
+ return mapArrayOfObjects(rulesArray, fromJson(resourceBundleSupplier));
}
private final String name;
@@ -99,7 +179,8 @@ public static List fromJsonArray(final JsonArray rulesAr
private final boolean denyIfMultivalued;
private final String requireType;
private final List valueRules;
- private final Violation.Severity severity;
+ private final Severity severity;
+ private final Supplier resourceBundleSupplier;
public JcrPropertyConstraints(final String name,
final boolean denyIfAbsent,
@@ -107,7 +188,8 @@ public JcrPropertyConstraints(final String name,
final boolean denyIfMultivalued,
final String requireType,
final List valueRules,
- final Violation.Severity severity) {
+ final Severity severity,
+ final Supplier resourceBundleSupplier) {
this.name = name;
this.denyIfAbsent = denyIfAbsent;
this.denyIfPresent = denyIfPresent;
@@ -115,6 +197,7 @@ public JcrPropertyConstraints(final String name,
this.requireType = requireType;
this.valueRules = valueRules;
this.severity = severity;
+ this.resourceBundleSupplier = resourceBundleSupplier;
}
public String getName() {
@@ -141,14 +224,24 @@ public List getValueRules() {
return valueRules;
}
- public Violation.Severity getSeverity() {
+ public Severity getSeverity() {
return severity;
}
+ @NotNull
+ String getString(@NotNull final String key) {
+ final ResourceBundle resourceBundle = resourceBundleSupplier.get();
+ if (resourceBundle.containsKey(key)) {
+ return resourceBundle.getString(key);
+ } else {
+ return key;
+ }
+ }
+
Violation constructViolation(final PackageId packageId, final Node node, final String reason)
throws RepositoryException {
return new SimpleViolation(getSeverity(),
- String.format("%s (t: %s, m: %s): %s -> %s",
+ MessageFormat.format("{0} (t: {1}, m: {2}): {3} -> {4}",
node.getPath(),
node.getPrimaryNodeType().getName(),
Stream.of(node.getMixinNodeTypes())
@@ -162,23 +255,23 @@ Violation constructViolation(final PackageId packageId, final Node node, final S
Optional evaluate(final PackageId packageId, final Node node) throws RepositoryException {
if (!node.hasProperty(getName())) {
if (isDenyIfAbsent()) {
- return Optional.of(constructViolation(packageId, node, "property absent"));
+ return Optional.of(constructViolation(packageId, node, getString("property absent")));
}
} else {
if (isDenyIfPresent()) {
- return Optional.of(constructViolation(packageId, node, "property present"));
+ return Optional.of(constructViolation(packageId, node, getString("property present")));
}
Property property = node.getProperty(getName());
if (isDenyIfMultivalued() && property.isMultiple()) {
- return Optional.of(constructViolation(packageId, node, "property is multivalued"));
+ return Optional.of(constructViolation(packageId, node, getString("property is multivalued")));
}
if (getRequireType() != null && !getRequireType().isEmpty()
&& !getRequireType().equals(PropertyType.nameFromValue(property.getType()))) {
return Optional.of(constructViolation(packageId, node,
- String.format("required type mismatch: %s != %s",
+ MessageFormat.format(getString("required type mismatch: {0} != {1}"),
PropertyType.nameFromValue(property.getType()), getRequireType())));
}
@@ -195,7 +288,7 @@ Optional evaluate(final PackageId packageId, final Node node) throws
final Rule lastMatch = Rule.lastMatch(getValueRules(), value);
if (lastMatch.isDeny()) {
return Optional.of(constructViolation(packageId, node,
- String.format("value %s denied by pattern %s",
+ MessageFormat.format(getString("value {0} denied by pattern {1}"),
value, lastMatch.getPattern().pattern())));
}
}
@@ -203,5 +296,4 @@ Optional evaluate(final PackageId packageId, final Node node) throws
return Optional.empty();
}
-
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/Overlaps.java b/core/src/main/java/net/adamcin/oakpal/core/checks/Overlaps.java
index 674b40d41..ecc64b434 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/Overlaps.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/Overlaps.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,14 +16,17 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -35,13 +38,13 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
/**
* The {@code overlaps} check keeps track of installed package workspace filters, and checks every affected path going
* forward against previous workspace filters for overlap, using {@link WorkspaceFilter#contains(String)}. Overlapping
- * deletions are reported as {@link net.adamcin.oakpal.core.Violation.Severity#MAJOR}, whereas other affected paths are
- * reported as {@link net.adamcin.oakpal.core.Violation.Severity#MINOR}.
+ * deletions are reported as {@link Severity#MAJOR}, whereas other affected paths are
+ * reported as {@link Severity#MINOR}.
*
* This check is sequence-dependent, in that changing the sequence of packages in the scan may result in a different
* outcome. It is recommended to test multiple sequences if the actual process for package deployment is undefined or
@@ -56,31 +59,45 @@
*
*/
public final class Overlaps implements ProgressCheckFactory {
- public static final String CONFIG_REPORT_ALL_OVERLAPS = "reportAllOverlaps";
+ @ProviderType
+ public interface JsonKeys {
+ String reportAllOverlaps();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String reportAllOverlaps() {
+ return "reportAllOverlaps";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_REPORT_ALL_OVERLAPS = keys().reportAllOverlaps();
@Override
public ProgressCheck newInstance(final JsonObject config) {
- final boolean reportAllOverlaps = hasNonNull(config, CONFIG_REPORT_ALL_OVERLAPS)
- && config.getBoolean(CONFIG_REPORT_ALL_OVERLAPS);
+ final boolean reportAllOverlaps = hasNonNull(config, keys().reportAllOverlaps())
+ && config.getBoolean(keys().reportAllOverlaps());
return new Check(reportAllOverlaps);
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
final Map filters = new HashMap<>();
- final Map reported = new HashMap<>();
+ final Map reported = new HashMap<>();
final boolean reportAllOverlaps;
Check(final boolean reportAllOverlaps) {
+ super(Overlaps.class);
this.reportAllOverlaps = reportAllOverlaps;
}
- @Override
- public String getCheckName() {
- return Overlaps.class.getSimpleName();
- }
-
@Override
public void startedScan() {
super.startedScan();
@@ -100,7 +117,7 @@ Predicate super Map.Entry> overlaps(final String p
}
void findOverlaps(final PackageId currentPackageId, final String path,
- final Violation.Severity severity) {
+ final Severity severity) {
// fast escape! no need to belabor the point.
if (!reportAllOverlaps
&& reported.containsKey(currentPackageId)
@@ -120,18 +137,20 @@ void findOverlaps(final PackageId currentPackageId, final String path,
if (!reportAllOverlaps) {
reported.put(currentPackageId, severity);
}
- reportViolation(severity,
- String.format("affected path %s overlaps %s", path, overlapping),
- currentPackageId);
+ reporting(violation -> violation.withSeverity(severity)
+ .withPackage(currentPackageId)
+ .withDescription("affected path {0} overlaps {1}")
+ .withArgument(path, overlapping));
}
}
@Override
- public void importedPath(final PackageId packageId, final String path, final Node node)
+ public void importedPath(final PackageId packageId, final String path, final Node node,
+ final PathAction action)
throws RepositoryException {
// don't worry about nodes outside of our own scope.
if (filters.get(packageId).contains(path)) {
- findOverlaps(packageId, path, Violation.Severity.MINOR);
+ findOverlaps(packageId, path, Severity.MINOR);
}
}
@@ -139,7 +158,7 @@ public void importedPath(final PackageId packageId, final String path, final Nod
public void deletedPath(final PackageId packageId, final String path, final Session inspectSession)
throws RepositoryException {
// any deletions should be considered major overlap violations.
- findOverlaps(packageId, path, Violation.Severity.MAJOR);
+ findOverlaps(packageId, path, Severity.MAJOR);
}
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/Paths.java b/core/src/main/java/net/adamcin/oakpal/core/checks/Paths.java
index f690e4fc9..60109984b 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/Paths.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/Paths.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,15 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
@@ -28,8 +32,8 @@
import javax.json.JsonObject;
import java.util.List;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
/**
* Deny path imports/deletes by regular expression.
@@ -65,49 +69,83 @@
*
*/
public final class Paths implements ProgressCheckFactory {
- public static final String CONFIG_RULES = "rules";
- public static final String CONFIG_DENY_ALL_DELETES = "denyAllDeletes";
- public static final String CONFIG_SEVERITY = "severity";
- public static final Violation.Severity DEFAULT_SEVERITY = Violation.Severity.MAJOR;
+ @ProviderType
+ public interface JsonKeys {
+ String rules();
+
+ String denyAllDeletes();
+
+ String severity();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String rules() {
+ return "rules";
+ }
+
+ @Override
+ public String denyAllDeletes() {
+ return "denyAllDeletes";
+ }
+
+ @Override
+ public String severity() {
+ return "severity";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_RULES = keys().rules();
+ @Deprecated
+ public static final String CONFIG_DENY_ALL_DELETES = keys().denyAllDeletes();
+ @Deprecated
+ public static final String CONFIG_SEVERITY = keys().severity();
+
+ public static final Severity DEFAULT_SEVERITY = Severity.MAJOR;
@Override
public ProgressCheck newInstance(final JsonObject config) {
- List rules = Rule.fromJsonArray(arrayOrEmpty(config, CONFIG_RULES));
+ List rules = Rule.fromJsonArray(arrayOrEmpty(config, keys().rules()));
- final boolean denyAllDeletes = hasNonNull(config, CONFIG_DENY_ALL_DELETES)
- && config.getBoolean(CONFIG_DENY_ALL_DELETES);
+ final boolean denyAllDeletes = hasNonNull(config, keys().denyAllDeletes())
+ && config.getBoolean(keys().denyAllDeletes());
- final Violation.Severity severity = Violation.Severity.valueOf(
- config.getString(CONFIG_SEVERITY, DEFAULT_SEVERITY.name()).toUpperCase());
+ final Severity severity = Severity.valueOf(
+ config.getString(keys().severity(), DEFAULT_SEVERITY.name()).toUpperCase());
return new Check(rules, denyAllDeletes, severity);
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
private final List rules;
private final boolean denyAllDeletes;
- private final Violation.Severity severity;
+ private final Severity severity;
- Check(final List rules, final boolean denyAllDeletes, final Violation.Severity severity) {
+ Check(final List rules, final boolean denyAllDeletes, final Severity severity) {
+ super(Paths.class);
this.rules = rules;
this.denyAllDeletes = denyAllDeletes;
this.severity = severity;
}
@Override
- public String getCheckName() {
- return Paths.class.getSimpleName();
- }
-
- @Override
- public void importedPath(final PackageId packageId, final String path, final Node node)
+ public void importedPath(final PackageId packageId, final String path, final Node node,
+ final PathAction action)
throws RepositoryException {
Rule lastMatch = Rule.lastMatch(rules, path);
if (lastMatch.isDeny()) {
- reportViolation(severity,
- String.format("imported path %s matches deny pattern %s", path,
- lastMatch.getPattern().pattern()), packageId);
+ reporting(violation -> violation
+ .withSeverity(severity)
+ .withPackage(packageId)
+ .withDescription("imported path {0} matches deny pattern {1}")
+ .withArgument(path, lastMatch.getPattern().pattern()));
}
}
@@ -115,14 +153,19 @@ public void importedPath(final PackageId packageId, final String path, final Nod
public void deletedPath(final PackageId packageId, final String path, final Session inspectSession)
throws RepositoryException {
if (this.denyAllDeletes) {
- reportViolation(severity,
- String.format("deleted path %s. All deletions are denied.", path), packageId);
+ reporting(violation -> violation
+ .withSeverity(severity)
+ .withPackage(packageId)
+ .withDescription("deleted path {0}. All deletions are denied.")
+ .withArgument(path));
} else {
final Rule lastMatch = Rule.lastMatch(rules, path);
if (lastMatch.isDeny()) {
- reportViolation(severity,
- String.format("deleted path %s matches deny rule %s", path,
- lastMatch.getPattern().pattern()), packageId);
+ reporting(violation -> violation
+ .withSeverity(severity)
+ .withPackage(packageId)
+ .withDescription("deleted path {0} matches deny rule {1}")
+ .withArgument(path, lastMatch.getPattern().pattern()));
}
}
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/checks/Subpackages.java b/core/src/main/java/net/adamcin/oakpal/core/checks/Subpackages.java
index 0849c64b4..d3d4905b1 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/checks/Subpackages.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/checks/Subpackages.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,17 +16,20 @@
package net.adamcin.oakpal.core.checks;
-import net.adamcin.oakpal.core.ProgressCheck;
-import net.adamcin.oakpal.core.ProgressCheckFactory;
-import net.adamcin.oakpal.core.SimpleProgressCheck;
-import net.adamcin.oakpal.core.Violation;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.ProgressCheckFactory;
+import net.adamcin.oakpal.api.Rule;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleProgressCheckFactoryCheck;
import org.apache.jackrabbit.vault.packaging.PackageId;
+import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import javax.json.JsonObject;
import java.util.List;
-import static net.adamcin.oakpal.core.JavaxJson.arrayOrEmpty;
-import static net.adamcin.oakpal.core.JavaxJson.hasNonNull;
+import static net.adamcin.oakpal.api.JavaxJson.arrayOrEmpty;
+import static net.adamcin.oakpal.api.JavaxJson.hasNonNull;
/**
* Check for subpackage inclusion.
@@ -59,49 +62,72 @@
*
*/
public final class Subpackages implements ProgressCheckFactory {
- public static final String CONFIG_RULES = "rules";
- public static final String CONFIG_DENY_ALL = "denyAll";
+ @ProviderType
+ public interface JsonKeys {
+ String rules();
+
+ String denyAll();
+ }
+
+ private static final JsonKeys KEYS = new JsonKeys() {
+ @Override
+ public String rules() {
+ return "rules";
+ }
+
+ @Override
+ public String denyAll() {
+ return "denyAll";
+ }
+ };
+
+ @NotNull
+ public static JsonKeys keys() {
+ return KEYS;
+ }
+
+ @Deprecated
+ public static final String CONFIG_RULES = keys().rules();
+ @Deprecated
+ public static final String CONFIG_DENY_ALL = keys().denyAll();
@Override
public ProgressCheck newInstance(final JsonObject config) {
- List rules = Rule.fromJsonArray(arrayOrEmpty(config, CONFIG_RULES));
+ List rules = Rule.fromJsonArray(arrayOrEmpty(config, keys().rules()));
- final boolean denyAll = hasNonNull(config, CONFIG_DENY_ALL) && config.getBoolean(CONFIG_DENY_ALL);
+ final boolean denyAll = hasNonNull(config, keys().denyAll()) && config.getBoolean(keys().denyAll());
return new Check(rules, denyAll);
}
- static final class Check extends SimpleProgressCheck {
+ static final class Check extends SimpleProgressCheckFactoryCheck {
private final List rules;
private final boolean denyAll;
Check(final List rules, final boolean denyAll) {
+ super(Subpackages.class);
this.rules = rules;
this.denyAll = denyAll;
}
- @Override
- public String getCheckName() {
- return Subpackages.class.getSimpleName();
- }
-
@Override
public void identifySubpackage(final PackageId packageId, final PackageId parentId) {
if (denyAll) {
- reportViolation(Violation.Severity.MAJOR,
- String.format("subpackage %s included by %s. no subpackages are allowed.",
- packageId, parentId), packageId);
+ reporting(violation -> violation
+ .withSeverity(Severity.MAJOR)
+ .withPackage(packageId)
+ .withDescription("subpackage {0} included by {1}. no subpackages are allowed.")
+ .withArgument(packageId, parentId));
} else {
final Rule lastMatch = Rule.lastMatch(rules, packageId.toString());
if (lastMatch.isDeny()) {
- reportViolation(Violation.Severity.MAJOR,
- String.format("subpackage %s included by %s matches deny pattern %s",
- packageId.toString(), parentId.toString(),
- lastMatch.getPattern().pattern()), packageId);
+ reporting(violation -> violation
+ .withSeverity(Severity.MAJOR)
+ .withPackage(packageId)
+ .withDescription("subpackage {0} included by {1} matches deny pattern {2}")
+ .withArgument(packageId, parentId, lastMatch.getPattern().pattern()));
}
}
}
}
-
-
}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/opear/AdhocOpear.java b/core/src/main/java/net/adamcin/oakpal/core/opear/AdhocOpear.java
new file mode 100644
index 000000000..2da5480c9
--- /dev/null
+++ b/core/src/main/java/net/adamcin/oakpal/core/opear/AdhocOpear.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2020 Mark Adamcin
+ *
+ * Licensed 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 net.adamcin.oakpal.core.opear;
+
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.core.OakpalPlan;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Optional;
+import java.util.function.Function;
+
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.result1;
+
+/**
+ * Simpler opear implementation for CLI and other runtime-generated contexts.
+ */
+public final class AdhocOpear implements Opear {
+ private final URL planFileUrl;
+ private final URL baseUrl;
+
+ public AdhocOpear(final @NotNull URL planFileUrl, final @NotNull URL baseUrl) {
+ this.planFileUrl = planFileUrl;
+ this.baseUrl = baseUrl;
+ }
+
+ @Override
+ public URL getDefaultPlan() {
+ return planFileUrl;
+ }
+
+ @Override
+ public Result getSpecificPlan(final @NotNull String planName) {
+ return Result.success(planFileUrl);
+ }
+
+ @Override
+ public ClassLoader getPlanClassLoader(final @NotNull ClassLoader parent) {
+ return new URLClassLoader(new URL[]{baseUrl}, parent);
+ }
+
+ public static Result fromPlanFile(final @NotNull File planFile, final @Nullable File baseDir) {
+ final Function> fnFileUrl = compose(File::toURI, result1(URI::toURL));
+ final Result planFileUrlResult = fnFileUrl.apply(planFile);
+ return planFileUrlResult
+ .flatMap(planFileUrl -> fnFileUrl.apply(Optional.ofNullable(baseDir).orElse(planFile.getParentFile()))
+ .flatMap(baseUrl ->
+ OakpalPlan.fromJson(planFileUrl).map(plan ->
+ new AdhocOpear(planFileUrl, baseUrl))));
+ }
+}
diff --git a/core/src/main/java/net/adamcin/oakpal/core/Opear.java b/core/src/main/java/net/adamcin/oakpal/core/opear/Opear.java
similarity index 64%
rename from core/src/main/java/net/adamcin/oakpal/core/Opear.java
rename to core/src/main/java/net/adamcin/oakpal/core/opear/Opear.java
index 9fad11cfc..ce0eea0ad 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/Opear.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/opear/Opear.java
@@ -1,12 +1,32 @@
-package net.adamcin.oakpal.core;
+/*
+ * Copyright 2020 Mark Adamcin
+ *
+ * Licensed 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 net.adamcin.oakpal.core.opear;
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.core.OakpalPlan;
import org.jetbrains.annotations.NotNull;
+import org.osgi.annotation.versioning.ProviderType;
import java.net.URL;
/**
* OPEAR stands for "OakPal Encapsulated ARchive".
*/
+@ProviderType
public interface Opear {
String MF_BUNDLE_SYMBOLICNAME = "Bundle-SymbolicName";
diff --git a/core/src/main/java/net/adamcin/oakpal/core/OpearFile.java b/core/src/main/java/net/adamcin/oakpal/core/opear/OpearFile.java
similarity index 93%
rename from core/src/main/java/net/adamcin/oakpal/core/OpearFile.java
rename to core/src/main/java/net/adamcin/oakpal/core/opear/OpearFile.java
index fcb03ece0..ed03b5b45 100644
--- a/core/src/main/java/net/adamcin/oakpal/core/OpearFile.java
+++ b/core/src/main/java/net/adamcin/oakpal/core/opear/OpearFile.java
@@ -1,5 +1,24 @@
-package net.adamcin.oakpal.core;
+/*
+ * Copyright 2020 Mark Adamcin
+ *
+ * Licensed 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 net.adamcin.oakpal.core.opear;
+import net.adamcin.oakpal.api.Result;
+import net.adamcin.oakpal.core.OakpalPlan;
+import net.adamcin.oakpal.core.Util;
import org.apache.jackrabbit.oak.commons.FileIOUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,8 +45,8 @@
import static java.lang.String.format;
import static java.util.Optional.ofNullable;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.result1;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.result1;
/**
* The default implemenation of {@link Opear}. This is backed by an extracted JAR directory, including
@@ -256,6 +275,4 @@ static Result cacheJar(final @NotNull JarFile jarFile, final @NotNull File
.orElseGet(() -> Result.failure("failed to cache jarFile" + jarFile.getName())))
.orElse(Result.success(cacheDir));
}
-
-
}
diff --git a/core/src/main/resources/OAKPAL-INF/checklists/basic.json b/core/src/main/resources/OAKPAL-INF/checklists/basic.json
index 1a6a76f1b..3aa3177eb 100644
--- a/core/src/main/resources/OAKPAL-INF/checklists/basic.json
+++ b/core/src/main/resources/OAKPAL-INF/checklists/basic.json
@@ -30,6 +30,10 @@
"name": "overlaps",
"impl": "net.adamcin.oakpal.core.checks.Overlaps"
},
+ {
+ "name": "composite-store-alignment",
+ "impl": "net.adamcin.oakpal.core.checks.CompositeStoreAlignment"
+ },
{
"name": "echo",
"impl": "net.adamcin.oakpal.core.checks.Echo",
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/DefaultErrorListener.properties b/core/src/main/resources/net/adamcin/oakpal/core/DefaultErrorListener.properties
new file mode 100644
index 000000000..82e04a2c8
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/DefaultErrorListener.properties
@@ -0,0 +1,26 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+NodeType\ registration\ error\ ({0})\:\ {1}\ "{2}"=NodeType registration error ({0}): {1} "{2}"
+JCR\ namespace\ registration\ error\ ({0}\={1})\:\ {2}\ "{3}"=JCR namespace registration error ({0}={1}): {2} "{3}"
+JCR\ privilege\ registration\ error\ ({0})\:\ {1}\ "{2}"=JCR privilege registration error ({0}): {1} "{2}"
+Forced\ root\ creation\ error\ ({0})\:\ {1}\ "{2}"=Forced root creation error ({0}): {1} "{2}"
+Listener\ error\ ({0})\:\ {1}\ "{2}"=Listener error ({0}): {1} "{2}"
+Package\ error\:\ {0}\ "{1}"=Package error: {0} "{1}"
+{0}\ -\ Importer\ error\:\ {1}\ "{2}"={0} - Importer error: {1} "{2}"
+{0}\ -\ Listener\ error\:\ {1}\ "{2}"={0} - Listener error: {1} "{2}"
+InstallHook\ error\:\ {0}\ "{1}"=InstallHook error: {0} "{1}"
+Policy\ prohibits\ the\ use\ of\ InstallHooks\ in\ packages=Policy prohibits the use of InstallHooks in packages
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/AcHandling.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/AcHandling.properties
new file mode 100644
index 000000000..c66b970ee
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/AcHandling.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+acHandling\ mode\ {0}\ is\ forbidden.\ acHandling\ values\ in\ allowedModes\ are\ {1}=acHandling mode {0} is forbidden. acHandling values in allowedModes are {1}
+acHandling\ mode\ {0}\ is\ forbidden.\ allowed\ acHandling\ values\ in\ levelSet\:{1}\ are\ {2}=acHandling mode {0} is forbidden. allowed acHandling values in levelSet:{1} are {2}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.properties
new file mode 100644
index 000000000..cea766efb
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/CompositeStoreAlignment.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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\ content\ not\ aligned\ to\ a\ single\ composite\ store\ mount\ ({0})=package content not aligned to a single composite store mount ({0})
+recursive\ package\ installation\ not\ aligned\ to\ a\ single\ composite\ store\ mount\ ({0})=recursive package installation not aligned to a single composite store mount ({0})
+and=and
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectAces.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectAces.properties
new file mode 100644
index 000000000..ecd1918a7
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectAces.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+expected\:\ {0}=expected: {0}
+unexpected\:\ {0}=unexpected: {0}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectPaths.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectPaths.properties
new file mode 100644
index 000000000..3c5ada428
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/ExpectPaths.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+expected\ path\ missing\:\ {0}=expected path missing: {0}
+unexpected\ path\ present\:\ {0}=unexpected path present: {0}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/FilterSets.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/FilterSets.properties
new file mode 100644
index 000000000..bca46d509
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/FilterSets.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+empty\ workspace\ filter\ is\ not\ allowed=empty workspace filter is not allowed
+non-default\ import\ mode\ {0}\ defined\ for\ filterSet\ with\ root\ {1}=non-default import mode {0} defined for filterSet with root {1}
+root\ filter\ sets\ are\ not\ allowed=root filter sets are not allowed
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/JcrProperties.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/JcrProperties.properties
new file mode 100644
index 000000000..b70498888
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/JcrProperties.properties
@@ -0,0 +1,22 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+{0}\ (t\:\ {1},\ m\:\ {2})\:\ denied\ node\ type\ {3}={0} (t: {1}, m: {2}): denied node type {3}
+property\ absent=property absent
+property\ present=property present
+property\ is\ multivalued=property is multivalued
+required\ type\ mismatch\:\ {0}\ !\=\ {1}=required type mismatch: {0} != {1}
+value\ {0}\ denied\ by\ pattern\ {1}=value {0} denied by pattern {1}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/Overlaps.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/Overlaps.properties
new file mode 100644
index 000000000..70e936115
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/Overlaps.properties
@@ -0,0 +1,17 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+affected\ path\ {0}\ overlaps\ {1}=affected path {0} overlaps {1}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths.properties
new file mode 100644
index 000000000..51fe443e6
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+imported\ path\ {0}\ matches\ deny\ pattern\ {1}=imported path {0} matches deny pattern {1}
+deleted\ path\ {0}.\ All\ deletions\ are\ denied.=deleted path {0}. All deletions are denied.
+deleted\ path\ {0}\ matches\ deny\ rule\ {1}=deleted path {0} matches deny rule {1}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths_de.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths_de.properties
new file mode 100644
index 000000000..9f512caab
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/Paths_de.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+imported\ path\ {0}\ matches\ deny\ pattern\ {1}=importierte Pfad {0} stimmt mit dem deny Muster \u00fcberein {1}
+deleted\ path\ {0}.\ All\ deletions\ are\ denied.=gel\u00f6schte Pfad {0}. Alle L\u00f6chungen werden verweigert.
+deleted\ path\ {0}\ matches\ deny\ rule\ {1}=gel\u00f6schte Pfad {0} stimmt mit dem deny Muster \u00fcberein {1}
\ No newline at end of file
diff --git a/core/src/main/resources/net/adamcin/oakpal/core/checks/Subpackages.properties b/core/src/main/resources/net/adamcin/oakpal/core/checks/Subpackages.properties
new file mode 100644
index 000000000..ff66b1a04
--- /dev/null
+++ b/core/src/main/resources/net/adamcin/oakpal/core/checks/Subpackages.properties
@@ -0,0 +1,18 @@
+#
+# Copyright 2020 Mark Adamcin
+#
+# Licensed 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.
+#
+
+subpackage\ {0}\ included\ by\ {1}.\ no\ subpackages\ are\ allowed.=subpackage {0} included by {1}. no subpackages are allowed.
+subpackage\ {0}\ included\ by\ {1}\ matches\ deny\ pattern\ {2}=subpackage {0} included by {1} matches deny pattern {2}
\ No newline at end of file
diff --git a/core/src/site/xdoc/the-basic-checklist.xml.vm b/core/src/site/xdoc/the-basic-checklist.xml.vm
index 21395ba00..194554e48 100644
--- a/core/src/site/xdoc/the-basic-checklist.xml.vm
+++ b/core/src/site/xdoc/the-basic-checklist.xml.vm
@@ -45,6 +45,10 @@
"name": "overlaps",
"impl": "net.adamcin.oakpal.core.checks.Overlaps"
},
+ {
+ "name": "composite-store-alignment",
+ "impl": "net.adamcin.oakpal.core.checks.CompositeStoreAlignment"
+ },
{
"name": "echo",
"impl": "net.adamcin.oakpal.core.checks.Echo",
@@ -83,6 +87,8 @@
see net.adamcin.oakpal.core.checks.FilterSets
overlaps
(net.adamcin.oakpal.core/basic/overlaps
)
see net.adamcin.oakpal.core.checks.Overlaps
+ composite-store-alignment
(net.adamcin.oakpal.core/basic/composite-store-alignment
)
+ see net.adamcin.oakpal.core.checks.CompositeStoreAlignment
echo
(net.adamcin.oakpal.core/basic/echo
)
(skipped, template-only) see net.adamcin.oakpal.core.checks.Echo
jcrProperties
(net.adamcin.oakpal.core/basic/jcrProperties
)
diff --git a/core/src/test/filtered-resources/test-packages.properties b/core/src/test/filtered-resources/test-packages.properties
index 1c6d7919e..eae2b1bad 100644
--- a/core/src/test/filtered-resources/test-packages.properties
+++ b/core/src/test/filtered-resources/test-packages.properties
@@ -15,4 +15,4 @@
#
test-packages.root=${project.build.directory}
-test-packages.src=/jackrabbit-filevault-${vault-api.version}/vault-core/src/test/resources/org/apache/jackrabbit/vault/packaging/integration/testpackages/
\ No newline at end of file
+test-packages.src=/jackrabbit-filevault-${vault-api.version}/${vault.test-packages.src}/
diff --git a/core/src/test/java/net/adamcin/oakpal/core/BadInstallHookTest.java b/core/src/test/java/net/adamcin/oakpal/core/BadInstallHookTest.java
index b620beac5..8551f7be5 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/BadInstallHookTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/BadInstallHookTest.java
@@ -20,12 +20,12 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import net.adamcin.oakpal.api.Violation;
import net.adamcin.oakpal.testing.TestPackageUtil;
import org.junit.Test;
import java.io.File;
import java.util.Collection;
-import java.util.List;
import java.util.Optional;
public class BadInstallHookTest {
diff --git a/core/src/test/java/net/adamcin/oakpal/core/CheckReportTest.java b/core/src/test/java/net/adamcin/oakpal/core/CheckReportTest.java
index b853e3130..f930e6423 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/CheckReportTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/CheckReportTest.java
@@ -30,6 +30,10 @@
import javax.json.JsonArray;
import javax.json.JsonObject;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleViolation;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.junit.Test;
@@ -40,18 +44,18 @@ public void testGetViolationsBySeverity() {
final CheckReport report = mock(CheckReport.class);
final List violations = new ArrayList<>();
when(report.getViolations()).thenReturn(violations);
- doCallRealMethod().when(report).getViolations(nullable(Violation.Severity.class));
+ doCallRealMethod().when(report).getViolations(nullable(Severity.class));
assertEquals("violations size", 0, report.getViolations(null).size());
- violations.add(new SimpleViolation(Violation.Severity.MINOR, "minor violation"));
- violations.add(new SimpleViolation(Violation.Severity.MAJOR, "major violation"));
- violations.add(new SimpleViolation(Violation.Severity.SEVERE, "severe violation"));
+ violations.add(new SimpleViolation(Severity.MINOR, "minor violation"));
+ violations.add(new SimpleViolation(Severity.MAJOR, "major violation"));
+ violations.add(new SimpleViolation(Severity.SEVERE, "severe violation"));
assertEquals("violations size after populating", 3, report.getViolations(null).size());
- assertEquals("violations size at or above minor", 3, report.getViolations(Violation.Severity.MINOR).size());
- assertEquals("violations size at or above major", 2, report.getViolations(Violation.Severity.MAJOR).size());
- assertEquals("violations size at or above severe", 1, report.getViolations(Violation.Severity.SEVERE).size());
+ assertEquals("violations size at or above minor", 3, report.getViolations(Severity.MINOR).size());
+ assertEquals("violations size at or above major", 2, report.getViolations(Severity.MAJOR).size());
+ assertEquals("violations size at or above severe", 1, report.getViolations(Severity.SEVERE).size());
}
@Test
@@ -60,18 +64,18 @@ public void testToJson() {
final List violations = new ArrayList<>();
when(report.getViolations()).thenReturn(violations);
when(report.getCheckName()).thenReturn("mock");
- doCallRealMethod().when(report).getViolations(nullable(Violation.Severity.class));
+ doCallRealMethod().when(report).getViolations(nullable(Severity.class));
doCallRealMethod().when(report).toJson();
final PackageId fooId = PackageId.fromString("test:foo:1.0-SNAPSHOT");
final PackageId barId = PackageId.fromString("test:bar:1.0-SNAPSHOT");
- violations.add(new SimpleViolation(Violation.Severity.MINOR, "minor violation"));
- violations.add(new SimpleViolation(Violation.Severity.MAJOR, "major violation", fooId));
- violations.add(new SimpleViolation(Violation.Severity.SEVERE, "severe violation", fooId, barId));
+ violations.add(new SimpleViolation(Severity.MINOR, "minor violation"));
+ violations.add(new SimpleViolation(Severity.MAJOR, "major violation", fooId));
+ violations.add(new SimpleViolation(Severity.SEVERE, "severe violation", fooId, barId));
JsonObject json = report.toJson();
assertNotNull("json is not null", json);
- assertEquals("checkName should be", "mock", json.getString(ReportMapper.KEY_CHECK_NAME));
- JsonArray violationArray = json.getJsonArray(ReportMapper.KEY_VIOLATIONS);
+ assertEquals("checkName should be", "mock", json.getString(ReportMapper.keys().checkName()));
+ JsonArray violationArray = json.getJsonArray(ReportMapper.keys().violations());
List fromJson = JavaxJson.mapArrayOfObjects(violationArray, SimpleViolation::fromJson);
assertEquals("fromJson should be an array of three simple violations", 3, fromJson.size());
assertEquals("foo package is reported twice", 2,
diff --git a/core/src/test/java/net/adamcin/oakpal/core/CheckSpecTest.java b/core/src/test/java/net/adamcin/oakpal/core/CheckSpecTest.java
index 4830b3b4a..8a24dd4ee 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/CheckSpecTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/CheckSpecTest.java
@@ -16,22 +16,24 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import org.junit.Test;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import javax.json.JsonObject;
-import javax.json.JsonValue;
-import org.junit.Test;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
public class CheckSpecTest {
@@ -313,7 +315,7 @@ public void testInlineScript() throws Exception {
CheckSpec inline = CheckSpec.fromJson(key("inlineScript", "function importedPath(packageId, path) { print(path); }").get());
List checks = Locator.loadFromCheckSpecs(Collections.singletonList(inline));
- checks.get(0).importedPath(null, "/foo", null);
+ checks.get(0).importedPath(null, "/foo", null, PathAction.ADDED);
}
@Test
@@ -348,21 +350,22 @@ public void testGetters() {
@Test
public void testFromJson() {
+ final CheckSpec.JsonKeys keys = CheckSpec.keys();
final JsonObject specJson = obj()
- .key(CheckSpec.KEY_NAME, CheckSpec.KEY_NAME)
- .key(CheckSpec.KEY_IMPL, CheckSpec.KEY_IMPL)
- .key(CheckSpec.KEY_INLINE_SCRIPT, CheckSpec.KEY_INLINE_SCRIPT)
- .key(CheckSpec.KEY_INLINE_ENGINE, CheckSpec.KEY_INLINE_ENGINE)
- .key(CheckSpec.KEY_CONFIG, key("foo", "bar"))
- .key(CheckSpec.KEY_TEMPLATE, CheckSpec.KEY_TEMPLATE)
- .key(CheckSpec.KEY_SKIP, true)
+ .key(keys.name(), keys.name())
+ .key(keys.impl(), keys.impl())
+ .key(keys.inlineScript(), keys.inlineScript())
+ .key(keys.inlineEngine(), keys.inlineEngine())
+ .key(keys.config(), key("foo", "bar"))
+ .key(keys.template(), keys.template())
+ .key(keys.skip(), true)
.get();
final CheckSpec spec = CheckSpec.fromJson(specJson);
- assertEquals("fromJson getName same", CheckSpec.KEY_NAME, spec.getName());
- assertEquals("fromJson getImpl same", CheckSpec.KEY_IMPL, spec.getImpl());
- assertEquals("fromJson getTemplate same", CheckSpec.KEY_TEMPLATE, spec.getTemplate());
- assertEquals("fromJson getInlineScript same", CheckSpec.KEY_INLINE_SCRIPT, spec.getInlineScript());
- assertEquals("fromJson getInlineEngine same", CheckSpec.KEY_INLINE_ENGINE, spec.getInlineEngine());
+ assertEquals("fromJson getName same", keys.name(), spec.getName());
+ assertEquals("fromJson getImpl same", keys.impl(), spec.getImpl());
+ assertEquals("fromJson getTemplate same", keys.template(), spec.getTemplate());
+ assertEquals("fromJson getInlineScript same", keys.inlineScript(), spec.getInlineScript());
+ assertEquals("fromJson getInlineEngine same", keys.inlineEngine(), spec.getInlineEngine());
assertEquals("fromJson getConfig same", key("foo", "bar").get(), spec.getConfig());
assertTrue("fromJson isSkip true", spec.isSkip());
assertEquals("json should be equal", specJson, spec.toJson());
@@ -372,14 +375,15 @@ public void testFromJson() {
@Test
public void testCopyOf() {
+ final CheckSpec.JsonKeys keys = CheckSpec.keys();
final JsonObject specJson = obj()
- .key(CheckSpec.KEY_NAME, CheckSpec.KEY_NAME)
- .key(CheckSpec.KEY_IMPL, CheckSpec.KEY_IMPL)
- .key(CheckSpec.KEY_INLINE_SCRIPT, CheckSpec.KEY_INLINE_SCRIPT)
- .key(CheckSpec.KEY_INLINE_ENGINE, CheckSpec.KEY_INLINE_ENGINE)
- .key(CheckSpec.KEY_CONFIG, key("foo", "bar"))
- .key(CheckSpec.KEY_TEMPLATE, CheckSpec.KEY_TEMPLATE)
- .key(CheckSpec.KEY_SKIP, true)
+ .key(keys.name(), keys.name())
+ .key(keys.impl(), keys.impl())
+ .key(keys.inlineScript(), keys.inlineScript())
+ .key(keys.inlineEngine(), keys.inlineEngine())
+ .key(keys.config(), key("foo", "bar"))
+ .key(keys.template(), keys.template())
+ .key(keys.skip(), true)
.get();
final CheckSpec spec = CheckSpec.fromJson(specJson);
assertEquals("copy should equal copied", spec, CheckSpec.copyOf(spec));
diff --git a/core/src/test/java/net/adamcin/oakpal/core/ChecklistPlannerTest.java b/core/src/test/java/net/adamcin/oakpal/core/ChecklistPlannerTest.java
index 363f9ff31..61c2b05e9 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/ChecklistPlannerTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/ChecklistPlannerTest.java
@@ -16,7 +16,7 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.key;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -38,6 +38,7 @@
import java.util.stream.Collectors;
import javax.json.JsonObject;
+import net.adamcin.oakpal.api.Fun;
import org.junit.Before;
import org.junit.Test;
diff --git a/core/src/test/java/net/adamcin/oakpal/core/ChecklistTest.java b/core/src/test/java/net/adamcin/oakpal/core/ChecklistTest.java
index 5d73fe0a9..de7019c28 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/ChecklistTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/ChecklistTest.java
@@ -16,9 +16,9 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.arr;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
+import static net.adamcin.oakpal.api.JavaxJson.arr;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -37,6 +37,7 @@
import javax.json.JsonObject;
import javax.json.JsonReader;
+import net.adamcin.oakpal.api.JavaxJson;
import org.apache.jackrabbit.spi.PrivilegeDefinition;
import org.apache.jackrabbit.spi.QNodeTypeDefinition;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
@@ -76,20 +77,21 @@ public void testFromJSON() throws Exception {
@Test
public void testChecklistKeyComparator() {
- final String[] inputValues1 = Checklist.KEY_ORDER.toArray(new String[0]);
+ final Checklist.JsonKeys keys = Checklist.keys();
+ final String[] inputValues1 = keys.orderedKeys().toArray(new String[0]);
Arrays.sort(inputValues1, Checklist.checklistKeyComparator.reversed());
Arrays.sort(inputValues1, Checklist.checklistKeyComparator);
assertArrayEquals("sort reverse sort should be stable",
- Checklist.KEY_ORDER.toArray(new String[0]), inputValues1);
+ keys.orderedKeys().toArray(new String[0]), inputValues1);
- final String[] inputValues2 = new String[]{"foo", Checklist.KEY_NAME};
- final String[] expectValues2 = new String[]{Checklist.KEY_NAME, "foo"};
+ final String[] inputValues2 = new String[]{"foo", keys.name()};
+ final String[] expectValues2 = new String[]{keys.name(), "foo"};
Arrays.sort(inputValues2, Checklist.checklistKeyComparator);
assertArrayEquals("sort unknown keys after known keys",
expectValues2, inputValues2);
- final String[] inputValues2b = new String[]{Checklist.KEY_NAME, "foo"};
- final String[] expectValues2b = new String[]{Checklist.KEY_NAME, "foo"};
+ final String[] inputValues2b = new String[]{keys.name(), "foo"};
+ final String[] expectValues2b = new String[]{keys.name(), "foo"};
Arrays.sort(inputValues2b, Checklist.checklistKeyComparator);
assertArrayEquals("sort unknown keys after known keys",
expectValues2b, inputValues2b);
@@ -103,9 +105,10 @@ public void testChecklistKeyComparator() {
@Test
public void testComparingJsonKeys() {
- final JsonObject obj1 = key("id", Checklist.KEY_CHECKS).get();
- final JsonObject obj2 = key("id", Checklist.KEY_CND_NAMES).get();
- final JsonObject obj3 = key("id", Checklist.KEY_CND_URLS).get();
+ final Checklist.JsonKeys keys = Checklist.keys();
+ final JsonObject obj1 = key("id", keys.checks()).get();
+ final JsonObject obj2 = key("id", keys.cndNames()).get();
+ final JsonObject obj3 = key("id", keys.cndUrls()).get();
final JsonObject[] inputValues1 = new JsonObject[]{obj2, obj3, obj1};
final JsonObject[] expectValues1 = new JsonObject[]{obj1, obj2, obj3};
Arrays.sort(inputValues1, Checklist.comparingJsonKeys(obj -> obj.getString("id")));
@@ -189,12 +192,12 @@ public void testBuilderWithForcedRoots() {
Checklist.Builder builderWithForcedRoots = new Checklist.Builder("test");
final List forcedRoots = Arrays.asList(
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/foo")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "foo:primaryType")
+ .key(ForcedRoot.keys().path(), "/test/foo")
+ .key(ForcedRoot.keys().primaryType(), "foo:primaryType")
.get()),
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/bar")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "bar:primaryType")
+ .key(ForcedRoot.keys().path(), "/test/bar")
+ .key(ForcedRoot.keys().primaryType(), "bar:primaryType")
.get()));
builderWithForcedRoots.withForcedRoots(forcedRoots);
assertEquals("forced roots pass thru",
@@ -204,23 +207,23 @@ public void testBuilderWithForcedRoots() {
@Test
public void testBuilderIsValidCheckSpec() {
Checklist.Builder builder = new Checklist.Builder("test");
- CheckSpec validSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid")
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec validSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid")
+ .key(CheckSpec.keys().impl(), "impl").get());
assertTrue("valid spec isValid: " + validSpec.getName(),
builder.isValidCheckspec(validSpec));
- CheckSpec abstractSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid").get());
+ CheckSpec abstractSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid").get());
assertFalse("abstract spec not isValid: " + abstractSpec.getName(),
builder.isValidCheckspec(abstractSpec));
- CheckSpec nullNameSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, null)
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec nullNameSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), null)
+ .key(CheckSpec.keys().impl(), "impl").get());
assertFalse("nullName spec not isValid: " + nullNameSpec.getName(),
builder.isValidCheckspec(nullNameSpec));
- CheckSpec emptyNameSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "")
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec emptyNameSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), "")
+ .key(CheckSpec.keys().impl(), "impl").get());
assertFalse("emptyName spec not isValid: " + emptyNameSpec.getName(),
builder.isValidCheckspec(emptyNameSpec));
- CheckSpec slashNameSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid/notValid")
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec slashNameSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid/notValid")
+ .key(CheckSpec.keys().impl(), "impl").get());
assertFalse("slashName spec not isValid: " + slashNameSpec.getName(),
builder.isValidCheckspec(slashNameSpec));
}
@@ -228,12 +231,12 @@ public void testBuilderIsValidCheckSpec() {
@Test
public void testBuilderWithChecks() {
final Checklist.Builder builder = new Checklist.Builder("test");
- CheckSpec validSpec1 = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid1")
- .key(CheckSpec.KEY_IMPL, "impl").get());
- CheckSpec validSpec2 = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid2")
- .key(CheckSpec.KEY_IMPL, "impl").get());
- CheckSpec slashNameSpec = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid/notValid")
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec validSpec1 = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid1")
+ .key(CheckSpec.keys().impl(), "impl").get());
+ CheckSpec validSpec2 = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid2")
+ .key(CheckSpec.keys().impl(), "impl").get());
+ CheckSpec slashNameSpec = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid/notValid")
+ .key(CheckSpec.keys().impl(), "impl").get());
assertFalse("slashName spec not isValid: " + slashNameSpec.getName(),
builder.isValidCheckspec(slashNameSpec));
final String prefix = "test/";
@@ -275,14 +278,14 @@ public void testAsInitStage() throws Exception {
builder.withJcrPrivileges(privileges);
final List forcedRoots = Arrays.asList(
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/foo")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "foo:primaryType")
- .key(ForcedRoot.KEY_MIXIN_TYPES, arr().val("foo:mixinType"))
+ .key(ForcedRoot.keys().path(), "/test/foo")
+ .key(ForcedRoot.keys().primaryType(), "foo:primaryType")
+ .key(ForcedRoot.keys().mixinTypes(), arr().val("foo:mixinType"))
.get()),
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/bar")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "bar:primaryType")
- .key(ForcedRoot.KEY_MIXIN_TYPES, arr().val("bar:mixinType"))
+ .key(ForcedRoot.keys().path(), "/test/bar")
+ .key(ForcedRoot.keys().primaryType(), "bar:primaryType")
+ .key(ForcedRoot.keys().mixinTypes(), arr().val("bar:mixinType"))
.get()));
builder.withForcedRoots(forcedRoots);
InitStage initStage = builder.build().asInitStage();
@@ -337,33 +340,34 @@ public void testToJsonFromBuilder() {
builder.withJcrPrivileges(privileges);
final List forcedRoots = Arrays.asList(
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/foo")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "foo:primaryType")
- .key(ForcedRoot.KEY_MIXIN_TYPES, arr().val("foo:mixinType"))
+ .key(ForcedRoot.keys().path(), "/test/foo")
+ .key(ForcedRoot.keys().primaryType(), "foo:primaryType")
+ .key(ForcedRoot.keys().mixinTypes(), arr().val("foo:mixinType"))
.get()),
ForcedRoot.fromJson(obj()
- .key(ForcedRoot.KEY_PATH, "/test/bar")
- .key(ForcedRoot.KEY_PRIMARY_TYPE, "bar:primaryType")
- .key(ForcedRoot.KEY_MIXIN_TYPES, arr().val("bar:mixinType"))
+ .key(ForcedRoot.keys().path(), "/test/bar")
+ .key(ForcedRoot.keys().primaryType(), "bar:primaryType")
+ .key(ForcedRoot.keys().mixinTypes(), arr().val("bar:mixinType"))
.get()));
final JsonArray forcedRootsJson = JavaxJson.wrap(forcedRoots).asJsonArray();
builder.withForcedRoots(forcedRoots);
- CheckSpec validSpec1 = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid1")
- .key(CheckSpec.KEY_IMPL, "impl").get());
- CheckSpec validSpec2 = CheckSpec.fromJson(key(CheckSpec.KEY_NAME, "valid2")
- .key(CheckSpec.KEY_IMPL, "impl").get());
+ CheckSpec validSpec1 = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid1")
+ .key(CheckSpec.keys().impl(), "impl").get());
+ CheckSpec validSpec2 = CheckSpec.fromJson(key(CheckSpec.keys().name(), "valid2")
+ .key(CheckSpec.keys().impl(), "impl").get());
final List checks = Arrays.asList(validSpec1, validSpec2);
final JsonArray checksJson = JavaxJson.wrap(checks).asJsonArray();
builder.withChecks(checks);
final Checklist checklist = builder.build();
+ final Checklist.JsonKeys keys = Checklist.keys();
final JsonObject expectJson = obj()
- .key(Checklist.KEY_NAME, "name")
- .key(Checklist.KEY_CHECKS, checksJson)
- .key(Checklist.KEY_FORCED_ROOTS, forcedRootsJson)
- .key(Checklist.KEY_CND_URLS, cndUrlsJson)
- .key(Checklist.KEY_JCR_NODETYPES, nodetypesJson)
- .key(Checklist.KEY_JCR_PRIVILEGES, privilegesJson)
- .key(Checklist.KEY_JCR_NAMESPACES, jcrNamespacesJson)
+ .key(keys.name(), "name")
+ .key(keys.checks(), checksJson)
+ .key(keys.forcedRoots(), forcedRootsJson)
+ .key(keys.cndUrls(), cndUrlsJson)
+ .key(keys.jcrNodetypes(), nodetypesJson)
+ .key(keys.jcrPrivileges(), privilegesJson)
+ .key(keys.jcrNamespaces(), jcrNamespacesJson)
.get();
final JsonObject json = checklist.toJson();
assertEquals("toJson should match", expectJson, json);
diff --git a/core/src/test/java/net/adamcin/oakpal/core/DefaultErrorListenerTest.java b/core/src/test/java/net/adamcin/oakpal/core/DefaultErrorListenerTest.java
index 6c38feaa5..f18fde6f9 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/DefaultErrorListenerTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/DefaultErrorListenerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,52 @@
package net.adamcin.oakpal.core;
-import static org.junit.Assert.assertEquals;
-
+import net.adamcin.oakpal.api.Severity;
+import net.adamcin.oakpal.api.SimpleViolation;
import org.junit.Test;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
public class DefaultErrorListenerTest {
final Exception simpleCause = new IllegalStateException(new IllegalArgumentException());
+ @Test
+ public void testSetResourceBundle() {
+ final DefaultErrorListener listener = new DefaultErrorListener();
+
+ ResourceBundle originalBundle = listener.getResourceBundle();
+ assertSame("same object returned twice", originalBundle, listener.getResourceBundle());
+ ResourceBundle newBundle = ResourceBundle.getBundle(listener.getResourceBundleBaseName(),
+ Locale.getDefault(), new URLClassLoader(new URL[0], getClass().getClassLoader()));
+ assertNotSame("not same object as created externally", newBundle, listener.getResourceBundle());
+ listener.setResourceBundle(newBundle);
+ assertSame("same object as set", newBundle, listener.getResourceBundle());
+ assertSame("same object as set, again", newBundle, listener.getResourceBundle());
+ }
+
+ @Test
+ public void testGetString() {
+ final DefaultErrorListener listener = new DefaultErrorListener();
+ assertEquals("expect passthrough", "testKey", listener.getString("testKey"));
+ ResourceBundle newBundle = ResourceBundle.getBundle(getClass().getName());
+ listener.setResourceBundle(newBundle);
+ assertEquals("expect from bundle", "yeKtset", listener.getString("testKey"));
+ }
+
@Test
public void testGetReportedViolations() {
final DefaultErrorListener errorListener = new DefaultErrorListener();
- errorListener.reportViolation(new SimpleViolation(Violation.Severity.MINOR, "minor"));
- errorListener.reportViolation(new SimpleViolation(Violation.Severity.MAJOR, "major"));
- errorListener.reportViolation(new SimpleViolation(Violation.Severity.SEVERE, "severe"));
+ errorListener.reportViolation(new SimpleViolation(Severity.MINOR, "minor"));
+ errorListener.reportViolation(new SimpleViolation(Severity.MAJOR, "major"));
+ errorListener.reportViolation(new SimpleViolation(Severity.SEVERE, "severe"));
assertEquals("should have reported", 3, errorListener.getReportedViolations().size());
}
diff --git a/core/src/test/java/net/adamcin/oakpal/core/DefaultPackagingServiceTest.java b/core/src/test/java/net/adamcin/oakpal/core/DefaultPackagingServiceTest.java
index 1db11096d..f25e285da 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/DefaultPackagingServiceTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/DefaultPackagingServiceTest.java
@@ -45,6 +45,7 @@
import org.apache.jackrabbit.vault.packaging.VaultPackage;
import org.apache.jackrabbit.vault.packaging.impl.JcrPackageDefinitionImpl;
import org.apache.jackrabbit.vault.packaging.impl.JcrPackageManagerImpl;
+import org.jetbrains.annotations.NotNull;
import org.junit.Test;
public class DefaultPackagingServiceTest {
@@ -292,5 +293,15 @@ public VaultPackage rewrap(final ExportOptions opts, final VaultPackage src, fin
public void rewrap(final ExportOptions opts, final VaultPackage src, final OutputStream out) throws IOException {
}
+
+ @Override
+ public @NotNull VaultPackage open(@NotNull final Archive archive) throws IOException {
+ return null;
+ }
+
+ @Override
+ public @NotNull VaultPackage open(@NotNull final Archive archive, final boolean strict) throws IOException {
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/core/src/test/java/net/adamcin/oakpal/core/ErrorListenerTest.java b/core/src/test/java/net/adamcin/oakpal/core/ErrorListenerTest.java
index 799bfe75c..74655418b 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/ErrorListenerTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/ErrorListenerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 Mark Adamcin
+ * Copyright 2020 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,12 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.Violation;
+import org.junit.Test;
+
import java.util.Collection;
import java.util.Collections;
-import org.junit.Test;
-
public class ErrorListenerTest {
@Test
diff --git a/core/src/test/java/net/adamcin/oakpal/core/ForcedRootTest.java b/core/src/test/java/net/adamcin/oakpal/core/ForcedRootTest.java
index bac93f100..9450a4e2b 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/ForcedRootTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/ForcedRootTest.java
@@ -16,15 +16,20 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static org.junit.Assert.*;
+import org.junit.Test;
+import javax.json.JsonValue;
import java.util.Collections;
import java.util.List;
-import javax.json.JsonValue;
-import org.junit.Test;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
public class ForcedRootTest {
@@ -92,6 +97,7 @@ public void testGetNamespacePrefixes() {
@Test
public void testFromJson() {
+ final ForcedRoot.JsonKeys keys = ForcedRoot.keys();
final String path = "/correct/path";
final String primaryType = "primaryType";
final List mixinTypes = Collections.singletonList("mixinType");
@@ -101,18 +107,18 @@ public void testFromJson() {
assertTrue("empty root has empty mixinTypes", rootEmpty.getMixinTypes().isEmpty());
final ForcedRoot rootPath = ForcedRoot.fromJson(
- obj().key(ForcedRoot.KEY_PATH, path).get());
+ obj().key(keys.path(), path).get());
assertEquals("path root has correct path", path, rootPath.getPath());
final ForcedRoot rootPrimaryType = ForcedRoot.fromJson(
- obj().key(ForcedRoot.KEY_PRIMARY_TYPE, primaryType).get());
+ obj().key(keys.primaryType(), primaryType).get());
assertEquals("primaryType root has correct primaryType",
primaryType, rootPrimaryType.getPrimaryType());
final ForcedRoot rootMixinTypes = ForcedRoot.fromJson(
- obj().key(ForcedRoot.KEY_MIXIN_TYPES, mixinTypes).get());
+ obj().key(keys.mixinTypes(), mixinTypes).get());
assertEquals("mixinTypes root has correct mixinTypes",
mixinTypes, rootMixinTypes.getMixinTypes());
@@ -120,6 +126,7 @@ public void testFromJson() {
@Test
public void testToJson() {
+ final ForcedRoot.JsonKeys keys = ForcedRoot.keys();
final String path = "/correct/path";
final String primaryType = "primaryType";
final List mixinTypes = Collections.singletonList("mixinType");
@@ -130,15 +137,15 @@ public void testToJson() {
final ForcedRoot pathRoot = new ForcedRoot().withPath(path);
assertEquals("path root toJson should have path",
- key(ForcedRoot.KEY_PATH, path).get(), pathRoot.toJson());
+ key(keys.path(), path).get(), pathRoot.toJson());
final ForcedRoot primaryTypeRoot = new ForcedRoot().withPrimaryType(primaryType);
assertEquals("primaryType root toJson should have primaryType",
- key(ForcedRoot.KEY_PRIMARY_TYPE, primaryType).get(), primaryTypeRoot.toJson());
+ key(keys.primaryType(), primaryType).get(), primaryTypeRoot.toJson());
final ForcedRoot mixinTypeRoot = new ForcedRoot().withMixinTypes(mixinTypes.get(0));
assertEquals("mixinTypes root toJson should have mixinTypes",
- key(ForcedRoot.KEY_MIXIN_TYPES, mixinTypes).get(), mixinTypeRoot.toJson());
+ key(keys.mixinTypes(), mixinTypes).get(), mixinTypeRoot.toJson());
}
@Test
@@ -151,6 +158,7 @@ public void testCompareTo() {
@Test
public void testToString() {
+ final ForcedRoot.JsonKeys keys = ForcedRoot.keys();
final String path = "/correct/path";
final String primaryType = "primaryType";
final List mixinTypes = Collections.singletonList("mixinType");
@@ -159,9 +167,9 @@ public void testToString() {
.withPrimaryType(primaryType)
.withMixinTypes(mixinTypes.get(0));
final String jsonString = root.toString();
- final String expectString = key(ForcedRoot.KEY_PATH, path)
- .key(ForcedRoot.KEY_PRIMARY_TYPE, primaryType)
- .key(ForcedRoot.KEY_MIXIN_TYPES, mixinTypes)
+ final String expectString = key(keys.path(), path)
+ .key(keys.primaryType(), primaryType)
+ .key(keys.mixinTypes(), mixinTypes)
.get().toString();
assertEquals("expect json string for toString", expectString, jsonString);
}
diff --git a/core/src/test/java/net/adamcin/oakpal/core/InitStageTest.java b/core/src/test/java/net/adamcin/oakpal/core/InitStageTest.java
index 5f8eea4a2..82d9ebe51 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/InitStageTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/InitStageTest.java
@@ -16,12 +16,11 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.Fun.toEntry;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.uncheck2;
-import static net.adamcin.oakpal.core.JavaxJson.arr;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
+import static net.adamcin.oakpal.api.Fun.toEntry;
+import static net.adamcin.oakpal.api.Fun.uncheck2;
+import static net.adamcin.oakpal.api.JavaxJson.arr;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -34,7 +33,6 @@
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
diff --git a/core/src/test/java/net/adamcin/oakpal/core/JcrNsTest.java b/core/src/test/java/net/adamcin/oakpal/core/JcrNsTest.java
index 27482d10c..80ab6ba20 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/JcrNsTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/JcrNsTest.java
@@ -16,7 +16,7 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.key;
import static org.junit.Assert.*;
import javax.json.JsonObject;
@@ -27,16 +27,17 @@
public class JcrNsTest {
final String prefix = "foo";
final String uri = "http://foo.com";
+ private static final JcrNs.JsonKeys KEYS = JcrNs.keys();
@Test
public void testFromJson() {
assertNull("should be null if either prefix and uri are missing",
JcrNs.fromJson(JsonValue.EMPTY_JSON_OBJECT));
assertNull("should be null prefix is missing",
- JcrNs.fromJson(key(JcrNs.KEY_PREFIX, prefix).get()));
+ JcrNs.fromJson(key(KEYS.prefix(), prefix).get()));
assertNull("should be null if uri is missing",
- JcrNs.fromJson(key(JcrNs.KEY_URI, uri).get()));
- JcrNs complete = JcrNs.fromJson(key(JcrNs.KEY_PREFIX, prefix).key(JcrNs.KEY_URI, uri).get());
+ JcrNs.fromJson(key(KEYS.uri(), uri).get()));
+ JcrNs complete = JcrNs.fromJson(key(KEYS.prefix(), prefix).key(KEYS.uri(), uri).get());
assertNotNull("complete should not be null", complete);
assertEquals("complete prefix should be", prefix, complete.getPrefix());
assertEquals("complete prefix should be", uri, complete.getUri());
@@ -52,14 +53,14 @@ public void testCreate() {
@Test
public void testToJson() {
- JsonObject expect = key(JcrNs.KEY_PREFIX, prefix).key(JcrNs.KEY_URI, uri).get();
+ JsonObject expect = key(KEYS.prefix(), prefix).key(KEYS.uri(), uri).get();
JcrNs complete = JcrNs.create(prefix, uri);
assertEquals("expect json", expect, complete.toJson());
}
@Test
public void testToString() {
- String expect = key(JcrNs.KEY_PREFIX, prefix).key(JcrNs.KEY_URI, uri).get().toString();
+ String expect = key(KEYS.prefix(), prefix).key(KEYS.uri(), uri).get().toString();
JcrNs complete = JcrNs.create(prefix, uri);
assertEquals("expect json string", expect, complete.toString());
}
diff --git a/core/src/test/java/net/adamcin/oakpal/core/JsonCndTest.java b/core/src/test/java/net/adamcin/oakpal/core/JsonCndTest.java
index 5f2a0607c..89567afe8 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/JsonCndTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/JsonCndTest.java
@@ -16,8 +16,8 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.Fun.*;
-import static net.adamcin.oakpal.core.JavaxJson.*;
+import static net.adamcin.oakpal.api.Fun.*;
+import static net.adamcin.oakpal.api.JavaxJson.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
@@ -41,6 +41,9 @@
import javax.json.JsonValue;
import javax.json.stream.JsonCollectors;
+import net.adamcin.oakpal.api.Fun;
+import net.adamcin.oakpal.api.JavaxJson;
+import net.adamcin.oakpal.api.Result;
import org.apache.jackrabbit.commons.cnd.Lexer;
import org.apache.jackrabbit.spi.*;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
diff --git a/core/src/test/java/net/adamcin/oakpal/core/LocatorTest.java b/core/src/test/java/net/adamcin/oakpal/core/LocatorTest.java
index 5c8d199a3..19d5f46b6 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/LocatorTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/LocatorTest.java
@@ -16,12 +16,8 @@
package net.adamcin.oakpal.core;
-import static net.adamcin.oakpal.core.JavaxJson.key;
-import static net.adamcin.oakpal.core.JavaxJson.obj;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.Violation;
import net.adamcin.oakpal.core.checks.Echo;
import net.adamcin.oakpal.core.checks.Paths;
import org.junit.Test;
@@ -30,6 +26,12 @@
import java.util.Collection;
import java.util.Collections;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
public class LocatorTest {
public static class NotACheck {
@@ -61,7 +63,7 @@ public void testLoadProgressCheck() throws Exception {
assertNotNull("echo should load by class name, with config, with cl",
Locator.loadProgressCheck(Echo.class.getName(), obj().get(), getClass().getClassLoader()));
- assertNotNull("paths should load by class name, with config, with cl",
+ assertNotNull("paths should load by factory class name, with config, with cl",
Locator.loadProgressCheck(Paths.class.getName(), obj().get(), getClass().getClassLoader()));
assertNotNull("simpleHandler.js should load by resource name, with config, with cl",
diff --git a/core/src/test/java/net/adamcin/oakpal/core/NamespaceMappingRequestTest.java b/core/src/test/java/net/adamcin/oakpal/core/NamespaceMappingRequestTest.java
index bf126e480..c1b264435 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/NamespaceMappingRequestTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/NamespaceMappingRequestTest.java
@@ -16,7 +16,7 @@
package net.adamcin.oakpal.core;
-import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
+import net.adamcin.oakpal.api.Result;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.namespace.NamespaceMapping;
@@ -26,7 +26,7 @@
import java.util.Arrays;
import java.util.List;
-import static net.adamcin.oakpal.core.Fun.inferTest1;
+import static net.adamcin.oakpal.api.Fun.inferTest1;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
diff --git a/core/src/test/java/net/adamcin/oakpal/core/OakMachineTest.java b/core/src/test/java/net/adamcin/oakpal/core/OakMachineTest.java
index 6d65acff0..97d3c8695 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/OakMachineTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/OakMachineTest.java
@@ -17,6 +17,9 @@
package net.adamcin.oakpal.core;
import junitx.util.PrivateAccessor;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.SimpleProgressCheck;
import net.adamcin.oakpal.testing.TestPackageUtil;
import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
@@ -69,10 +72,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import static net.adamcin.oakpal.core.Fun.compose;
-import static net.adamcin.oakpal.core.Fun.toEntry;
-import static net.adamcin.oakpal.core.Fun.uncheck1;
-import static net.adamcin.oakpal.core.Fun.uncheckVoid1;
+import static net.adamcin.oakpal.api.Fun.compose;
+import static net.adamcin.oakpal.api.Fun.toEntry;
+import static net.adamcin.oakpal.api.Fun.uncheck1;
+import static net.adamcin.oakpal.api.Fun.uncheckVoid1;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -82,10 +85,8 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockitoSession;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
@@ -683,7 +684,7 @@ public void testImporterListenerAdapter_onMessage_importedPathException() throws
final File testPackage = TestPackageUtil.prepareTestPackage("tmp_foo_bar.zip");
final ProgressCheck check = mock(ProgressCheck.class);
doThrow(RepositoryException.class).when(check)
- .importedPath(any(PackageId.class), anyString(), any(Node.class));
+ .importedPath(any(PackageId.class), anyString(), any(Node.class), any(PathAction.class));
final CompletableFuture eLatch = new CompletableFuture<>();
final CompletableFuture handlerLatch = new CompletableFuture<>();
diff --git a/core/src/test/java/net/adamcin/oakpal/core/OakpalPlanTest.java b/core/src/test/java/net/adamcin/oakpal/core/OakpalPlanTest.java
index 6d8bd6618..0f9a04b61 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/OakpalPlanTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/OakpalPlanTest.java
@@ -16,6 +16,8 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.Result;
import org.apache.jackrabbit.api.JackrabbitWorkspace;
import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
import org.apache.jackrabbit.spi.PrivilegeDefinition;
@@ -31,7 +33,11 @@
import org.slf4j.LoggerFactory;
import javax.jcr.nodetype.NodeTypeManager;
-import javax.json.*;
+import javax.json.Json;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonValue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -41,13 +47,26 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-
-import static net.adamcin.oakpal.core.JavaxJson.*;
-import static org.junit.Assert.*;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.concurrent.CompletableFuture;
+
+import static net.adamcin.oakpal.api.JavaxJson.arr;
+import static net.adamcin.oakpal.api.JavaxJson.key;
+import static net.adamcin.oakpal.api.JavaxJson.obj;
+import static net.adamcin.oakpal.api.JavaxJson.wrap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class OakpalPlanTest {
private static final Logger LOGGER = LoggerFactory.getLogger(OakpalPlanTest.class);
@@ -512,4 +531,21 @@ public void testRelativizeToBaseParent() throws Exception {
assertEquals("return relative uri when base is not json",
fooRel, OakpalPlan.relativizeToBaseParent(fooRoot, fooAbs));
}
+
+ @Test
+ public void testInitResourceBundle() throws Exception {
+ CompletableFuture callback = new CompletableFuture<>();
+ OakpalPlan plan = builder().build();
+ ProgressCheck check = mock(ProgressCheck.class);
+ doAnswer(call -> callback.complete(call.getArgument(0)))
+ .when(check).setResourceBundle(nullable(ResourceBundle.class));
+ when(check.getResourceBundleBaseName()).thenReturn(null);
+ plan.initResourceBundle(check, Locale.getDefault(), getClass().getClassLoader());
+ assertFalse("expect callback not done", callback.isDone());
+ when(check.getResourceBundleBaseName()).thenReturn(getClass().getName());
+ plan.initResourceBundle(check, Locale.getDefault(), getClass().getClassLoader());
+ assertSame("expect callback complete with", ResourceBundle.getBundle(getClass().getName()),
+ callback.getNow(null));
+
+ }
}
\ No newline at end of file
diff --git a/core/src/test/java/net/adamcin/oakpal/core/ProgressCheckAliasFacadeTest.java b/core/src/test/java/net/adamcin/oakpal/core/ProgressCheckAliasFacadeTest.java
index e41f14428..56267f9c4 100644
--- a/core/src/test/java/net/adamcin/oakpal/core/ProgressCheckAliasFacadeTest.java
+++ b/core/src/test/java/net/adamcin/oakpal/core/ProgressCheckAliasFacadeTest.java
@@ -16,6 +16,9 @@
package net.adamcin.oakpal.core;
+import net.adamcin.oakpal.api.PathAction;
+import net.adamcin.oakpal.api.ProgressCheck;
+import net.adamcin.oakpal.api.Violation;
import org.apache.jackrabbit.vault.fs.config.MetaInf;
import org.apache.jackrabbit.vault.packaging.PackageId;
import org.apache.jackrabbit.vault.packaging.PackageProperties;
@@ -29,11 +32,13 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;
import java.util.jar.Manifest;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -225,15 +230,17 @@ public void testImportedPath_throws() throws Exception {
final PackageId arg0 = PackageId.fromString("my_packages:example:1.0");
final String arg1 = "/correct/path";
final Node arg2 = mock(Node.class);
+ final PathAction arg3 = PathAction.MODIFIED;
final ProgressCheck delegate = mock(ProgressCheck.class);
doThrow(RepositoryException.class).when(delegate).importedPath(
any(PackageId.class),
any(String.class),
- any(Node.class));
+ any(Node.class),
+ any(PathAction.class));
final ProgressCheckAliasFacade alias = new ProgressCheckAliasFacade(delegate, null);
- alias.importedPath(arg0, arg1, arg2);
+ alias.importedPath(arg0, arg1, arg2, arg3);
}
@Test
@@ -241,10 +248,12 @@ public void testImportedPath() throws Exception {
final PackageId arg0 = PackageId.fromString("my_packages:example:1.0");
final String arg1 = "/correct/path";
final Node arg2 = mock(Node.class);
+ final PathAction arg3 = PathAction.MODIFIED;
final CompletableFuture slot0 = new CompletableFuture<>();
final CompletableFuture slot1 = new CompletableFuture<>();
final CompletableFuture