This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-cpconverter.git
commit 4439a9f0e455df61c67852ce3173264ea4517825 Author: Robert Munteanu <[email protected]> AuthorDate: Tue Mar 1 14:33:57 2022 +0200 SLING-11134 - Extract Oak index definitions and package them as an additional file - add an IndexManager that coordinates the various components working on index definitions parsing and storage - add an IndexDefinitionsEntryHandler that is able to parse Oak index definitions and store them for later use in the IndexManager - add add IndexDefinitionsJsonWriter that ouputs the index definitions in a format known to the oak-run tool - wire the IndexManager to the ContentPackage2FeatureModelConverter and store the discovered index definitions in a feature model extension --- pom.xml | 4 +- .../ContentPackage2FeatureModelConverter.java | 16 +- ...ntentPackage2FeatureModelConverterLauncher.java | 2 + .../features/DefaultFeaturesManager.java | 24 ++- .../cpconverter/features/FeaturesManager.java | 2 + .../handlers/IndexDefinitionsEntryHandler.java | 128 ++++++++++++ .../cpconverter/index/DefaultIndexManager.java | 52 +++++ .../cpconverter/index/IndexDefinitions.java | 163 +++++++++++++++ .../index/IndexDefinitionsJsonWriter.java | 154 ++++++++++++++ .../feature/cpconverter/index/IndexManager.java | 60 ++++++ .../cpconverter/vltpkg/JcrNamespaceRegistry.java | 35 ++-- ...sling.feature.cpconverter.handlers.EntryHandler | 1 + .../feature/cpconverter/AdjustedFilterTest.java | 4 +- .../ContentPackage2FeatureModelConverterTest.java | 4 +- .../ConverterUserAndPermissionTest.java | 2 + .../handlers/IndexDefinitionsEntryHandlerTest.java | 223 +++++++++++++++++++++ .../index/IndexDefinitionsJsonWriterTest.java | 190 ++++++++++++++++++ .../index_multiple_files/META-INF/vault/filter.xml | 21 ++ .../META-INF/vault/nodetypes.cnd | 25 +++ .../META-INF/vault/properties.xml | 34 ++++ .../jcr_root/_oak_index/baz/.content.xml | 24 +++ .../jcr_root/_oak_index/lucene_custom/.content.xml | 64 ++++++ .../index_nested_tika/META-INF/vault/filter.xml | 20 ++ .../index_nested_tika/META-INF/vault/nodetypes.cnd | 24 +++ .../META-INF/vault/properties.xml | 34 ++++ .../index/index_nested_tika/jcr_root/.content.xml | 21 ++ .../jcr_root/_oak_index/.content.xml | 89 ++++++++ .../_oak_index/lucene-custom/tika/config.xml | 26 +++ .../lucene-custom/tika/config.xml.dir/.content.xml | 24 +++ .../index_single_file/META-INF/vault/filter.xml | 20 ++ .../index_single_file/META-INF/vault/nodetypes.cnd | 25 +++ .../META-INF/vault/properties.xml | 34 ++++ .../index/index_single_file/jcr_root/.content.xml | 32 +++ .../jcr_root/_oak_index/.content.xml | 35 ++++ 34 files changed, 1590 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index 945207d..40c17c7 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ <sling.java.version>8</sling.java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <picocli.version>3.6.0</picocli.version> - <org.apache.jackrabbit.vault.version>3.4.10</org.apache.jackrabbit.vault.version> + <org.apache.jackrabbit.vault.version>3.6.0</org.apache.jackrabbit.vault.version> <jackrabbit-api.version>2.18.4</jackrabbit-api.version> <jackrabbit-spi-commons.version>2.18.4</jackrabbit-spi-commons.version> <mockito-core.version>3.2.0</mockito-core.version> @@ -253,7 +253,7 @@ <dependency> <groupId>org.apache.jackrabbit.vault</groupId> <artifactId>vault-validation</artifactId> - <version>3.4.6</version> + <version>3.6.0</version> <scope>compile</scope> </dependency> diff --git a/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java b/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java index c077ab0..f6c5507 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverter.java @@ -57,6 +57,7 @@ import org.apache.sling.feature.cpconverter.handlers.EntryHandler; import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.NodeTypesEntryHandler; import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; +import org.apache.sling.feature.cpconverter.index.IndexManager; import org.apache.sling.feature.cpconverter.vltpkg.BaseVaultPackageScanner; import org.apache.sling.feature.cpconverter.vltpkg.PackagesEventsEmitter; import org.apache.sling.feature.cpconverter.vltpkg.RecollectorVaultPackageScanner; @@ -110,6 +111,8 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne private BundleSlingInitialContentExtractor bundleSlingInitialContentExtractor = new BundleSlingInitialContentExtractor(); + private IndexManager indexManager; + public enum PackagePolicy { /** * References the content package in the feature model and deploys via the {@link ContentPackage2FeatureModelConverter#artifactsDeployer} @@ -236,6 +239,15 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne return this; } + public @Nullable IndexManager getIndexManager() { + return indexManager; + } + + public @NotNull ContentPackage2FeatureModelConverter setIndexManager(IndexManager indexManager) { + this.indexManager = indexManager; + return this; + } + public @NotNull File getTempDirectory() { return this.tmpDirectory; } @@ -315,6 +327,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne aclManager.addRepoinitExtension(assemblers, featuresManager); bundleSlingInitialContentExtractor.addRepoInitExtension(assemblers, featuresManager); + indexManager.addRepoinitExtension(featuresManager); logger.info("Conversion complete!"); @@ -326,6 +339,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne aclManager.reset(); bundleSlingInitialContentExtractor.reset(); + indexManager.reset(); assemblers.clear(); try { @@ -379,7 +393,7 @@ public class ContentPackage2FeatureModelConverter extends BaseVaultPackageScanne // Please note: THIS IS A HACK to meet the new requirement without drastically change the original design // temporary swap the main handler to collect stuff VaultPackageAssembler handler = getMainPackageAssembler(); - + Properties parentProps = handler.getPackageProperties(); boolean isContainerPackage = PackageType.CONTAINER.equals(parentProps.get(PackageProperties.NAME_PACKAGE_TYPE)); setMainPackageAssembler(clonedPackage); diff --git a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java index 59098fb..14948ff 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java @@ -38,6 +38,7 @@ import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager; import org.apache.sling.feature.cpconverter.filtering.RegexBasedResourceFilter; import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; +import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; import org.apache.sling.feature.cpconverter.shared.ConverterConstants; import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter; import org.apache.sling.feature.io.json.FeatureJSONReader; @@ -217,6 +218,7 @@ public final class ContentPackage2FeatureModelConverterLauncher implements Runna .setBundleSlingInitialContentExtractor(bundleSlingInitialContentExtractor) .setEntryHandlersManager(new DefaultEntryHandlersManager(entryHandlerConfigsMap, !disableInstallerPolicy, slingInitialContentPolicy, bundleSlingInitialContentExtractor, systemUserRelPath)) .setAclManager(aclManager) + .setIndexManager(new DefaultIndexManager()) .setEmitter(DefaultPackagesEventsEmitter.open(featureModelsOutputDirectory)) .setFailOnMixedPackages(failOnMixedPackages) .setContentTypePackagePolicy(contentTypePackagePolicy); diff --git a/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java b/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java index c29a9fb..3eb9e6d 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/features/DefaultFeaturesManager.java @@ -50,6 +50,7 @@ import org.apache.sling.feature.Feature; import org.apache.sling.feature.cpconverter.ConverterException; import org.apache.sling.feature.cpconverter.accesscontrol.AclManager; import org.apache.sling.feature.cpconverter.accesscontrol.Mapping; +import org.apache.sling.feature.cpconverter.index.IndexManager; import org.apache.sling.feature.cpconverter.interpolator.SimpleVariablesInterpolator; import org.apache.sling.feature.cpconverter.interpolator.VariablesInterpolator; import org.apache.sling.feature.cpconverter.repoinit.NoOpVisitor; @@ -328,7 +329,7 @@ public class DefaultFeaturesManager implements FeaturesManager, PackagesEventsEm } return false; } - + private List<String> convertMappings(@Nullable String[] mappings, @NotNull String pid, boolean enforceServiceMappingByPrincipal) throws ConverterException { if (mappings == null) { return Collections.emptyList(); @@ -393,8 +394,8 @@ public class DefaultFeaturesManager implements FeaturesManager, PackagesEventsEm adjustConfigurationProperties(configuration, configurationProperties); } - - private void adjustConfigurationProperties(@NotNull Configuration configuration, + + private void adjustConfigurationProperties(@NotNull Configuration configuration, @NotNull Dictionary<String, Object> configurationProperties) { Enumeration<String> keys = configurationProperties.keys(); while (keys.hasMoreElements()) { @@ -538,7 +539,22 @@ public class DefaultFeaturesManager implements FeaturesManager, PackagesEventsEm repoInitExtension.setText(repoInitExtension.getText().concat(System.lineSeparator()).concat(text)); } } - + + @Override + public void addOrAppendOakIndexDefinitionsExtension(String source, String text) + throws IOException, ConverterException { + + Extension oakIndexDefsExtension = getRunMode(null).getExtensions().getByName(IndexManager.EXTENSION_NAME); + if (oakIndexDefsExtension == null) { + oakIndexDefsExtension = new Extension(ExtensionType.JSON, IndexManager.EXTENSION_NAME, ExtensionState.REQUIRED); + getRunMode(null).getExtensions().add(oakIndexDefsExtension); + oakIndexDefsExtension.setJSON(text); + } else { + oakIndexDefsExtension.setJSON(oakIndexDefsExtension.getText().concat(System.lineSeparator()).concat(text)); + } + + } + private static void checkReferences(@NotNull final Dictionary<String, Object> configurationProperties, @NotNull final String pid) throws ConverterException { final String[] references = Converters.standardConverter().convert(configurationProperties.get("references")).to(String[].class); if (references != null && references.length > 0) { diff --git a/src/main/java/org/apache/sling/feature/cpconverter/features/FeaturesManager.java b/src/main/java/org/apache/sling/feature/cpconverter/features/FeaturesManager.java index 13e0377..028d1d8 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/features/FeaturesManager.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/features/FeaturesManager.java @@ -70,6 +70,8 @@ public interface FeaturesManager { void addOrAppendRepoInitExtension(@NotNull String source, @NotNull String text, @Nullable String runMode) throws IOException, ConverterException; + void addOrAppendOakIndexDefinitionsExtension(String source, String text) throws IOException, ConverterException; + @NotNull Map<String, String> getNamespaceUriByPrefix(); diff --git a/src/main/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandler.java b/src/main/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandler.java new file mode 100644 index 0000000..b0770f8 --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandler.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.handlers; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; + +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.util.Text; +import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter; +import org.apache.jackrabbit.vault.fs.io.Archive; +import org.apache.jackrabbit.vault.fs.io.Archive.Entry; +import org.apache.jackrabbit.vault.fs.io.DocViewParser; +import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException; +import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.apache.jackrabbit.vault.util.PlatformNameFormat; +import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter; +import org.apache.sling.feature.cpconverter.ConverterException; +import org.apache.sling.feature.cpconverter.index.IndexDefinitions; +import org.apache.sling.feature.cpconverter.index.IndexManager; +import org.jetbrains.annotations.NotNull; +import org.xml.sax.InputSource; + +/** + * Handler for Jackrabbit Oak index definitions + * + * <p>This implementation scans content packages for entries stored under <tt>/oak:index</tt> + * and exposes them to the {@link IndexManager} for further processing. + * + */ +public class IndexDefinitionsEntryHandler extends AbstractRegexEntryHandler { + + private final class IndexDefinitionsParserHandler implements DocViewParserHandler { + private final WorkspaceFilter filter; + private IndexDefinitions definitions; + + public IndexDefinitionsParserHandler(WorkspaceFilter filter, IndexDefinitions definitions) { + this.filter = filter; + this.definitions = definitions; + } + + @Override + public void startDocViewNode(@NotNull String nodePath, @NotNull DocViewNode2 docViewNode, + @NotNull Optional<DocViewNode2> parentDocViewNode, int line, int column) + throws IOException, RepositoryException { + + if ( nodePath.startsWith(IndexDefinitions.OAK_INDEX_PATH) && filter.contains(nodePath) ) { + definitions.addNode(Text.getRelativeParent(nodePath, 1), docViewNode); + } + } + + @Override + public void endDocViewNode(@NotNull String nodePath, @NotNull DocViewNode2 docViewNode, + @NotNull Optional<DocViewNode2> parentDocViewNode, int line, int column) + throws IOException, RepositoryException { + // nothing to do + } + + @Override + public void startPrefixMapping(String prefix, String uri) { + definitions.registerPrefixMapping(prefix, uri); + } + } + + public IndexDefinitionsEntryHandler() { + super("/jcr_root/" + PlatformNameFormat.getPlatformName(IndexDefinitions.OAK_INDEX_NAME)+ "/.*(/)?/*.xml"); + } + + @Override + public void handle(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry, + @NotNull ContentPackage2FeatureModelConverter converter) throws IOException, ConverterException { + + IndexManager indexManager = converter.getIndexManager(); + if ( indexManager == null ) { + logger.info("{} not present, will skip index definition extraction", IndexManager.class.getName()); + } else { + try (InputStream is = archive.openInputStream(entry)) { + + String platformPath = path.replaceAll("^/jcr_root", "") + .replaceAll("/\\.content\\.xml$", "") + .replace(".dir", ""); + String repositoryPath = PlatformNameFormat.getRepositoryPath(platformPath); + InputSource inputSource = new InputSource(is); + + boolean isDocView = false; + // DocViewParser.isDocView closes the input stream it is passed + try ( InputStream isCheck = archive.openInputStream(entry) ) { + isDocView = DocViewParser.isDocView(new InputSource(isCheck)); + } + if ( isDocView ) { + DocViewParser parser = new DocViewParser(); + IndexDefinitionsParserHandler handler = new IndexDefinitionsParserHandler(archive.getMetaInf().getFilter(), indexManager.getIndexes()); + + parser.parse(repositoryPath, inputSource, handler); + + } else { + // binary file, should we attach? + if ( archive.getMetaInf().getFilter().contains(repositoryPath)) { + indexManager.getIndexes().registerBinary(repositoryPath, is); + } + } + + + } catch (XmlParseException e) { + throw new ConverterException("Failed parsing the index definitions", e); + } + } + + converter.getMainPackageAssembler().addEntry(path, archive, entry); + } +} diff --git a/src/main/java/org/apache/sling/feature/cpconverter/index/DefaultIndexManager.java b/src/main/java/org/apache/sling/feature/cpconverter/index/DefaultIndexManager.java new file mode 100644 index 0000000..df68e01 --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/index/DefaultIndexManager.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.index; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import org.apache.sling.feature.cpconverter.ConverterException; +import org.apache.sling.feature.cpconverter.features.FeaturesManager; + +public class DefaultIndexManager implements IndexManager { + + private IndexDefinitions indexDefinitions = new IndexDefinitions(); + private IndexDefinitionsJsonWriter writer = new IndexDefinitionsJsonWriter(indexDefinitions); + + @Override + public void addRepoinitExtension(FeaturesManager features) throws IOException, ConverterException { + + if ( indexDefinitions.getIndexes().isEmpty() ) + return; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.writeAsJson(out); + features.addOrAppendOakIndexDefinitionsExtension("content-package", out.toString(StandardCharsets.UTF_8.toString())); + } + + @Override + public IndexDefinitions getIndexes() { + return indexDefinitions; + } + + @Override + public void reset() { + indexDefinitions = new IndexDefinitions(); + writer = new IndexDefinitionsJsonWriter(indexDefinitions); + } +} diff --git a/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitions.java b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitions.java new file mode 100644 index 0000000..300e42c --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitions.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.index; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.commons.io.IOUtils; +import org.apache.jackrabbit.spi.Name; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.jetbrains.annotations.NotNull; + +/** + * Holds information about discovered index definitions + * + */ +public class IndexDefinitions { + + public static final String OAK_INDEX_NAME = "oak:index"; + public static final String OAK_INDEX_PATH = "/" + OAK_INDEX_NAME; // NOSONAR - java:S1075 does not apply as this is not a filesystem path + + private final Map<String, List<DocViewNode2>> children = new HashMap<>(); + private final Map<String, byte[]> binaries = new HashMap<>(); + private Map<String, String> prefixesToUris = new HashMap<>(); + private Map<String, String> urisToPrefixes = new HashMap<>(); + + public void addNode(@NotNull String parentPath, @NotNull DocViewNode2 node) { + List<DocViewNode2> currentChildren = children.computeIfAbsent(parentPath, k -> new ArrayList<>()); + DocViewNode2 existing = null; + for ( DocViewNode2 currentChild : currentChildren ) { + + // prevent duplicates + if ( currentChild.getName().equals(node.getName() )) { + // new node holds less information. There should not be a scenario where we need to + // merge properties. + if ( node.getProperties().size() <= currentChild.getProperties().size() ) { + return; + } + + existing = currentChild; + } + } + + // remove node marked as placeholder + if ( existing != null ) { + currentChildren.remove(existing); + } + + // add new node + currentChildren.add(node); + } + + public @NotNull List<DocViewNode2> getIndexes() { + return getChildren(OAK_INDEX_PATH); + } + + public @NotNull List<DocViewNode2> getChildren(@NotNull String parentPath) { + return children.getOrDefault(parentPath, Collections.emptyList()); + } + + + /** + * Returns a name in compact format + * + * <p>Maps a fully qualified {@link Name name}, e.g. ['http://jackrabbit.apache.org/oak/ns/1.0','index'] to a compact name + * like <tt>oak:index</tt></p> + * + * @param name The name to map + * @return the compact name + */ + public @NotNull String toShortName(@NotNull Name name) { + if ( name.getNamespaceURI().length() == 0 ) + return name.getLocalName(); + return urisToPrefixes.get(name.getNamespaceURI()) + ":" + name.getLocalName(); + } + + /** + * Registers a binary entry at the specified repository path + * + * <p>The input stream may be fully read into memory, and therefore is not expected to be unreasonably large.</p> + * + * <p>The input stream will be fully read, but not closed.</p> + * + * @param repositoryPath The JCR repository path where the binary was found + * @param is the input stream for the binary + * @throws IOException in case of I/O problems + */ + public void registerBinary(@NotNull String repositoryPath, @NotNull InputStream is) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + IOUtils.copy(is, out); + binaries.put(repositoryPath, out.toByteArray()); + } + + /** + * Returns a potential binary registered for a repository path + * + * @param repositoryPath the path of the repository + * @return an optional wrapping the binary data, possibly {@link Optional#empty() empty} + */ + public @NotNull Optional<byte[]> getBinary(@NotNull String repositoryPath) { + return Optional.ofNullable(binaries.get(repositoryPath)); + } + + /** + * Registers a prefix mapping for a specified uri + * + * @param prefix the prefix + * @param uri the uri + */ + public void registerPrefixMapping(@NotNull String prefix, @NotNull String uri) { + prefixesToUris.put(prefix, uri); + urisToPrefixes.put(uri, prefix); + } + + /** + * Dumps a compact representation of the data + * + * <p>Useful for debugging purposes only</p> + * + * @param out the PrintStream to use + */ + public void dump(@NotNull PrintStream out) { + out.println("---------"); + out.println(OAK_INDEX_NAME); + dumpChildren(out, OAK_INDEX_PATH); + out.println("---------"); + } + + private void dumpChildren(PrintStream out, String parentPath) { + + StringBuilder padding = new StringBuilder(); + int depth = parentPath.split("/").length - 1; + for ( int i = 0 ; i < 2 * depth; i++) + padding.append(' '); + + for ( DocViewNode2 node : children.getOrDefault(parentPath, Collections.emptyList()) ) { + out.println(padding.toString() + toShortName(node.getName())); + dumpChildren(out, parentPath + '/' + node.getName().getLocalName()); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriter.java b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriter.java new file mode 100644 index 0000000..a14fab5 --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriter.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.index; + +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +import javax.jcr.PropertyType; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonValue; +import javax.json.stream.JsonGenerator; + +import org.apache.jackrabbit.util.Base64; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.apache.jackrabbit.vault.util.DocViewProperty2; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Writes index definitions in a JSON format that can be consumed by the <tt>oak-run</tt> tool. + * + * @see <a href= + * "https://jackrabbit.apache.org/oak/docs/query/oak-run-indexing.html">Oak-Run + * indexing</a> + */ +public class IndexDefinitionsJsonWriter { + + private static final Function<String, JsonValue> BLOB_MAPPER = s -> Json.createValue(":blobid:" + Base64.encode(s)); + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final IndexDefinitions indexDefinitions; + + public IndexDefinitionsJsonWriter(@NotNull IndexDefinitions indexDefinitions) { + this.indexDefinitions = indexDefinitions; + } + + /** + * Writes the index definitions to the specified <tt>out</tt> + * + * @param out the output stream to write to + */ + public void writeAsJson(@NotNull OutputStream out) { + try ( JsonGenerator root = Json.createGenerator(out) ) { + root.writeStartObject(); + for ( DocViewNode2 index : indexDefinitions.getIndexes() ) { + write(root, index, IndexDefinitions.OAK_INDEX_PATH); + } + root.writeEnd(); // end object declaration + } + } + + private void write(JsonGenerator json, DocViewNode2 index, String parentPath) { + + String nodeName = indexDefinitions.toShortName(index.getName()); + String objectKey = parentPath.equals(IndexDefinitions.OAK_INDEX_PATH) ? + IndexDefinitions.OAK_INDEX_PATH + "/" + nodeName : nodeName; + + // 1. start object + json.writeStartObject(objectKey); + + // 2. write properties + for ( DocViewProperty2 property : index.getProperties() ) { + + String propertyName = indexDefinitions.toShortName(property.getName()); + + switch ( property.getType() ) { + case PropertyType.STRING: + case PropertyType.UNDEFINED: + write(json, propertyName, property.getStringValues(), s -> Json.createValue("str:" + s )); + break; + case PropertyType.LONG: + write(json, propertyName, property.getStringValues(), s -> Json.createValue(Long.parseLong(s) )); + break; + case PropertyType.BOOLEAN: + write(json, propertyName, property.getStringValues(), s -> ( Boolean.parseBoolean(s) ? JsonValue.TRUE : JsonValue.FALSE) ); + break; + case PropertyType.NAME: + write(json, propertyName, property.getStringValues(), s -> Json.createValue("nam:" + s )); + break; + case PropertyType.DOUBLE: + write(json, propertyName, property.getStringValues(), s -> Json.createValue(Double.parseDouble(s) )); + break; + case PropertyType.DATE: + write(json, propertyName, property.getStringValues(), s -> Json.createValue("dat:" + s) ); + break; + case PropertyType.PATH: + write(json, propertyName, property.getStringValues(), s -> Json.createValue("pat:" + s) ); + break; + case PropertyType.URI: + write(json, propertyName, property.getStringValues(), s -> Json.createValue("uri:" + s) ); + break; + case PropertyType.BINARY: + write(json, propertyName, property.getStringValues(), BLOB_MAPPER ); + break; + default: + logger.warn("Skipping property {}, don't know how to handle type {}; values: {}", property.getName(), property.getType(), property.getStringValues()); + + } + } + + // 3. write nt:data entries for nt:resource children of nt:files + // in this case, this is the nt:resource node + Optional<byte[]> binary = indexDefinitions.getBinary(parentPath); + if ( binary.isPresent() ) { + String blobAsString = new String(binary.get(), StandardCharsets.UTF_8); + write(json, "jcr:data", Collections.singletonList(blobAsString), BLOB_MAPPER); + }; + + // 4. write children + String nodePath = parentPath + "/" + nodeName; // NOSONAR - java:S1075 does not apply as this is not a filesystem path + for ( DocViewNode2 child : indexDefinitions.getChildren(nodePath)) { + write(json, child, nodePath); + } + + // 5. end object + json.writeEnd(); + } + + private void write(JsonGenerator json, String propertyName, List<String> propertyValues, Function<String, JsonValue> mapper) { + if ( propertyValues.size() == 1 ) { + json.write(propertyName, mapper.apply(propertyValues.get(0))); + return; + } + + JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + propertyValues.stream() + .map( mapper ) + .forEach( arrayBuilder::add ); + + json.write(propertyName, arrayBuilder.build()); + } + +} diff --git a/src/main/java/org/apache/sling/feature/cpconverter/index/IndexManager.java b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexManager.java new file mode 100644 index 0000000..1f4573f --- /dev/null +++ b/src/main/java/org/apache/sling/feature/cpconverter/index/IndexManager.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.index; + +import java.io.IOException; + +import org.apache.sling.feature.cpconverter.ConverterException; +import org.apache.sling.feature.cpconverter.features.FeaturesManager; +import org.jetbrains.annotations.NotNull; + +/** + * Point of entry for logic related to handling Oak indexes + * + * @see <a href= + * "https://jackrabbit.apache.org/oak/docs/query/oak-run-indexing.html">Oak-Run + * indexing</a> + */ +public interface IndexManager { + + public static final String EXTENSION_NAME = "oak-index-definitions"; + + /** + * Returns the index definitions managed by this instance + * + * <p>The returned object may be used to record data discovered about oak indexes</p> + * + * @return the index definitions + */ + @NotNull IndexDefinitions getIndexes(); + + /** + * Records the Oak index data using the features manager + * + * <p>The index definitions will be recoreded as a JSON repoinit extension named {@value #EXTENSION_NAME} .</p> + * + * @param features + * @throws IOException + * @throws ConverterException + */ + void addRepoinitExtension(FeaturesManager features) throws IOException, ConverterException; + + /** + * Resets the internal state + */ + void reset(); +} diff --git a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/JcrNamespaceRegistry.java b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/JcrNamespaceRegistry.java index e1ea0b5..d88f63e 100644 --- a/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/JcrNamespaceRegistry.java +++ b/src/main/java/org/apache/sling/feature/cpconverter/vltpkg/JcrNamespaceRegistry.java @@ -16,37 +16,38 @@ */ package org.apache.sling.feature.cpconverter.vltpkg; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import javax.jcr.NamespaceException; +import javax.jcr.NamespaceRegistry; +import javax.jcr.RepositoryException; +import javax.jcr.ValueFactory; +import javax.jcr.nodetype.NodeTypeManager; +import javax.xml.namespace.NamespaceContext; + import org.apache.commons.lang3.StringUtils; import org.apache.jackrabbit.commons.SimpleValueFactory; import org.apache.jackrabbit.commons.cnd.CndImporter; import org.apache.jackrabbit.commons.cnd.ParseException; import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver; -import org.apache.jackrabbit.vault.validation.spi.impl.nodetype.NodeTypeManagerProvider; +import org.apache.jackrabbit.vault.util.StandaloneManagerProvider; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.jcr.NamespaceException; -import javax.jcr.NamespaceRegistry; -import javax.jcr.RepositoryException; -import javax.jcr.ValueFactory; -import javax.jcr.nodetype.NodeTypeManager; -import javax.xml.namespace.NamespaceContext; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - /** Simple namespace registry backed by a map */ public class JcrNamespaceRegistry implements NamespaceRegistry, NamespaceResolver, NamespaceContext { - + private final Collection<String> registeredCndSystemIds = new ArrayList<>(); - private final NodeTypeManagerProvider ntManagerProvider = new NodeTypeManagerProvider(); + private final StandaloneManagerProvider ntManagerProvider = new StandaloneManagerProvider(); private final NodeTypeManager ntManager = ntManagerProvider.getNodeTypeManager(); private final Logger logger = LoggerFactory.getLogger(JcrNamespaceRegistry.class); - + public JcrNamespaceRegistry() throws RepositoryException, ParseException, IOException { ntManagerProvider.registerNamespace(PREFIX_XML, NAMESPACE_XML); ntManagerProvider.registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0"); diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler b/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler index 46fb089..b8ad4c8 100644 --- a/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler +++ b/src/main/resources/META-INF/services/org.apache.sling.feature.cpconverter.handlers.EntryHandler @@ -2,6 +2,7 @@ org.apache.sling.feature.cpconverter.handlers.BundleEntryHandler org.apache.sling.feature.cpconverter.handlers.ConfigurationEntryHandler org.apache.sling.feature.cpconverter.handlers.ContentPackageEntryHandler org.apache.sling.feature.cpconverter.handlers.GroupEntryHandler +org.apache.sling.feature.cpconverter.handlers.IndexDefinitionsEntryHandler org.apache.sling.feature.cpconverter.handlers.JsonConfigurationEntryHandler org.apache.sling.feature.cpconverter.handlers.NodeTypesEntryHandler org.apache.sling.feature.cpconverter.handlers.PrivilegesHandler diff --git a/src/test/java/org/apache/sling/feature/cpconverter/AdjustedFilterTest.java b/src/test/java/org/apache/sling/feature/cpconverter/AdjustedFilterTest.java index 0792378..86fd426 100644 --- a/src/test/java/org/apache/sling/feature/cpconverter/AdjustedFilterTest.java +++ b/src/test/java/org/apache/sling/feature/cpconverter/AdjustedFilterTest.java @@ -27,6 +27,7 @@ import org.apache.sling.feature.cpconverter.features.FeaturesManager; import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; +import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; import org.apache.sling.feature.cpconverter.shared.ConverterConstants; import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter; import org.jetbrains.annotations.NotNull; @@ -59,7 +60,8 @@ public class AdjustedFilterTest extends AbstractConverterTest { converter = new ContentPackage2FeatureModelConverter() .setEntryHandlersManager(handlersManager) - .setAclManager(aclManager); + .setAclManager(aclManager) + .setIndexManager(new DefaultIndexManager()); outputDirectory = new File(System.getProperty("java.io.tmpdir"), getClass().getName() + '_' + System.currentTimeMillis()); FeaturesManager featuresManager = new DefaultFeaturesManager(true, 5, outputDirectory, null, null, null, aclManager); diff --git a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java index 4aea947..f4e0441 100644 --- a/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java +++ b/src/test/java/org/apache/sling/feature/cpconverter/ContentPackage2FeatureModelConverterTest.java @@ -68,6 +68,7 @@ import org.apache.sling.feature.cpconverter.filtering.RegexBasedResourceFilter; import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; +import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; import org.apache.sling.feature.cpconverter.shared.ConverterConstants; import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter; import org.apache.sling.feature.io.json.FeatureJSONReader; @@ -100,7 +101,8 @@ public class ContentPackage2FeatureModelConverterTest extends AbstractConverterT converter = new ContentPackage2FeatureModelConverter() .setEntryHandlersManager(handlersManager) .setFeaturesManager(new DefaultFeaturesManager(new File(""))) - .setAclManager(new DefaultAclManager()); + .setAclManager(new DefaultAclManager()) + .setIndexManager(new DefaultIndexManager()); } @After diff --git a/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java b/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java index 6ff8aea..9e46b80 100644 --- a/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java +++ b/src/test/java/org/apache/sling/feature/cpconverter/ConverterUserAndPermissionTest.java @@ -35,6 +35,7 @@ import org.apache.sling.feature.cpconverter.features.FeaturesManager; import org.apache.sling.feature.cpconverter.handlers.DefaultEntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.EntryHandlersManager; import org.apache.sling.feature.cpconverter.handlers.slinginitialcontent.BundleSlingInitialContentExtractor; +import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; import org.apache.sling.feature.cpconverter.shared.ConverterConstants; import org.apache.sling.feature.cpconverter.vltpkg.DefaultPackagesEventsEmitter; import org.apache.sling.feature.io.json.FeatureJSONReader; @@ -146,6 +147,7 @@ public class ConverterUserAndPermissionTest extends AbstractConverterTest { converter = new ContentPackage2FeatureModelConverter() .setEntryHandlersManager(handlersManager) .setAclManager(aclManager) + .setIndexManager(new DefaultIndexManager()) .setContentTypePackagePolicy(PackagePolicy.REFERENCE); outputDirectory = new File(System.getProperty("java.io.tmpdir"), getClass().getName() + '_' + System.currentTimeMillis()); diff --git a/src/test/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandlerTest.java b/src/test/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandlerTest.java new file mode 100644 index 0000000..6bf7c55 --- /dev/null +++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandlerTest.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.handlers; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Objects; + +import javax.jcr.NamespaceRegistry; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.jackrabbit.vault.fs.io.Archive; +import org.apache.jackrabbit.vault.fs.io.Archive.Entry; +import org.apache.jackrabbit.vault.fs.io.FileArchive; +import org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter; +import org.apache.sling.feature.cpconverter.ConverterException; +import org.apache.sling.feature.cpconverter.index.DefaultIndexManager; +import org.apache.sling.feature.cpconverter.index.IndexDefinitions; +import org.apache.sling.feature.cpconverter.vltpkg.BaseVaultPackageScanner; +import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler; +import org.assertj.core.api.Condition; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.mockito.Mockito; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +public class IndexDefinitionsEntryHandlerTest { + + @Test + public void matches() { + IndexDefinitionsEntryHandler handler = new IndexDefinitionsEntryHandler(); + assertThat(handler.matches("/jcr_root/_oak_index/.content.xml")).isTrue(); + assertThat(handler.matches("/jcr_root/_oak_index/bar/.content.xml")).isTrue(); + assertThat(handler.matches("/jcr_root/_oak_index/lucene/tika/config.xml")).isTrue(); + assertThat(handler.matches("/jcr_root/_oak_index/.vlt")).isFalse(); + assertThat(handler.matches("/jcr_root/apps/_oak_index/.content.xml")).isFalse(); + } + + @Test + public void handleSingleFileIndexDefinition() throws IOException, ConverterException { + + DefaultIndexManager manager = new DefaultIndexManager(); + + traverseForIndexing(manager, "index_single_file"); + + IndexDefinitions defs = manager.getIndexes(); + List<DocViewNode2> indexes = defs.getIndexes(); + + assertThat(indexes).as("index definitions") + .hasSize(1) + .element(0) + .has( Conditions.localName("foo") ) + .has( Conditions.property("type", "property") ); + + } + + @Test + public void handleMultiFileIndexDefinition() throws IOException, ConverterException { + + DefaultIndexManager manager = new DefaultIndexManager(); + + traverseForIndexing(manager, "index_multiple_files"); + + IndexDefinitions defs = manager.getIndexes(); + List<DocViewNode2> indexes = defs.getIndexes(); + + assertThat(indexes).as("index definitions") + .hasSize(2); + + assertThat(indexes).as("baz index") + .element(0).has( Conditions.localName("baz") ); + assertThat(indexes).as("lucene_custom index") + .element(1) + .has( Conditions.localName("lucene_custom") ) + .has( Conditions.property("type", "lucene") ) + .has(Conditions.childWithLocalName("/oak:index/lucene_custom", "indexRules", defs)); + + } + + @Test + public void handleIndexDefinitionWithNestedTikaXml() throws IOException, ConverterException, ParserConfigurationException, SAXException { + DefaultIndexManager manager = new DefaultIndexManager(); + + traverseForIndexing(manager, "index_nested_tika"); + + IndexDefinitions defs = manager.getIndexes(); + List<DocViewNode2> indexes = defs.getIndexes(); + + assertThat(indexes).as("index definitions") + .hasSize(1) + .element(0) + .has(Conditions.localName("lucene-custom")); + + DocViewNode2 luceneCustom = indexes.get(0); + assertThat(luceneCustom).as("lucene index definition") + .has(Conditions.childWithLocalName("/oak:index/lucene-custom", "indexRules", defs)) + .has(Conditions.childWithLocalName("/oak:index/lucene-custom", "tika", defs)); + + List<DocViewNode2> luceneCustomChildren = defs.getChildren("/oak:index/lucene-custom"); + assertThat(luceneCustomChildren).as("lucene index definition children") + .hasSize(2); + + DocViewNode2 tikaConfigNode = luceneCustomChildren.stream() + .filter( c -> c.getName().getLocalName().equals("tika") ) + .findFirst() + .get(); + + assertThat(tikaConfigNode).as("tika config node") + .has(Conditions.childWithLocalName("/oak:index/lucene-custom/tika","config.xml", defs)); + + List<DocViewNode2> children = defs.getChildren("/oak:index/lucene-custom/tika"); + assertThat(children).as("tika config child nodes") + .hasSize(1) + .element(0) + .has( Conditions.localName("config.xml") ) + .has( Conditions.property(NamespaceRegistry.NAMESPACE_JCR, "primaryType", "nt:file", defs) ); + + byte[] tikaConfig = defs.getBinary("/oak:index/lucene-custom/tika/config.xml").get(); + assertIsValidXml(tikaConfig); + } + + + private void assertIsValidXml(byte[] tikeConfig) throws ParserConfigurationException, SAXException, IOException { + + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = dbFactory.newDocumentBuilder(); + documentBuilder.parse(new InputSource(new ByteArrayInputStream(tikeConfig))); + } + + private void traverseForIndexing(DefaultIndexManager manager, String testPackageDirectory) throws IOException, ConverterException { + + try ( Archive archive = new FileArchive(TestUtils.getPackageRelativeFile(getClass(), "index", testPackageDirectory)) ) { + archive.open(true); + + try ( ContentPackage2FeatureModelConverter converter = new ContentPackage2FeatureModelConverter() ) { + + converter.setMainPackageAssembler(Mockito.mock(VaultPackageAssembler.class)) + .setIndexManager(manager); + IndexDefinitionsEntryHandler handler = new IndexDefinitionsEntryHandler(); + + new BaseVaultPackageScanner(true) { + @Override + protected void onFile(@NotNull String path, @NotNull Archive archive, @NotNull Entry entry) + throws IOException, ConverterException { + if ( handler.matches(path) ) + handler.handle(path, archive, entry, converter); + } + }.traverse(new ZipVaultPackage(archive, true)); + } + + } + } + + static class Conditions { + static final Condition<DocViewNode2> localName(String localName) { + return new Condition<DocViewNode2>("Node with name " + localName) { + @Override + public boolean matches(DocViewNode2 value) { + return value.getName().getLocalName().equals(localName); + } + }; + } + + static final Condition<DocViewNode2> childWithLocalName(String path, String childName, IndexDefinitions defs) { + return new Condition<DocViewNode2>("Node with a child with localName " + childName) { + @Override + public boolean matches(DocViewNode2 value) { + return defs.getChildren(path).stream().filter( n -> n.getName().getLocalName().equals(childName)).findAny().isPresent(); + } + }; + } + + static final Condition<DocViewNode2> property(String localPropertyName, String propertyValue) { + return new Condition<DocViewNode2>("Node with property '" + localPropertyName + "' equal to '" + propertyValue + "'") { + @Override + public boolean matches(DocViewNode2 value) { + return value.getProperties().stream(). + anyMatch( p -> { + return p.getName().getLocalName().equals(localPropertyName) + && p.getStringValue().isPresent() && Objects.equals(p.getStringValue().get(), propertyValue); + }); + } + }; + } + + static final Condition<DocViewNode2> property(String uri, String localPropertyName, String propertyValue, IndexDefinitions defs) { + return new Condition<DocViewNode2>("Node with property '{" + uri +"}" + localPropertyName + "' equal to '" + propertyValue + "'") { + @Override + public boolean matches(DocViewNode2 value) { + return value.getProperties().stream(). + anyMatch( p -> { + return p.getName().getLocalName().equals(localPropertyName) + && Objects.equals(p.getName().getNamespaceURI(), uri) + && p.getStringValue().isPresent() && Objects.equals(p.getStringValue().get(), propertyValue); + }); + } + }; + } + } + +} diff --git a/src/test/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriterTest.java b/src/test/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriterTest.java new file mode 100644 index 0000000..a68ccad --- /dev/null +++ b/src/test/java/org/apache/sling/feature/cpconverter/index/IndexDefinitionsJsonWriterTest.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.sling.feature.cpconverter.index; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import javax.jcr.NamespaceRegistry; +import javax.jcr.PropertyType; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonString; +import javax.json.JsonValue; +import javax.json.stream.JsonParser; + +import org.apache.jackrabbit.spi.NameFactory; +import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; +import org.apache.jackrabbit.util.Base64; +import org.apache.jackrabbit.vault.util.DocViewNode2; +import org.apache.jackrabbit.vault.util.DocViewProperty2; +import org.assertj.core.api.Condition; +import org.junit.Before; +import org.junit.Test; + +public class IndexDefinitionsJsonWriterTest { + + // copied from oak-spi-core/NamespaceConstants to not add a dependency on Oak + private static final String PREFIX_OAK = "oak"; + private static final String NAMESPACE_OAK = "http://jackrabbit.apache.org/oak/ns/1.0"; + + private NameFactory nameFactory; + private IndexDefinitions definitions; + + @Before + public void setUp() { + nameFactory = NameFactoryImpl.getInstance(); + definitions = new IndexDefinitions(); + definitions.registerPrefixMapping(NamespaceRegistry.PREFIX_NT, NamespaceRegistry.NAMESPACE_NT); + definitions.registerPrefixMapping(NamespaceRegistry.PREFIX_JCR, NamespaceRegistry.NAMESPACE_JCR); + definitions.registerPrefixMapping(PREFIX_OAK, NAMESPACE_OAK); + + } + + @Test + public void emptyInput() throws IOException { + JsonObject root = generateAndParse(definitions); + assertThat(root).as("index definitions").isEmpty(); + } + + @Test + public void propertyIndexDefinition() throws IOException { + + Collection<DocViewProperty2> fooProps = new ArrayList<>(); + fooProps.add(new DocViewProperty2(nameFactory.create("{}type"), "property")); + fooProps.add(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), PREFIX_OAK+":QueryIndexDefinition")); + fooProps.add(new DocViewProperty2(nameFactory.create("{}reindex"), Boolean.FALSE.toString(), PropertyType.BOOLEAN)); + fooProps.add(new DocViewProperty2(nameFactory.create("{}reindexCount"), "1", PropertyType.LONG)); + + definitions.addNode("/oak:index", new DocViewNode2(nameFactory.create("{}foo"), fooProps)); + + Collection<DocViewProperty2> barProps = new ArrayList<>(); + fooProps.add(new DocViewProperty2(nameFactory.create("{}type"), "property")); + fooProps.add(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), PREFIX_OAK+":QueryIndexDefinition")); + fooProps.add(new DocViewProperty2(nameFactory.create("{}reindex"), Boolean.TRUE.toString(), PropertyType.BOOLEAN)); + fooProps.add(new DocViewProperty2(nameFactory.create("{}reindexCount"), "25", PropertyType.LONG)); + + definitions.addNode("/oak:index", new DocViewNode2(nameFactory.create("{}bar"), barProps)); + + JsonObject root = generateAndParse(definitions); + assertThat(root).as("indexDefinitions") + .hasSize(2) + .hasEntrySatisfying("/oak:index/foo", Conditions.isJsonObject()) + .hasEntrySatisfying("/oak:index/bar", Conditions.isJsonObject()); + + JsonObject fooIndex = root.getJsonObject("/oak:index/foo"); + assertThat(fooIndex).as("foo index") + .hasSize(4) + .contains(entry("type", Json.createValue("str:property"))) + .contains(entry("jcr:primaryType", Json.createValue("nam:oak:QueryIndexDefinition"))) + .contains(entry("reindex", JsonObject.FALSE)) + .contains(entry("reindexCount", Json.createValue(1))); + } + + @Test + public void luceneIndexDefinitionWithTikaConfig() throws IOException { + + String configXmlFileContents = "<properties/>"; + + // lucene index + Collection<DocViewProperty2> luceneProps = new ArrayList<>(); + luceneProps.add(new DocViewProperty2(nameFactory.create("{}type"), "lucene")); + luceneProps.add(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), PREFIX_OAK+":QueryIndexDefinition")); + luceneProps.add(new DocViewProperty2(nameFactory.create("{}reindex"), Boolean.FALSE.toString(), PropertyType.BOOLEAN)); + luceneProps.add(new DocViewProperty2(nameFactory.create("{}reindexCount"), "1", PropertyType.LONG)); + luceneProps.add(new DocViewProperty2(nameFactory.create("{}includePropertyTypes"), Arrays.asList("String", "Binary"), PropertyType.STRING)); + + definitions.addNode("/oak:index", new DocViewNode2(nameFactory.create("{}lucene"), luceneProps)); + + // index rules node + List<DocViewProperty2> indexRulesProps = Collections.singletonList(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), "nt:unstructured")); + + definitions.addNode("/oak:index/lucene", new DocViewNode2(nameFactory.create("{}indexRules"), indexRulesProps)); + + // tika node + List<DocViewProperty2> tikaProps = Collections.singletonList(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), "nt:unstructured")); + + definitions.addNode("/oak:index/lucene", new DocViewNode2(nameFactory.create("{}tika"), tikaProps)); + + // tika config.xml node + List<DocViewProperty2> configXmlProps = Collections.singletonList(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), "nt:file")); + + definitions.addNode("/oak:index/lucene/tika", new DocViewNode2(nameFactory.create("{}config.xml"), configXmlProps)); + definitions.registerBinary("/oak:index/lucene/tika/config.xml", new ByteArrayInputStream(configXmlFileContents.getBytes(StandardCharsets.UTF_8))); + + // tika config.xml jcr:content node + List<DocViewProperty2> jcrContentProps = Collections.singletonList(new DocViewProperty2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "primaryType"), "nt:resource")); + definitions.addNode("/oak:index/lucene/tika/config.xml", new DocViewNode2(nameFactory.create(NamespaceRegistry.NAMESPACE_JCR, "resource"), jcrContentProps)); + + JsonObject root = generateAndParse(definitions); + System.out.println(root); + + assertThat(root).as("root index") + .hasEntrySatisfying("/oak:index/lucene", Conditions.isJsonObject()); + + JsonObject lucene = root.getJsonObject("/oak:index/lucene"); + assertThat(lucene).as("lucene index") + .hasEntrySatisfying("tika", Conditions.isJsonObject()); + + JsonObject tika = lucene.getJsonObject("tika"); + assertThat(tika).as("tika node index") + .hasEntrySatisfying("config.xml", Conditions.isJsonObject()); + + JsonObject configNode = tika.getJsonObject("config.xml"); + assertThat(configNode).as("config node") + .hasEntrySatisfying("jcr:resource", Conditions.isJsonObject()); + + JsonObject jcrResource = configNode.getJsonObject("jcr:resource"); + JsonString binaryEntry = jcrResource.getJsonString("jcr:data"); + assertThat(binaryEntry).as("config.xml blob") + .hasFieldOrPropertyWithValue("string", ":blobid:" + Base64.encode(configXmlFileContents)); + } + + + private JsonObject generateAndParse(IndexDefinitions definitions) throws IOException { + + IndexDefinitionsJsonWriter writer = new IndexDefinitionsJsonWriter(definitions); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writer.writeAsJson(out); + + JsonParser parser = Json.createParser(new ByteArrayInputStream(out.toByteArray())); + JsonObject root = parser.getObject(); + return root; + } + + static class Conditions { + public static Condition<JsonValue> isJsonObject() { + return new Condition<JsonValue>("Is a " + JsonObject.class.getSimpleName()) { + @Override + public boolean matches(JsonValue value) { + return value instanceof JsonObject; + } + }; + } + } + +} diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/filter.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/filter.xml new file mode 100644 index 0000000..9e1e22c --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/filter.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<workspaceFilter version="1.0"> + <filter root="/oak:index/baz"/> + <filter root="/oak:index/lucene_custom"/> +</workspaceFilter> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/nodetypes.cnd b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/nodetypes.cnd new file mode 100644 index 0000000..29762da --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/nodetypes.cnd @@ -0,0 +1,25 @@ +/* + * 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. + */ + +<'sling'='http://sling.apache.org/jcr/sling/1.0'> +<'nt'='http://www.jcp.org/jcr/nt/1.0'> + +[sling:Folder] > nt:folder + - * (undefined) + - * (undefined) multiple + + * (nt:base) = sling:Folder version + diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/properties.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/properties.xml new file mode 100644 index 0000000..8a7b22d --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/META-INF/vault/properties.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!-- + 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. + --> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>FileVault Package Properties</comment> +<entry key="createdBy">admin</entry> +<entry key="name">index_multiple_files</entry> +<entry key="lastModified">2011-11-15T09:45:14.664+01:00</entry> +<entry key="lastModifiedBy">admin</entry> +<entry key="created">2011-11-15T09:45:14.685+01:00</entry> +<entry key="buildCount">1</entry> +<entry key="version"/> +<entry key="dependencies"/> +<entry key="packageFormatVersion">2</entry> +<entry key="description"/> +<entry key="lastWrapped">2011-11-15T09:45:14.664+01:00</entry> +<entry key="group"/> +<entry key="lastWrappedBy">admin</entry> +</properties> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/baz/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/baz/.content.xml new file mode 100644 index 0000000..2296ed9 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/baz/.content.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal" + jcr:primaryType="oak:QueryIndexDefinition" + propertyNames="[foo]" + reindex="{Boolean}false" + reindexCount="{Long}1" + type="property"> +</jcr:root> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/lucene_custom/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/lucene_custom/.content.xml new file mode 100644 index 0000000..cbb532c --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_multiple_files/jcr_root/_oak_index/lucene_custom/.content.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + jcr:primaryType="oak:QueryIndexDefinition" + async="[async]" + includePropertyTypes="[String,Binary]" + reindex="{Boolean}false" + reindexCount="{Long}1" + seed="{Long}4516265077047968953" + type="lucene"> + <indexRules + jcr:primaryType="nt:unstructured"> + <nt:base + jcr:primaryType="nt:unstructured" + includePropertyTypes="[String,Binary]"> + <properties + jcr:primaryType="nt:unstructured"> + <sling:alias + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:alias"/> + <jcr:lastmodifiedby + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="jcr:lastmodifiedby"/> + <sling:resourcetype + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:resourcetype"/> + <jcr:createdby + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="jcr:createdby"/> + <sling:vanitypath + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:vanitypath"/> + <prop0 + jcr:primaryType="nt:unstructured" + analyzed="{Boolean}true" + isRegexp="{Boolean}true" + name="^[^\\/]*$" + nodeScopeIndex="{Boolean}true" + propertyIndex="{Boolean}false" + useInExcerpt="{Boolean}true"/> + </properties> + </nt:base> + </indexRules> +</jcr:root> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/filter.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/filter.xml new file mode 100644 index 0000000..1da236d --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/filter.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<workspaceFilter version="1.0"> + <filter root="/oak:index/lucene-custom"/> +</workspaceFilter> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/nodetypes.cnd b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/nodetypes.cnd new file mode 100644 index 0000000..82c6bd6 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/nodetypes.cnd @@ -0,0 +1,24 @@ +/* + * 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. + */ +<'sling'='http://sling.apache.org/jcr/sling/1.0'> +<'nt'='http://www.jcp.org/jcr/nt/1.0'> + +[sling:Folder] > nt:folder + - * (undefined) + - * (undefined) multiple + + * (nt:base) = sling:Folder version + diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/properties.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/properties.xml new file mode 100644 index 0000000..1032a7f --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/META-INF/vault/properties.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!-- + 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. + --> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>FileVault Package Properties</comment> +<entry key="createdBy">admin</entry> +<entry key="name">index_single_file</entry> +<entry key="lastModified">2011-11-15T09:45:14.664+01:00</entry> +<entry key="lastModifiedBy">admin</entry> +<entry key="created">2011-11-15T09:45:14.685+01:00</entry> +<entry key="buildCount">1</entry> +<entry key="version"/> +<entry key="dependencies"/> +<entry key="packageFormatVersion">2</entry> +<entry key="description"/> +<entry key="lastWrapped">2011-11-15T09:45:14.664+01:00</entry> +<entry key="group"/> +<entry key="lastWrappedBy">admin</entry> +</properties> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/.content.xml new file mode 100644 index 0000000..741d31d --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/.content.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + jcr:primaryType="rep:root" + sling:resourceType="sling:redirect" + sling:target="/starter.html"/> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/.content.xml new file mode 100644 index 0000000..5db0614 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/.content.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" + jcr:primaryType="nt:unstructured"> + <jcrLanguage/> + <event.job.topic/> + <extensionType/> + <slingeventEventId/> + <repMembers/> + <counter/> + <acPrincipalName/> + <uuid/> + <slingVanityPath/> + <jcrLockOwner/> + <status/> + <type/> + <slingResource/> + <nodetype/> + <reference/> + <lucene-custom + jcr:primaryType="oak:QueryIndexDefinition" + async="async" + includePropertyTypes="[String,Binary]" + reindex="{Boolean}false" + reindexCount="{Long}3" + seed="{Long}8337987644672197141" + type="lucene"> + <indexRules jcr:primaryType="nt:unstructured"> + <nt:base + jcr:primaryType="nt:unstructured" + includePropertyTypes="[String,Binary]"> + <properties jcr:primaryType="nt:unstructured"> + <sling:alias + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:alias"/> + <jcr:lastmodifiedby + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="jcr:lastmodifiedby"/> + <sling:resourcetype + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:resourcetype"/> + <jcr:createdby + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="jcr:createdby"/> + <sling:vanitypath + jcr:primaryType="nt:unstructured" + index="{Boolean}false" + name="sling:vanitypath"/> + <prop0 + jcr:primaryType="nt:unstructured" + analyzed="{Boolean}true" + isRegexp="{Boolean}true" + name="^[^\\/]*$" + nodeScopeIndex="{Boolean}true" + propertyIndex="{Boolean}false" + useInExcerpt="{Boolean}true"/> + </properties> + </nt:base> + </indexRules> + <tika jcr:primaryType="nt:unstructured"> + <config.xml/> + </tika> + </lucene-custom> + <lockCreated/> + <principalName/> + <lucene/> + <slingAlias/> + <authorizableId/> + <slingResourceType/> +</jcr:root> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml new file mode 100644 index 0000000..fa7c2be --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml @@ -0,0 +1,26 @@ +<!-- + 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. + --> +<properties> + <parsers> + <parser class="org.apache.tika.parser.EmptyParser"> + <mime>application/zip</mime> + <mime>application/msword</mime> + <mime>application/vnd.ms-excel</mime> + <mime>application/pdf</mime> + </parser> + </parsers> +</properties> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml.dir/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml.dir/.content.xml new file mode 100644 index 0000000..0436956 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_nested_tika/jcr_root/_oak_index/lucene-custom/tika/config.xml.dir/.content.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" + jcr:primaryType="nt:file"> + <jcr:content + jcr:lastModifiedBy="admin" + jcr:mimeType="application/xml" + jcr:primaryType="nt:resource"/> +</jcr:root> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/filter.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/filter.xml new file mode 100644 index 0000000..43772b3 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/filter.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<workspaceFilter version="1.0"> + <filter root="/oak:index/foo"/> +</workspaceFilter> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/nodetypes.cnd b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/nodetypes.cnd new file mode 100644 index 0000000..29762da --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/nodetypes.cnd @@ -0,0 +1,25 @@ +/* + * 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. + */ + +<'sling'='http://sling.apache.org/jcr/sling/1.0'> +<'nt'='http://www.jcp.org/jcr/nt/1.0'> + +[sling:Folder] > nt:folder + - * (undefined) + - * (undefined) multiple + + * (nt:base) = sling:Folder version + diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/properties.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/properties.xml new file mode 100644 index 0000000..1032a7f --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/META-INF/vault/properties.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<!-- + 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. + --> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties> +<comment>FileVault Package Properties</comment> +<entry key="createdBy">admin</entry> +<entry key="name">index_single_file</entry> +<entry key="lastModified">2011-11-15T09:45:14.664+01:00</entry> +<entry key="lastModifiedBy">admin</entry> +<entry key="created">2011-11-15T09:45:14.685+01:00</entry> +<entry key="buildCount">1</entry> +<entry key="version"/> +<entry key="dependencies"/> +<entry key="packageFormatVersion">2</entry> +<entry key="description"/> +<entry key="lastWrapped">2011-11-15T09:45:14.664+01:00</entry> +<entry key="group"/> +<entry key="lastWrappedBy">admin</entry> +</properties> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/.content.xml new file mode 100644 index 0000000..fd08de2 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/.content.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal" + jcr:mixinTypes="[rep:AccessControllable]" + jcr:primaryType="rep:root" + sling:resourceType="sling:redirect" + sling:target="/index.html"> + <rep:policy/> + <jcr:system/> + <var/> + <libs/> + <etc/> + <apps/> + <content/> + <tmp/> + <home/> +</jcr:root> diff --git a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/_oak_index/.content.xml b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/_oak_index/.content.xml new file mode 100644 index 0000000..3f1e4c7 --- /dev/null +++ b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/index_single_file/jcr_root/_oak_index/.content.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<jcr:root xmlns:oak="http://jackrabbit.apache.org/oak/ns/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" xmlns:rep="internal" + jcr:mixinTypes="[rep:AccessControllable]" + jcr:primaryType="nt:unstructured"> + <foo + jcr:primaryType="oak:QueryIndexDefinition" + propertyNames="[foo]" + reindex="{Boolean}false" + reindexCount="{Long}1" + type="property"> + </foo> + <bar + jcr:primaryType="oak:QueryIndexDefinition" + propertyNames="[bar]" + reindex="{Boolean}false" + reindexCount="{Long}1" + type="property"> + </bar> +</jcr:root>
