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


The following commit(s) were added to refs/heads/master by this push:
     new 8ff5dea  SLING-12469 - Index definitions are not extracted when 
individual definitions are defined in the filter.xml as roots (#179)
8ff5dea is described below

commit 8ff5dead11ee7b84f962b9a7496e50828ad19a15
Author: Robert Munteanu <[email protected]>
AuthorDate: Wed Nov 6 11:05:22 2024 +0100

    SLING-12469 - Index definitions are not extracted when individual 
definitions are defined in the filter.xml as roots (#179)
---
 .../handlers/IndexDefinitionsEntryHandler.java     | 130 ++++++++++++++++-----
 .../handlers/IndexDefinitionsEntryHandlerTest.java |  23 ++++
 .../index/full_aggregate/META-INF/vault/filter.xml |  20 ++++
 .../jcr_root/_oak_index/.content.xml               |  19 +++
 .../jcr_root/_oak_index/jcrCreated.xml             |  63 ++++++++++
 5 files changed, 226 insertions(+), 29 deletions(-)

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
index 2da38f2..cda7033 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandler.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandler.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import static java.lang.String.format;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Optional;
@@ -61,35 +63,33 @@ public class IndexDefinitionsEntryHandler extends 
AbstractRegexEntryHandler {
             String.join("|", EXCLUDED_EXTENSIONS) +
             ")$)[^.]+$"; // match everything else
 
-    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.contains(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);
+    private static final String EXTENSION_XML = ".xml";
+    
+    // we hardcode the node type name to avoid a dependency on oak-core
+    private static final String NODETYPE_OAK_QUERY_INDEX_DEFINITION = 
"oak:QueryIndexDefinition";
+    
+    private static final String removeXmlExtension(String input) {
+        if ( !input.endsWith(EXTENSION_XML) )
+            throw new IllegalArgumentException(format("Input string '%s' does 
not end in '%s'", input, EXTENSION_XML));
+        
+        return input.substring(0, input.length() - EXTENSION_XML.length());
+        
+    }
+    
+    private static boolean 
isOakIndexDefinitionAsFullCoverageAggregate(@NotNull String repositoryPath,
+            @NotNull Archive archive, @NotNull Entry entry) throws 
IOException, XmlParseException {
+        
+        if ( !repositoryPath.endsWith(EXTENSION_XML) )
+            return false;
+        
+        DocViewParser parser = new DocViewParser(new 
SimpleNamespaceResolver());
+        
+        try (InputStream isCheck = archive.openInputStream(entry)) {
+            IndexDefinitionAsFullCoverageDetectorParserHandler parserHandler = 
new IndexDefinitionAsFullCoverageDetectorParserHandler(repositoryPath);
+            
+            parser.parse(repositoryPath, new InputSource(isCheck), 
parserHandler);
+            
+            return parserHandler.isIsIndexDefinitionAsFullCoverage();
         }
     }
 
@@ -120,6 +120,11 @@ public class IndexDefinitionsEntryHandler extends 
AbstractRegexEntryHandler {
                 }
                 if ( isDocView ) {
                     DocViewParser parser = new DocViewParser(new 
SimpleNamespaceResolver());
+                    
+                    // SLING-12469 - support index definitions serialized as 
full coverage aggregates
+                    if 
(isOakIndexDefinitionAsFullCoverageAggregate(repositoryPath, archive, entry)) {
+                        repositoryPath = removeXmlExtension(repositoryPath);
+                    }
                     IndexDefinitionsParserHandler handler = new 
IndexDefinitionsParserHandler(archive.getMetaInf().getFilter(), 
indexManager.getIndexes());
 
                     parser.parse(repositoryPath, inputSource, handler);
@@ -139,4 +144,71 @@ public class IndexDefinitionsEntryHandler extends 
AbstractRegexEntryHandler {
 
         converter.getMainPackageAssembler().addEntry(path, archive, entry);
     }
+
+    static class DocViewParserHandlerAdapter implements DocViewParserHandler {
+
+        @Override
+        public void startDocViewNode(@NotNull String nodePath, @NotNull 
DocViewNode2 docViewNode,
+                @NotNull Optional<DocViewNode2> parentDocViewNode, int line, 
int column)
+                throws IOException, RepositoryException {
+            // override as needed
+        }
+
+        @Override
+        public void endDocViewNode(@NotNull String nodePath, @NotNull 
DocViewNode2 docViewNode,
+                @NotNull Optional<DocViewNode2> parentDocViewNode, int line, 
int column)
+                throws IOException, RepositoryException {
+            // override as needed
+        }
+    }
+    
+    static class IndexDefinitionsParserHandler extends 
DocViewParserHandlerAdapter {
+        
+        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.contains(IndexDefinitions.OAK_INDEX_PATH) && 
filter.contains(nodePath) ) {
+                definitions.addNode(Text.getRelativeParent(nodePath, 1), 
docViewNode);
+            }
+        }
+
+        @Override
+        public void startPrefixMapping(String prefix, String uri) {
+            definitions.registerPrefixMapping(prefix, uri);
+        }
+    }
+    
+    static final class IndexDefinitionAsFullCoverageDetectorParserHandler 
extends DocViewParserHandlerAdapter {
+        private final @NotNull String repositoryPath;
+        private boolean isIndexDefinitionAsFullCoverage;
+
+        private IndexDefinitionAsFullCoverageDetectorParserHandler(@NotNull 
String repositoryPath) {
+            this.repositoryPath = repositoryPath;
+        }
+
+        @Override
+        public void startDocViewNode(@NotNull String nodePath, @NotNull 
DocViewNode2 docViewNode,
+                @NotNull Optional<DocViewNode2> parentDocViewNode, int line, 
int column)
+                throws IOException, RepositoryException {
+            boolean isTopLevelDocViewNode = nodePath.equals(repositoryPath);
+            boolean isOakQueryIndexDefinition = 
docViewNode.getPrimaryType().orElse("").equals(NODETYPE_OAK_QUERY_INDEX_DEFINITION);
+            if ( isTopLevelDocViewNode   && isOakQueryIndexDefinition) { // 
top-level node
+                isIndexDefinitionAsFullCoverage = true;
+            }
+        }
+        public boolean isIsIndexDefinitionAsFullCoverage() {
+            return isIndexDefinitionAsFullCoverage;
+        }
+        
+    }
 }
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
index e724dd4..257a844 100644
--- 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandlerTest.java
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/IndexDefinitionsEntryHandlerTest.java
@@ -255,6 +255,29 @@ public class IndexDefinitionsEntryHandlerTest {
 
         traverseForIndexing(manager, "index_missing_namespaces");
     }
+    
+    @Test
+    public void handleIndexDefinitionsAsFullAggregates() throws IOException, 
ConverterException {
+
+        DefaultIndexManager manager = new DefaultIndexManager();
+
+        traverseForIndexing(manager, "full_aggregate");
+
+        IndexDefinitions defs = manager.getIndexes();
+        Map<String, List<DocViewNode2>> indexes = defs.getIndexes();
+
+        assertThat(indexes).as("index definitions")
+            .hasSize(1)
+            .containsKey("/oak:index");
+
+       List<DocViewNode2> rootIndexes = indexes.get("/oak:index");
+       assertThat(rootIndexes).as("root oak indexes")
+            .hasSize(1)
+            .element(0)
+                .has( Conditions.localName("jcrCreated") )
+                .has( Conditions.property("type", "lucene") )
+                .has( Conditions.childWithLocalName("/oak:index/jcrCreated", 
"indexRules", defs));
+    }
 
     private void assertIsValidXml(byte[] tikeConfig) throws 
ParserConfigurationException, SAXException, IOException {
 
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/META-INF/vault/filter.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/META-INF/vault/filter.xml
new file mode 100644
index 0000000..dd1b898
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/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/jcrCreated"/>
+</workspaceFilter>
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/.content.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/.content.xml
new file mode 100644
index 0000000..bbb035e
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/.content.xml
@@ -0,0 +1,19 @@
+<?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";
+    jcr:primaryType="nt:unstructured"/>
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/jcrCreated.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/jcrCreated.xml
new file mode 100644
index 0000000..8f541bb
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/index/full_aggregate/jcr_root/_oak_index/jcrCreated.xml
@@ -0,0 +1,63 @@
+<?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="oak:QueryIndexDefinition"
+    propertyNames="{Name}[jcr:created]"
+    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>
+</jcr:root>
\ No newline at end of file

Reply via email to