This is an automated email from the ASF dual-hosted git repository.
reschke pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new d86fc37969 Revert "OAK-11617: Provide oak-run commands to analyze and
fix inconsistencie… (#2328)"
d86fc37969 is described below
commit d86fc3796996d5a22d8279e4f0d64e214b4083c5
Author: Julian Reschke <[email protected]>
AuthorDate: Sat Jun 28 06:20:23 2025 +0100
Revert "OAK-11617: Provide oak-run commands to analyze and fix
inconsistencie… (#2328)"
This reverts commit a16b36f159783701b2b06f5871c26c4bd4eb810b.
---
.../oak/plugins/name/NamespaceRegistryModel.java | 456 ---------------------
.../plugins/name/ReadOnlyNamespaceRegistry.java | 65 ++-
.../oak/plugins/name/NamespaceRegistryTest.java | 263 ------------
.../apache/jackrabbit/oak/run/AvailableModes.java | 1 -
.../oak/run/NamespaceRegistryCommand.java | 169 --------
.../oak/run/NamespaceRegistryOptions.java | 104 -----
.../oak/run/NamespaceRegistryCommandTest.java | 107 -----
7 files changed, 54 insertions(+), 1111 deletions(-)
diff --git
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryModel.java
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryModel.java
deleted file mode 100755
index 99868effdb..0000000000
---
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryModel.java
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.plugins.name;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import javax.jcr.RepositoryException;
-
-import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.oak.api.Root;
-import org.apache.jackrabbit.util.Text;
-import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.commons.collections.IterableUtils;
-import org.apache.jackrabbit.oak.commons.collections.SetUtils;
-import org.apache.jackrabbit.oak.commons.collections.StreamUtils;
-import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
-import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.api.Type.STRING;
-import static org.apache.jackrabbit.oak.api.Type.STRINGS;
-import static
org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_NAMESPACES;
-
-/**
- * A model of the namespace registry, containing the mappings from prefixes to
- * namespace URIs and vice versa.
- * <p>
- * The model is created from the namespace registry stored in the repository.
- * It can be used to check the consistency of the registry, repair it if
- * possible, and apply the changes back to the repository.
- */
-public final class NamespaceRegistryModel {
-
- private final Map<String, String> prefixToNamespaceMap;
- private final Map<String, String> encodedNamespaceToPrefixMap;
-
- private final Set<String> registeredPrefixes;
- private final Set<String> registeredNamespacesEncoded;
- private final Set<String> mappedPrefixes;
- private final Set<String> mappedNamespacesEncoded;
- private final Set<String> mappedToPrefixes;
- private final Set<String> mappedToNamespacesEncoded;
- private final Set<String> allPrefixes;
- private final Set<String> allNamespacesEncoded;
- private final Set<String> consistentPrefixes;
- private final Set<String> consistentNamespacesEncoded;
- private final int registrySize;
-
- private final Set<String> duplicatePrefixes;
- private final Set<String> duplicateNamespacesEncoded;
-
- private final Set<String> danglingPrefixes;
- private final Set<String> danglingNamespacesEncoded;
-
- private volatile boolean consistent = false;
- private volatile boolean fixable = false;
-
- private NamespaceRegistryModel(
- List<String> registeredPrefixesList, List<String>
registeredNamespacesEncodedList,
- // prefixes to URIs
- Map<String, String> prefixToNamespaceMap,
- // encoded URIs to prefixes
- Map<String, String> encodedNamespaceToPrefixMap) {
- // ignore the empty namespace which is not mapped
- registeredPrefixes = registeredPrefixesList.stream().filter(s ->
!(Objects.isNull(s) || s.isEmpty())).collect(Collectors.toSet());
- duplicatePrefixes = findDuplicates(registeredPrefixesList);
- registeredNamespacesEncoded =
registeredNamespacesEncodedList.stream().filter(s -> !(Objects.isNull(s) ||
s.isEmpty())).collect(Collectors.toSet());
- duplicateNamespacesEncoded =
findDuplicates(registeredNamespacesEncodedList);
- this.prefixToNamespaceMap = new HashMap<>(prefixToNamespaceMap);
- this.encodedNamespaceToPrefixMap = new
HashMap<>(encodedNamespaceToPrefixMap);
- mappedPrefixes = this.prefixToNamespaceMap.keySet();
- mappedNamespacesEncoded = this.encodedNamespaceToPrefixMap.keySet();
- mappedToPrefixes = new HashSet<>(encodedNamespaceToPrefixMap.values());
- mappedToNamespacesEncoded =
this.prefixToNamespaceMap.values().stream().map(Namespaces::encodeUri).collect(Collectors.toSet());
- allPrefixes = SetUtils.union(SetUtils.union(registeredPrefixes,
mappedPrefixes), mappedToPrefixes);
- allNamespacesEncoded =
SetUtils.union(SetUtils.union(registeredNamespacesEncoded,
mappedNamespacesEncoded), mappedToNamespacesEncoded);
- registrySize = Math.max(allPrefixes.size(),
allNamespacesEncoded.size());
- consistentPrefixes =
SetUtils.intersection(SetUtils.intersection(registeredPrefixes,
mappedPrefixes), mappedToPrefixes);
- consistentNamespacesEncoded =
SetUtils.intersection(SetUtils.intersection(registeredNamespacesEncoded,
mappedNamespacesEncoded), mappedToNamespacesEncoded);
- danglingPrefixes = SetUtils.difference(registeredPrefixes,
SetUtils.union(mappedPrefixes, mappedToPrefixes));
- danglingNamespacesEncoded =
SetUtils.difference(registeredNamespacesEncoded,
SetUtils.union(mappedNamespacesEncoded, mappedToNamespacesEncoded));
-
- boolean sizeMatches = duplicatePrefixes.isEmpty()
- && duplicateNamespacesEncoded.isEmpty()
- && consistentNamespacesEncoded.size() ==
allNamespacesEncoded.size()
- && consistentPrefixes.size() == allPrefixes.size();
- boolean doesRoundtrip = true;
- if (sizeMatches) {
- for (String prefix : mappedPrefixes) {
- String revMapped =
encodedNamespaceToPrefixMap.get(Namespaces.encodeUri(prefixToNamespaceMap.get(prefix)));
- if (revMapped == null || !revMapped.equals(prefix)) {
- doesRoundtrip = false;
- break;
- }
- }
- if (doesRoundtrip) {
- for (String ns : mappedNamespacesEncoded) {
- String uri =
prefixToNamespaceMap.get(encodedNamespaceToPrefixMap.get(ns));
- if (uri == null || !Namespaces.encodeUri(uri).equals(ns)) {
- doesRoundtrip = false;
- break;
- }
- }
- }
- }
- consistent = sizeMatches && doesRoundtrip;
- fixable = consistent;
- if (!consistent && doesRoundtrip) {
- fixable = registrySize == SetUtils.union(mappedPrefixes,
mappedToPrefixes).size()
- && registrySize == SetUtils.union(mappedNamespacesEncoded,
mappedToNamespacesEncoded).size();
- }
- }
-
- /**
- * Creates a new {@link NamespaceRegistryModel} from the namespace registry
- * stored in the system tree under the given repository {@link Root}.
- *
- * @param root the root of the repository
- * @return a new {@link NamespaceRegistryModel} or {@code null} if the
- * namespace registry does not exist
- */
- public static @Nullable NamespaceRegistryModel create(@NotNull Root root) {
- Tree rootTree = root.getTree("/");
- Tree namespaces = rootTree.getChild( JcrConstants.JCR_SYSTEM
).getChild(REP_NAMESPACES);
- if (namespaces.exists()) {
- Tree nsdata = namespaces.getChild(NamespaceConstants.REP_NSDATA);
- Map<String, String> prefixToNamespaceMap = new HashMap<>();
- Map<String, String> namespaceToPrefixMap = new HashMap<>();
- for (PropertyState propertyState : namespaces.getProperties()) {
- String prefix = propertyState.getName();
- if (!prefix.equals(NodeTypeConstants.JCR_PRIMARYTYPE)) {
- prefixToNamespaceMap.put(prefix,
propertyState.getValue(STRING));
- }
- }
- for (PropertyState propertyState : nsdata.getProperties()) {
- String encodedUri = propertyState.getName();
- switch (encodedUri) {
- case NamespaceConstants.REP_PREFIXES:
- case NamespaceConstants.REP_URIS:
- case NodeTypeConstants.JCR_PRIMARYTYPE:
- break;
- default:
- namespaceToPrefixMap.put(encodedUri,
propertyState.getValue(STRING));
- }
- }
- Iterable<String> uris =
Objects.requireNonNull(nsdata.getProperty(NamespaceConstants.REP_URIS))
- .getValue(STRINGS);
- return new NamespaceRegistryModel(
-
Arrays.asList(IterableUtils.toArray(Objects.requireNonNull(nsdata.getProperty(NamespaceConstants.REP_PREFIXES)).getValue(STRINGS),
String.class)),
-
StreamUtils.toStream(uris).map(Namespaces::encodeUri).collect(Collectors.toList()),
- prefixToNamespaceMap, namespaceToPrefixMap);
- } else {
- return null;
- }
- }
-
- /**
- * Creates a new {@link NamespaceRegistryModel} with the given mappings.
Used by {@see NamespaceRegistryCommand} to
- * repair a namespace registry that cannot be fixed automatically because
mapping information is missing.
- *
- * @param additionalPrefixToUrisMappings a map from prefixes to namespace
URIs
- * @return a new {@link NamespaceRegistryModel}
- */
- public NamespaceRegistryModel setMappings(@NotNull Map<String, String>
additionalPrefixToUrisMappings) {
- List<String> newRegisteredPrefixesList = new
ArrayList<>(registeredPrefixes);
- HashMap<String, String> newPrefixToNamespaceMap = new
HashMap<>(prefixToNamespaceMap);
- List<String> newRegisteredNamespacesEncodedList = new
ArrayList<>(registeredNamespacesEncoded);
- HashMap<String, String> newEncodedNamespaceToPrefixMap = new
HashMap<>(encodedNamespaceToPrefixMap);
- for (Map.Entry<String, String> entry :
additionalPrefixToUrisMappings.entrySet()) {
- String prefix = entry.getKey();
- String uri = entry.getValue();
- String encodedUri = Namespaces.encodeUri(uri);
-
- if (!newRegisteredPrefixesList.contains(prefix)) {
- newRegisteredPrefixesList.add(prefix);
- }
- if (!newRegisteredNamespacesEncodedList.contains(encodedUri)) {
- newRegisteredNamespacesEncodedList.add(encodedUri);
- }
- String previousUri = newPrefixToNamespaceMap.get(prefix);
- newPrefixToNamespaceMap.put(prefix, uri);
- if (previousUri != null) {
- String previousEncodedUri = Namespaces.encodeUri(previousUri);
- newRegisteredNamespacesEncodedList.remove(previousEncodedUri);
- newEncodedNamespaceToPrefixMap.remove(previousEncodedUri);
- }
- newEncodedNamespaceToPrefixMap.put(encodedUri, prefix);
- }
- return new NamespaceRegistryModel(newRegisteredPrefixesList,
newRegisteredNamespacesEncodedList,
- newPrefixToNamespaceMap, newEncodedNamespaceToPrefixMap);
- }
-
- /** Tries to repair the namespace registry model by fixing the mappings
- * from prefixes to namespace URIs and vice versa. If the model is not
- * fixable, it returns the original model.
- *
- * @return a new {@link NamespaceRegistryModel} with fixed mappings or the
- * original model if it cannot be fixed
- */
- public NamespaceRegistryModel tryRegistryRepair() {
- if (fixable) {
- List<String> fixedRegisteredPrefixesList = new ArrayList<>();
- HashMap<String, String> fixedPrefixToNamespaceMap = new
HashMap<>();
- for (String prefix : allPrefixes) {
- if (mappedPrefixes.contains(prefix)) {
- fixedRegisteredPrefixesList.add(prefix);
- fixedPrefixToNamespaceMap.put(prefix,
prefixToNamespaceMap.get(prefix));
- } else {
- for (Map.Entry<String, String> entry :
encodedNamespaceToPrefixMap.entrySet()) {
- if (entry.getValue().equals(prefix)) {
- fixedRegisteredPrefixesList.add(prefix);
- fixedPrefixToNamespaceMap.put(prefix,
Text.unescape(entry.getKey()));
- break;
- }
- }
- }
- }
- List<String> fixedRegisteredNamespacesEncodedList = new
ArrayList<>();
- HashMap<String, String> fixedNamespaceToPrefixMap = new
HashMap<>();
- for (String encodedNamespace : allNamespacesEncoded) {
- if (mappedNamespacesEncoded.contains(encodedNamespace)) {
- fixedRegisteredNamespacesEncodedList.add(encodedNamespace);
- fixedNamespaceToPrefixMap.put(encodedNamespace,
encodedNamespaceToPrefixMap.get(encodedNamespace));
- } else {
- for (Map.Entry<String, String> entry :
prefixToNamespaceMap.entrySet()) {
- if
(Namespaces.encodeUri(entry.getValue()).equals(encodedNamespace)) {
-
fixedRegisteredNamespacesEncodedList.add(encodedNamespace);
- fixedNamespaceToPrefixMap.put(encodedNamespace,
entry.getKey());
- break;
- }
- }
- }
- }
- return new NamespaceRegistryModel(fixedRegisteredPrefixesList,
fixedRegisteredNamespacesEncodedList,
- fixedPrefixToNamespaceMap, fixedNamespaceToPrefixMap);
- }
- return this;
- }
-
- /**
- * Applies this namespace registry model to the given repository {@link
Root}.
- *
- * @param root the root of the repository
- * @throws RepositoryException if an error occurs while applying the
changes
- * @throws CommitFailedException if the commit fails
- */
- public void apply(Root root) throws RepositoryException,
CommitFailedException {
- Tree rootTree = root.getTree("/");
- Tree namespaces = rootTree.getChild( JcrConstants.JCR_SYSTEM
).getChild(REP_NAMESPACES);
- Tree nsdata = namespaces.getChild(NamespaceConstants.REP_NSDATA);
- for (PropertyState propertyState : namespaces.getProperties()) {
- String name = propertyState.getName();
- if (!JCR_PRIMARYTYPE.equals(name)) {
- namespaces.removeProperty(name);
- }
- }
- for (PropertyState propertyState : nsdata.getProperties()) {
- String name = propertyState.getName();
- if (!JCR_PRIMARYTYPE.equals(name)) {
- nsdata.removeProperty(name);
- }
- }
- nsdata.removeProperty(NamespaceConstants.REP_PREFIXES);
- nsdata.removeProperty(NamespaceConstants.REP_URIS);
- for (Map.Entry<String, String> entry :
prefixToNamespaceMap.entrySet()) {
- String prefix = entry.getKey();
- String uri = entry.getValue();
- namespaces.setProperty(prefix, uri);
- }
- for (Map.Entry<String, String> entry :
encodedNamespaceToPrefixMap.entrySet()) {
- String encodedUri = entry.getKey();
- String prefix = entry.getValue();
- nsdata.setProperty(encodedUri, prefix);
- }
- nsdata.setProperty(NamespaceConstants.REP_PREFIXES, mappedPrefixes,
STRINGS);
- nsdata.setProperty(NamespaceConstants.REP_URIS,
prefixToNamespaceMap.values(), STRINGS);
- if (!consistent) {
- throw new IllegalStateException("Final registry consistency check
failed.");
- }
- }
-
- public boolean isConsistent() {
- return consistent;
- }
-
- public boolean isFixable() {
- return fixable;
- }
-
- /** Prefixes that are registered, but not mapped to or from a namespace
uri.
- * This kind of inconsistency cannot be fixed automatically, because the
namespace uri
- * corresponding to the prefix is unknown.
- * Apply the {@link #setMappings(Map)} method to create a new model with
the missing mappings.
- */
- public Set<String> getDanglingPrefixes() {
- return danglingPrefixes;
- }
-
- /** Namespace uris that are registered, but not mapped to or from a prefix.
- * This kind of inconsistency cannot be fixed automatically, because the
prefix
- * corresponding to the namespace uri is unknown.
- * Apply the {@link #setMappings(Map)} method to create a new model with
the missing mappings.
- */
- public Set<String> getDanglingEncodedNamespaceUris() {
- return danglingNamespacesEncoded;
- }
-
- /**
- * Broken mappings completed with the missing prefix or namespace uri.
- */
- public Map<String, String> getRepairedMappings() {
- Map<String, String> map = new HashMap<>();
- Set<String> repairablePrefixes =
SetUtils.difference(SetUtils.difference(allPrefixes, consistentPrefixes),
danglingPrefixes);
- Set<String> repairableUrisEncoded =
SetUtils.difference(SetUtils.difference(allNamespacesEncoded,
consistentNamespacesEncoded), danglingNamespacesEncoded);
- for (Map.Entry<String, String> entry :
prefixToNamespaceMap.entrySet()) {
- String prefix = entry.getKey();
- String uri = entry.getValue();
- if (repairablePrefixes.contains(prefix) ||
repairableUrisEncoded.contains(uri)) {
- map.put(prefix, uri);
- }
- }
- for (Map.Entry<String, String> entry :
encodedNamespaceToPrefixMap.entrySet()) {
- String prefix = entry.getValue();
- String uri = entry.getKey();
- if (repairablePrefixes.contains(prefix) ||
repairableUrisEncoded.contains(uri)) {
- map.put(prefix, uri);
- }
- }
- return map;
- }
-
- private <T> Set<T> findDuplicates(Collection<T> c) {
- HashSet<T> uniques = new HashSet<>();
- return c.stream().filter(t ->
!uniques.add(t)).collect(Collectors.toSet());
- }
-
- /**
- * Write a human-readable analysis of the namespace registry model to
System.out.
- */
- public void dump() throws IOException {
- dump(System.out);
- }
-
- /**
- * Write a human-readable analysis of the namespace registry model to the
- * given {@link OutputStream}.
- *
- * @param out the output stream to write to
- * @throws IOException if an error occurs while writing to the output
stream
- */
- public void dump(OutputStream out) throws IOException {
- dump(new OutputStreamWriter(out, StandardCharsets.UTF_8));
- out.flush();
- }
-
- public void dump(Writer out) throws IOException {
- BufferedWriter writer = new BufferedWriter(out);
- if (consistent) {
- writer.write("This namespace registry model is consistent,
containing the following mappings from prefixes to namespace uris:");
- writer.newLine();
- writer.newLine();
- for (Map.Entry<String, String> entry :
prefixToNamespaceMap.entrySet()) {
- writer.write(entry.getKey() + " -> " + entry.getValue());
- writer.newLine();
- }
- } else {
- writer.write("This namespace registry model is inconsistent.
The inconsistency can " + (isFixable()? "" : "NOT ") + "be fixed.");
- writer.newLine();
- writer.newLine();
- writer.write("Registered prefixes without any namespace
mapping: " + danglingPrefixes);
- writer.newLine();
- writer.write("Registered namespace URIs without any prefix
mapping: " + danglingNamespacesEncoded);
- writer.newLine();
- writer.write("Duplicate prefixes: " + duplicatePrefixes);
- writer.newLine();
- writer.write("Duplicate namespace URIs: " +
duplicateNamespacesEncoded);
- writer.newLine();
- writer.write("Mapped unregistered prefixes: " +
SetUtils.difference(SetUtils.union(mappedPrefixes, mappedToPrefixes),
registeredPrefixes));
- writer.newLine();
- writer.write("Mapped unregistered namespace URIs: " +
SetUtils.difference(SetUtils.union(mappedNamespacesEncoded,
mappedToNamespacesEncoded), registeredNamespacesEncoded));
- writer.newLine();
- writer.write("Mapped prefixes without a reverse mapping: " +
SetUtils.difference(mappedPrefixes, mappedToPrefixes));
- writer.newLine();
- writer.write("Mapped namespace URIs without a reverse mapping:
" + SetUtils.difference(mappedNamespacesEncoded, mappedToNamespacesEncoded));
- writer.newLine();
- writer.newLine();
- if (isFixable()) {
- NamespaceRegistryModel repaired = tryRegistryRepair();
- writer.newLine();
- writer.write("The following mappings could be repaired:");
- writer.newLine();
- writer.newLine();
- for (Map.Entry<String, String> entry :
getRepairedMappings().entrySet()) {
- writer.write(entry.getKey() + " -> " +
entry.getValue());
- writer.newLine();
- }
- writer.newLine();
- writer.newLine();
- writer.write("The repaired registry would contain the
following mappings:");
- writer.newLine();
- writer.newLine();
- for (Map.Entry<String, String> entry :
repaired.prefixToNamespaceMap.entrySet()) {
- writer.write(entry.getKey() + " -> " +
entry.getValue());
- writer.newLine();
- }
- } else {
- writer.write("The following mappings could be repaired:");
- writer.newLine();
- writer.newLine();
- for (Map.Entry<String, String> entry :
getRepairedMappings().entrySet()) {
- writer.write(entry.getKey() + " -> " +
entry.getValue());
- writer.newLine();
- }
- writer.newLine();
- writer.newLine();
- writer.write("To create a fixed model, use
#tryRegistryRepair(Map<String, String>) and supply missing prefix to namespace
mappings as parameters");
- writer.newLine();
- }
- }
- writer.flush();
- }
-}
diff --git
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
index 63dce06a57..ddf6509ce0 100644
---
a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
+++
b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
@@ -25,6 +25,7 @@ import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
+import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
@@ -34,7 +35,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Read-only namespace registry. Used mostly internally when access to the
@@ -57,7 +60,7 @@ public class ReadOnlyNamespaceRegistry
this.namespaces = root.getTree(NAMESPACES_PATH);
this.nsdata = namespaces.getChild(REP_NSDATA);
if (!CONSISTENCY_CHECKED) {
- checkConsistency(root);
+ checkConsistency();
}
}
@@ -127,16 +130,56 @@ public class ReadOnlyNamespaceRegistry
"No namespace prefix registered for URI " + uri);
}
- public boolean checkConsistency(Root root) throws IllegalStateException {
- NamespaceRegistryModel model = createNamespaceRegistryModel(root);
- if (model == null) {
- LOG.warn("Consistency check skipped because there is no namespace
registry.");
+ protected void checkConsistency() {
+ final String jcrPrimaryType = "jcr:primaryType";
+ List<String> prefixes = Arrays.asList(getPrefixes());
+ List<String> encodedUris =
Arrays.stream(getURIs()).map(Namespaces::encodeUri).collect(Collectors.toList());
+ if (prefixes.size() != encodedUris.size()) {
+ LOG.error("The namespace registry is inconsistent: found {}
registered namespace prefixes and {} registered namespace URIs. The numbers
have to be equal.", prefixes.size(), encodedUris.size());
}
- return model == null || model.isConsistent();
- }
-
- public NamespaceRegistryModel createNamespaceRegistryModel(Root root) {
- return NamespaceRegistryModel.create(root);
+ int mappedPrefixCount = 0;
+ for (PropertyState propertyState : namespaces.getProperties()) {
+ String prefix = propertyState.getName();
+ if (!prefix.equals(jcrPrimaryType)) {
+ mappedPrefixCount++;
+ if (!prefixes.contains(prefix)) {
+ LOG.error("The namespace registry is inconsistent:
namespace prefix {} is mapped to a namespace URI, but not contained in the list
of registered namespace prefixes.", prefix);
+ }
+ try {
+ getURI(prefix);
+ } catch (NamespaceException e) {
+ LOG.error("The namespace registry is inconsistent:
namespace prefix {} is not mapped to a namespace URI.", prefix);
+ }
+ }
+ }
+ //prefixes contains the unmapped empty prefix
+ if (mappedPrefixCount + 1 != prefixes.size()) {
+ LOG.error("The namespace registry is inconsistent: found {} mapped
namespace prefixes and {} registered namespace prefixes. The numbers have to be
equal.", mappedPrefixCount, prefixes.size());
+ }
+ int mappedUriCount = 0;
+ for (PropertyState propertyState : nsdata.getProperties()) {
+ String encodedUri = propertyState.getName();
+ switch (encodedUri) {
+ case REP_PREFIXES:
+ case REP_URIS:
+ case jcrPrimaryType:
+ break;
+ default:
+ mappedUriCount++;
+ if (!encodedUris.contains(encodedUri)) {
+ LOG.error("The namespace registry is inconsistent:
encoded namespace URI {} is mapped to a namespace prefix, but not contained in
the list of registered namespace URIs.", encodedUri);
+ }
+ try {
+ getPrefix(Text.unescapeIllegalJcrChars(encodedUri));
+ } catch (NamespaceException e) {
+ LOG.error("The namespace registry is inconsistent:
namespace URI {} is not mapped to a namespace prefix.", encodedUri);
+ }
+ }
+ }
+ //encodedUris contains the unmapped empty namespace URI
+ if (mappedUriCount + 1 != encodedUris.size()) {
+ LOG.error("The namespace registry is inconsistent: found {} mapped
namespace URIs and {} registered namespace URIs. The numbers have to be
equal.", mappedUriCount, encodedUris.size());
+ }
+ CONSISTENCY_CHECKED = true;
}
-
}
diff --git
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryTest.java
b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryTest.java
deleted file mode 100755
index d49bdcd46d..0000000000
---
a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/NamespaceRegistryTest.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.plugins.name;
-
-import org.apache.jackrabbit.oak.InitialContent;
-import org.apache.jackrabbit.oak.Oak;
-import org.apache.jackrabbit.oak.api.ContentSession;
-import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Root;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
-import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
-
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.HashMap;
-
-import static
org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_NSDATA;
-import static
org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_PREFIXES;
-import static
org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_URIS;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class NamespaceRegistryTest {
-
- /**
- * Artificially apply inconsistencies to the namespace registry and test
if the NamespaceRegistryModel
- * handles them correctly.
- * @throws Exception
- */
- @Test
- public void testNamespaceRegistryModel() throws Exception {
- try (ContentSession session = new Oak()
- .with(new OpenSecurityProvider())
- .with(new InitialContent())
- .with(new NamespaceEditorProvider())
- .createContentSession()) {
- Root root = session.getLatestRoot();
- ReadWriteNamespaceRegistry registry = new
ReadWriteNamespaceRegistry(root) {
- @Override
- protected Root getWriteRoot() {
- return session.getLatestRoot();
- }
- @Override
- protected void refresh() {
- root.refresh();
- }
- };
- Tree namespaces = root.getTree("/jcr:system/rep:namespaces");
- Tree nsdata = namespaces.getChild(REP_NSDATA);
- PropertyState prefixProp = nsdata.getProperty(REP_PREFIXES);
- PropertyState namespaceProp = nsdata.getProperty(REP_URIS);
-
- // Check the initial state of the namespace registry
- assertTrue(registry.checkConsistency(root));
- NamespaceRegistryModel model =
registry.createNamespaceRegistryModel(root);
- assertTrue(model.isConsistent());
- assertTrue(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(0, model.getRepairedMappings().size());
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- model.dump(out);
- String dump = out.toString(StandardCharsets.UTF_8);
- assertTrue(dump.contains("This namespace registry model is
consistent"));
-
- // Add a registered prefix without any mapping
- PropertyBuilder<String> builder =
PropertyBuilder.copy(Type.STRING, prefixProp);
- builder.addValue("foo");
- nsdata.setProperty(builder.getPropertyState());
-
- // Now it cannot be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertFalse(model.isFixable());
-
- assertEquals(1, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(0, model.getRepairedMappings().size());
-
- assertFalse(model.isConsistent());
- out = new ByteArrayOutputStream();
- model.dump(out);
- assertFalse(model.isConsistent());
- dump = out.toString(StandardCharsets.UTF_8);
- assertFalse(model.isConsistent());
- assertTrue(dump.contains("This namespace registry model is
inconsistent. The inconsistency can NOT be fixed."));
- assertFalse(model.isConsistent());
-
- model = model.tryRegistryRepair();
- assertFalse(model.isConsistent());
- assertFalse(model.isFixable());
-
- out = new ByteArrayOutputStream();
- model.dump(out);
- dump = out.toString(StandardCharsets.UTF_8);
- assertTrue(dump.contains("This namespace registry model is
inconsistent. The inconsistency can NOT be fixed."));
-
- // Now add a mapping to a namespace uri, but not the reverse
mapping
- namespaces.setProperty("foo", "urn:foo", Type.STRING);
-
- // This is inconsistent, but can be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(1, model.getRepairedMappings().size());
-
- out = new ByteArrayOutputStream();
- model.dump(out);
- dump = out.toString(StandardCharsets.UTF_8);
- assertTrue(dump.contains("This namespace registry model is
inconsistent. The inconsistency can be fixed."));
-
- model = model.tryRegistryRepair();
- assertTrue(model.isConsistent());
- assertTrue(model.isFixable());
-
- out = new ByteArrayOutputStream();
- model.dump(out);
- dump = out.toString(StandardCharsets.UTF_8);
- assertTrue(dump.contains("This namespace registry model is
consistent"));
-
- // Add a registered namespace uri without any mapping
- builder = PropertyBuilder.copy(Type.STRING, namespaceProp);
- builder.addValue("urn:bar");
- nsdata.setProperty(builder.getPropertyState());
-
- // Now it again cannot be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertFalse(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(1, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(1, model.getRepairedMappings().size());
-
- model = model.tryRegistryRepair();
- assertFalse(model.isConsistent());
- assertFalse(model.isFixable());
-
- // Now add a reverse mapping to a prefix, but not the forward
mapping
- nsdata.setProperty("urn%3Abar", "bar", Type.STRING);
-
- // Now it can be fixed automatically again
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(2, model.getRepairedMappings().size());
-
- model = model.tryRegistryRepair();
- assertTrue(model.isConsistent());
- assertTrue(model.isFixable());
-
- // Double a registered prefix
- builder = PropertyBuilder.copy(Type.STRING, prefixProp);
- builder.addValue("foo");
- nsdata.setProperty(builder.getPropertyState());
-
- // Can still be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(2, model.getRepairedMappings().size());
-
- model = model.tryRegistryRepair();
- assertTrue(model.isConsistent());
- assertTrue(model.isFixable());
-
- // Double a registered namespace uri
- builder = PropertyBuilder.copy(Type.STRING, namespaceProp);
- builder.addValue("urn:bar");
- nsdata.setProperty(builder.getPropertyState());
-
- // Can still be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(2, model.getRepairedMappings().size());
-
- // remap a prefix
- model = model.setMappings(Collections.singletonMap("foo",
"urn:foo2"));
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- // Add a registered namespace uri without any mapping
- builder = PropertyBuilder.copy(Type.STRING, namespaceProp);
- builder.addValue("urn:bar2");
- nsdata.setProperty(builder.getPropertyState());
-
- // Cannot be fixed automatically
- assertFalse(registry.checkConsistency(root));
- model = registry.createNamespaceRegistryModel(root);
- assertFalse(model.isConsistent());
- assertFalse(model.isFixable());
-
- // remap a prefix and map the new URI to make it fixable
- HashMap<String, String> mappings = new HashMap<>();
- mappings.put("foo", "urn:foo2");
- mappings.put("bar2", "urn:bar2");
- assertFalse(registry.checkConsistency(root));
- model = model.setMappings(mappings);
- assertFalse(model.isConsistent());
- assertTrue(model.isFixable());
-
- // Apply the fixed model
- model = model.tryRegistryRepair();
- assertTrue(model.isConsistent());
- assertTrue(model.isFixable());
- assertFalse(registry.checkConsistency(root));
- model.apply(root);
- assertTrue(registry.checkConsistency(root));
-
assertTrue(registry.createNamespaceRegistryModel(root).isConsistent());
-
- assertEquals(0, model.getDanglingPrefixes().size());
- assertEquals(0, model.getDanglingEncodedNamespaceUris().size());
- assertEquals(0, model.getRepairedMappings().size());
-
- // Check the extra mappings
- assertEquals("urn:foo2", registry.getURI("foo"));
- assertEquals("foo", registry.getPrefix("urn:foo2"));
- assertEquals("urn:bar2", registry.getURI("bar2"));
- assertEquals("bar2", registry.getPrefix("urn:bar2"));
- }
- }
-}
diff --git
a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
b/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
index 9ea6adf590..87a37a46a8 100644
--- a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
+++ b/oak-run/src/main/java/org/apache/jackrabbit/oak/run/AvailableModes.java
@@ -82,7 +82,6 @@ public final class AvailableModes {
builder.put("server", new ServerCommand());
builder.put("purge-index-versions", new
LucenePurgeOldIndexVersionCommand());
builder.put("create-test-garbage", new CreateGarbageCommand());
- builder.put("namespace-registry", new NamespaceRegistryCommand());
return Collections.unmodifiableMap(builder);
}
diff --git
a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommand.java
b/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommand.java
deleted file mode 100755
index 106497cbc0..0000000000
---
a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommand.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.run;
-
-import joptsimple.OptionParser;
-import org.apache.jackrabbit.oak.Oak;
-import org.apache.jackrabbit.oak.api.ContentSession;
-import org.apache.jackrabbit.oak.api.Root;
-import org.apache.jackrabbit.oak.commons.pio.Closer;
-import org.apache.jackrabbit.oak.plugins.name.NamespaceRegistryModel;
-import org.apache.jackrabbit.oak.plugins.name.ReadWriteNamespaceRegistry;
-import org.apache.jackrabbit.oak.run.cli.CommonOptions;
-import org.apache.jackrabbit.oak.run.cli.NodeStoreFixture;
-import org.apache.jackrabbit.oak.run.cli.NodeStoreFixtureProvider;
-import org.apache.jackrabbit.oak.run.cli.Options;
-import org.apache.jackrabbit.oak.run.commons.Command;
-import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Command to analyze and repair the namespace registry in an Oak repository
({@link NamespaceRegistryModel}).
- * Possible options are: --analyse, --fix, and --mappings, which will execute
corresponding operations on
- * the namespace registry.
- * <p>
- * --analyse executes an operation that will print the current consistency
state of the namespace registry to
- * the console. If the namespace registry is inconsistent and fixable, it will
also perform a dry run of the
- * --fix operation and print the result to the console.
- * <p>
- * --fix executes an operation that will attempt to repair an inconsistent the
namespace registry.
- * <p>
- * --mappings is an option for both operations, allowing to specify additional
namespace mappings in
- * the format "prefix=uri", which will be applied during the operation.
- */
-public class NamespaceRegistryCommand implements Command {
-
- public static final String NAME = "namespace-registry";
-
- private static final Logger LOG =
LoggerFactory.getLogger(NamespaceRegistryCommand.class);
- private static final String SUMMARY = "Provides commands to analyse the
integrity of the namespace registry and repair it if necessary.";
-
- private final OptionParser parser = new OptionParser();
-
- @Override
- public void execute(String... args) throws Exception {
-
- Options opts = getOptions(args);
- NamespaceRegistryOptions namespaceRegistryOpts =
opts.getOptionBean(NamespaceRegistryOptions.class);
-
- try (Closer closer = Utils.createCloserWithShutdownHook()) {
-
- NodeStoreFixture fixture = NodeStoreFixtureProvider.create(opts);
- closer.register(fixture);
-
- if (!checkParameters(namespaceRegistryOpts, fixture)) {
- return;
- }
- doExecute(fixture, namespaceRegistryOpts);
- } catch (Throwable e) {
- LOG.error("Error occurred while performing namespace registry
operation", e);
- e.printStackTrace(System.err);
- }
- }
-
- Options getOptions(String... args) throws IOException {
- Options opts = new Options();
- opts.setCommandName(NAME);
- opts.setSummary(SUMMARY);
- opts.setConnectionString(CommonOptions.DEFAULT_CONNECTION_STRING);
- opts.registerOptionsFactory(NamespaceRegistryOptions.FACTORY);
- opts.parseAndConfigure(parser, args);
- return opts;
- }
-
- private boolean checkParameters(NamespaceRegistryOptions
namespaceRegistryOptions, NodeStoreFixture fixture)
- throws IOException {
- if (!namespaceRegistryOptions.anyActionSelected()) {
- LOG.info("No actions specified");
- parser.printHelpOn(System.out);
- return false;
- } else if (fixture.getStore() == null) {
- LOG.info("No NodeStore specified");
- parser.printHelpOn(System.out);
- return false;
- }
- return true;
- }
-
- private void doExecute(NodeStoreFixture fixture, NamespaceRegistryOptions
namespaceRegistryOptions)
- throws Exception {
-
- boolean analyse = namespaceRegistryOptions.analyse();
- boolean fix = namespaceRegistryOptions.fix();
- List<String> mappings = namespaceRegistryOptions.mappings();
- Oak oak = new Oak(fixture.getStore()).with(new OpenSecurityProvider());
- try (ContentSession contentSession = oak.createContentSession()) {
- Root root = contentSession.getLatestRoot();
- ReadWriteNamespaceRegistry namespaceRegistry = new
ReadWriteNamespaceRegistry(root) {
- @Override
- protected Root getWriteRoot() {
- return root;
- }
- };
- if (analyse || fix) {
- NamespaceRegistryModel registryModel =
namespaceRegistry.createNamespaceRegistryModel(root);
- if (fix) {
- Map<String, String> additionalMappings = new HashMap<>();
- if (mappings != null) {
- for (String mapping : mappings) {
- String[] parts = mapping.split("=");
- if (parts.length != 2) {
- System.err.println("Invalid mapping: " +
mapping);
- return;
- }
- additionalMappings.put(parts[0].trim(),
parts[1].trim());
- }
- }
- registryModel =
registryModel.setMappings(additionalMappings);
- if (registryModel.isConsistent() &&
additionalMappings.isEmpty()) {
- System.out.println("The namespace registry is already
consistent. No action is required.");
- } else if (registryModel.isFixable()) {
- registryModel.dump(System.out);
- System.out.println();
- System.out.println("Now fixing the registry.");
- System.out.println();
- System.out.flush();
- NamespaceRegistryModel repaired =
registryModel.tryRegistryRepair();
- if (repaired == null) {
- System.out.println("An unknown error has occurred.
No changes have been made to the namespace registry.");
- return;
- }
- repaired.apply(root);
- root.commit();
- repaired.dump();
- } else {
- registryModel.dump();
- }
- } else {
- if (registryModel == null) {
- System.out.println("There is no namespace registry in
the repository.");
- } else {
- registryModel.dump();
- }
- }
- } else {
- System.err.println("No action specified. Use --analyse to
check the integrity of the namespace registry. Use --fix to repair it if
necessary and possible.");
- }
- }
- }
-}
diff --git
a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryOptions.java
b/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryOptions.java
deleted file mode 100755
index 49b5d8f357..0000000000
---
a/oak-run/src/main/java/org/apache/jackrabbit/oak/run/NamespaceRegistryOptions.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.jackrabbit.oak.run;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-import joptsimple.OptionSpec;
-import org.apache.jackrabbit.oak.run.cli.OptionsBean;
-import org.apache.jackrabbit.oak.run.cli.OptionsBeanFactory;
-
-public class NamespaceRegistryOptions implements OptionsBean {
-
- public static final OptionsBeanFactory FACTORY =
NamespaceRegistryOptions::new;
-
- private OptionSet options;
- private final Set<OptionSpec<Void>> actionOpts;
- private final Set<String> operationNames;
-
- private final OptionSpec<Void> analyseOpt;
- private final OptionSpec<Void> fixOpt;
- private final OptionSpec<String> mappingsOpt;
-
- public NamespaceRegistryOptions(OptionParser parser) {
- analyseOpt = parser.accepts("analyse", "List the prefix to namespace
map and check for consistency.");
- fixOpt = parser.accepts("fix", "List the prefix to namespace map,
check for consistency and fix any inconsistencies, if possible.");
- mappingsOpt = parser.accepts("mappings", "Optionally specify explicit
prefix to namespace mappings ad a list of prefix=uri
expressions").withRequiredArg();
- actionOpts = Set.of(analyseOpt, fixOpt);
- operationNames = collectionOperationNames(actionOpts);
- }
-
- @Override
- public void configure(OptionSet options) {
- this.options = options;
- }
-
- @Override
- public String title() {
- return "";
- }
-
- @Override
- public String description() {
- return "The namespace-registry command supports the following
operations.";
- }
-
- @Override
- public int order() {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public Set<String> operationNames() {
- return operationNames;
- }
-
- public boolean anyActionSelected() {
- for (OptionSpec<Void> spec : actionOpts) {
- if (options.has(spec)){
- return true;
- }
- }
- return false;
- }
-
- public boolean analyse() {
- return options.has(analyseOpt);
- }
-
- public boolean fix() {
- return options.has(fixOpt);
- }
-
- public List<String> mappings() {
- return options.valuesOf(mappingsOpt);
- }
-
- private static Set<String> collectionOperationNames(Set<OptionSpec<Void>>
actionOpts) {
- Set<String> result = new HashSet<>();
- for (OptionSpec<Void> spec : actionOpts){
- result.addAll(spec.options());
- }
- return result;
- }
-}
diff --git
a/oak-run/src/test/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommandTest.java
b/oak-run/src/test/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommandTest.java
deleted file mode 100755
index 89d0ed2d73..0000000000
---
a/oak-run/src/test/java/org/apache/jackrabbit/oak/run/NamespaceRegistryCommandTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.jackrabbit.oak.run;
-
-import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.oak.InitialContent;
-import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
-import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
-import org.apache.jackrabbit.oak.plugins.name.Namespaces;
-import org.apache.jackrabbit.oak.run.cli.NodeStoreFixture;
-import org.apache.jackrabbit.oak.run.cli.NodeStoreFixtureProvider;
-import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
-import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
-import org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeTrue;
-
-/**
- * Tests for the {@link NamespaceRegistryCommand}.
- */
-public class NamespaceRegistryCommandTest {
-
- private final NamespaceRegistryCommand cmd = new
NamespaceRegistryCommand();
- private DocumentNodeStore store;
-
- @Before
- public void before() throws CommitFailedException {
- assumeTrue(MongoUtils.isAvailable());
- try {
- NodeStoreFixture fixture =
NodeStoreFixtureProvider.create(cmd.getOptions(MongoUtils.URL, "--fix",
"--read-write"));
- store = (DocumentNodeStore) fixture.getStore();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- NodeBuilder rootBuilder = store.getRoot().builder();
- new InitialContent().initialize(rootBuilder);
- NodeBuilder system = rootBuilder.getChildNode(JcrConstants.JCR_SYSTEM);
- NodeBuilder namespaces =
system.getChildNode(NamespaceConstants.REP_NAMESPACES);
- namespaces.remove();
-
Namespaces.setupNamespaces(rootBuilder.getChildNode(JcrConstants.JCR_SYSTEM));
- store.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
- store.runBackgroundOperations();
- }
-
- @Test
- public void analyse() throws Exception {
- testCmd(new String[] { MongoUtils.URL, "--analyse" }, new String[] {
"This namespace registry model is consistent, containing the following mappings
from prefixes to namespace uris:" });
- }
-
- @Test
- public void fix() throws Exception {
- testCmd(new String[] { MongoUtils.URL, "--fix" }, new String[] { "The
namespace registry is already consistent. No action is required." });
- }
-
- @Test
- public void breakAndFix() throws Exception {
- NodeBuilder rootBuilder = store.getRoot().builder();
- NodeBuilder namespaces =
rootBuilder.getChildNode(JcrConstants.JCR_SYSTEM).getChildNode(NamespaceConstants.REP_NAMESPACES);
- namespaces.setProperty("foo", "urn:foo");
- store.merge(rootBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
- store.runBackgroundOperations();
- testCmd(new String[] { MongoUtils.URL, "--analyse" }, new String[] {
"This namespace registry model is inconsistent. The inconsistency can be
fixed.", "The repaired registry would contain the following mappings:", "foo ->
urn:foo" });
- testCmd(new String[] { MongoUtils.URL, "--fix", "--read-write" }, new
String[] { "This namespace registry model is consistent, containing the
following mappings from prefixes to namespace uris:", "foo -> urn:foo" });
- }
-
- @Test
- public void mappings() throws Exception {
- testCmd(new String[] { MongoUtils.URL, "--analyse" }, new String[] {
"This namespace registry model is consistent"});
- testCmd(new String[] { MongoUtils.URL, "--fix", "--mappings",
"foo=urn:foo", "--read-write" }, new String[] { "This namespace registry model
is consistent, containing the following mappings from prefixes to namespace
uris:", "foo -> urn:foo" });
- }
-
- private void testCmd(String[] opts, String[] output) throws Exception {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try(PrintStream printStream = new PrintStream(out)) {
- System.setOut(printStream);
- cmd.execute(opts);
- printStream.flush();
- for (String expected : output) {
- String s = out.toString(StandardCharsets.UTF_8);
- assertTrue(s.contains(expected));
- }
- }
- }
-}