You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/02/20 10:59:29 UTC

[jackrabbit-filevault-package-maven-plugin] 02/02: JCRVLT-559 add mojo for generating CND file containing used node types and namespace of a package

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/JCVLT-558-generate-cnd
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault-package-maven-plugin.git

commit 5bd4b0c19f41c0c9d59f5d9a67aef5cf147b7916
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Sun Feb 20 11:59:18 2022 +0100

    JCRVLT-559 add mojo for generating CND file containing used node types
    and namespace of a package
---
 pom.xml                                            |   2 +-
 .../filevault/maven/packaging/GenerateCndMojo.java | 118 ++++++++++++++++-----
 2 files changed, 95 insertions(+), 25 deletions(-)

diff --git a/pom.xml b/pom.xml
index c38113c..dd93ec7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,7 +32,7 @@
     <!-- ====================================================================== -->
     <groupId>org.apache.jackrabbit</groupId>
     <artifactId>filevault-package-maven-plugin</artifactId>
-    <version>1.2.3-SNAPSHOT</version>
+    <version>1.3.0-SNAPSHOT</version>
     <packaging>maven-plugin</packaging>
 
     <name>Apache Jackrabbit FileVault - Package Maven Plugin</name>
diff --git a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateCndMojo.java b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateCndMojo.java
index 3c2804c..7a1fb60 100644
--- a/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateCndMojo.java
+++ b/src/main/java/org/apache/jackrabbit/filevault/maven/packaging/GenerateCndMojo.java
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.jackrabbit.filevault.maven.packaging;
 
 import java.io.File;
@@ -24,6 +40,7 @@ import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.commons.cnd.ParseException;
 import org.apache.jackrabbit.jcr2spi.nodetype.NodeTypeDefinitionProvider;
 import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QNodeDefinition;
 import org.apache.jackrabbit.spi.QNodeTypeDefinition;
 import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
 import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
@@ -34,8 +51,9 @@ import org.apache.jackrabbit.vault.fs.io.DocViewParser.XmlParseException;
 import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler;
 import org.apache.jackrabbit.vault.util.Constants;
 import org.apache.jackrabbit.vault.util.DocViewNode2;
-import org.apache.jackrabbit.vault.validation.spi.impl.nodetype.NodeTypeManagerProvider;
-import org.apache.jackrabbit.vault.validation.spi.impl.nodetype.NodeTypeValidatorFactory;
+import org.apache.jackrabbit.vault.util.StandaloneManagerProvider;
+import org.apache.jackrabbit.vault.validation.spi.util.classloaderurl.CndUtil;
+import org.apache.jackrabbit.vault.validation.spi.util.classloaderurl.URLFactory;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
@@ -63,7 +81,7 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
      * The source cnd urls.
      * Must be urls
      */
-    @Parameter()
+    @Parameter(property = "vault.inputCndUrls")
     List<String> inputCndUrls = new LinkedList<>();
 
     public GenerateCndMojo() {
@@ -74,20 +92,37 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
     public void execute() throws MojoExecutionException, MojoFailureException {
         getLog().info("Retrieving used node types and namespaces...");
         try {
-            NodeTypeManagerProvider ntManagerProvider = new NodeTypeManagerProvider();
-            NodeTypeValidatorFactory.registerNodeTypes(inputCndUrls, ntManagerProvider);
-            DocViewParser docViewParser = new DocViewParser(ntManagerProvider.getNamespaceResolver());
+            StandaloneManagerProvider managerProvider = new StandaloneManagerProvider();
+            URLFactory.processUrlStreams(CndUtil.resolveJarUrls(inputCndUrls), t -> {
+                try {
+                    managerProvider.registerNodeTypes(t);
+                } catch (IOException e) {
+                    throw new UncheckedIOException(e);
+                }
+                catch (ParseException | RepositoryException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            });
+            DocViewParser docViewParser = new DocViewParser(managerProvider.getNamespaceResolver());
             File cndOutputFile = new File(getGeneratedVaultDir(true), Constants.NODETYPES_CND);
             // traverse relevant package files
-            Set<String> nodeTypes = collectNodeTypes(getJcrSourceDirectory().toPath(), docViewParser);
-            Collection<? extends QNodeTypeDefinition> ntDefinitons = resolveNodeTypes(nodeTypes, ntManagerProvider.getNameResolver(),
-                    ntManagerProvider.getNodeTypeDefinitionProvider());
+            final Set<String> nodeTypes;
+            try {
+                nodeTypes = collectNodeTypes(getJcrSourceDirectory().toPath(), docViewParser);
+            } catch (UncheckedIOException e) {
+                throw e.getCause();
+            }
+            getLog().info("Found " + nodeTypes.size() + " unique node types" );
+            Collection<? extends QNodeTypeDefinition> ntDefinitons = resolveNodeTypes(nodeTypes, managerProvider.getNameResolver(),
+                    managerProvider.getNodeTypeDefinitionProvider());
 
-            // writes the cnd into the given file
+            // writes the CND into the given file
             try (Writer writer = Files.newBufferedWriter(cndOutputFile.toPath(), StandardCharsets.US_ASCII)) {
-                writeCnd(ntDefinitons, ntManagerProvider.getNamespaceResolver(), writer);
+                writeCnd(ntDefinitons, managerProvider.getNodeTypeDefinitionProvider(), managerProvider.getNamespaceResolver(), writer);
             }
-        } catch (IOException | RepositoryException | ParseException e) {
+
+            getLog().info("Written CND file to " + getProjectRelativeFilePath(cndOutputFile));
+        } catch (IOException | RepositoryException | ParseException | IllegalStateException e) {
             throw new MojoExecutionException("Error while writing CND: " + e.getMessage(), e);
         }
     }
@@ -101,7 +136,7 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
 
         NodeTypeCollectorHandler nodeTypeCollectorHandler = new NodeTypeCollectorHandler(nodeTypes);
         // extract types from docview files
-        try (Stream<Path> filePaths = Files.find(jcrRootPath, 50, (path, attributes) -> path.getFileName().toString().endsWith(".xml"))) {
+        try (Stream<Path> filePaths = Files.find(jcrRootPath, 50, (path, attributes) -> !attributes.isDirectory() && path.getFileName().toString().endsWith(".xml"))) {
             filePaths.forEach(p -> {
                 try {
                     getNodeTypes(p, docViewParser, nodeTypeCollectorHandler);
@@ -115,21 +150,22 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
 
     private void getNodeTypes(Path docViewFile, DocViewParser docViewParser, NodeTypeCollectorHandler nodeTypeCollectorHandler) throws IOException {
         try (Reader reader = Files.newBufferedReader(docViewFile, StandardCharsets.UTF_8)) {
+            reader.mark(1024);
             if (!DocViewParser.isDocView(reader)) {
                 return;
             }
-            InputSource inputSource = new InputSource();
-            inputSource.setCharacterStream(reader);
+            reader.reset();
+            InputSource inputSource = new InputSource(reader);
             try {
+                // TODO: get root node path
                 docViewParser.parse("/", inputSource, nodeTypeCollectorHandler);
             } catch (XmlParseException e) {
                 getLog().warn("Could not parse " + docViewFile + ". Ignore for node type definition generation!", e);
             }
         }
     }
-    
-    static final class NodeTypeCollectorHandler implements DocViewParserHandler {
 
+    final class NodeTypeCollectorHandler implements DocViewParserHandler {
         private final Set<String> nodeTypes;
         public NodeTypeCollectorHandler(Set<String> nodeTypes) {
             this.nodeTypes = nodeTypes;
@@ -138,8 +174,15 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
         @Override
         public void startDocViewNode(@NotNull String nodePath, @NotNull DocViewNode2 docViewNode, @NotNull Optional<DocViewNode2> parentDocViewNode, int line, int column)
                 throws IOException, RepositoryException {
-            docViewNode.getPrimaryType().ifPresent(type -> nodeTypes.add(type));
-            nodeTypes.addAll(docViewNode.getMixinTypes());
+            Optional<String> primaryType = docViewNode.getPrimaryType();
+            if (primaryType.isPresent()) {
+                if (nodeTypes.add(primaryType.get())) {
+                    getLog().debug("Found primary type " + primaryType.get() + " in " + nodePath);
+                }
+            }
+            if (nodeTypes.addAll(docViewNode.getMixinTypes())) {
+                getLog().debug("Found mixin types " + docViewNode.getMixinTypes() + " in " + nodePath);
+            }
         }
 
         @Override
@@ -150,20 +193,20 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
     }
 
     // resolve from cnd file
-    private Collection<? extends QNodeTypeDefinition> resolveNodeTypes(Set<String> nodeTypeNames, NameResolver nameResolver, NodeTypeDefinitionProvider ntDefinitionProvider) throws IOException, RepositoryException, ParseException {
+    private Collection<QNodeTypeDefinition> resolveNodeTypes(Set<String> nodeTypeNames, NameResolver nameResolver, NodeTypeDefinitionProvider ntDefinitionProvider) throws IOException, RepositoryException, ParseException {
         return resolveNodeTypesFromNames(nodeTypeNames.stream()
                 .map(name -> {
                     try {
                         return nameResolver.getQName(name);
                     } catch (IllegalNameException|NamespaceException e) {
-                        throw new IllegalStateException(e);
+                        throw new IllegalStateException("Cannot get expanded name for type " + name, e);
                     }
                 })
                 .collect(Collectors.toSet()), 
                 ntDefinitionProvider);
     }
 
-    static Collection<? extends QNodeTypeDefinition> resolveNodeTypesFromNames(Set<Name> nodeTypeNames, NodeTypeDefinitionProvider ntDefinitionProvider) throws IOException, RepositoryException, ParseException {
+    static Collection<QNodeTypeDefinition> resolveNodeTypesFromNames(Set<Name> nodeTypeNames, NodeTypeDefinitionProvider ntDefinitionProvider) throws IOException, RepositoryException, ParseException {
         return nodeTypeNames.stream().map(name -> {
             try {
                 return ntDefinitionProvider.getNodeTypeDefinition(name);
@@ -173,11 +216,38 @@ public class GenerateCndMojo extends AbstractSourceAndMetadataPackageMojo {
         }).collect(Collectors.toList());
     }
 
-    private void writeCnd(Collection<? extends QNodeTypeDefinition> nodeTypeDefinitions, NamespaceResolver nsResolver, Writer writer) throws IOException {
+    private void writeCnd(Collection<? extends QNodeTypeDefinition> nodeTypeDefinitions, NodeTypeDefinitionProvider ntDefinitionProvider, NamespaceResolver nsResolver, Writer writer) throws IOException, RepositoryException {
         CompactNodeTypeDefWriter cndWriter = new CompactNodeTypeDefWriter(writer, nsResolver, true);
+        Set<Name> written = new HashSet<>();
         for (QNodeTypeDefinition nodeTypeDefinition : nodeTypeDefinitions) {
-            cndWriter.write(nodeTypeDefinition);
+            writeNodeType(nodeTypeDefinition, cndWriter, written, ntDefinitionProvider);
         }
         cndWriter.close();
     }
+
+    private void writeNodeType(Name nodeType, CompactNodeTypeDefWriter cndWriter, Set<Name> written, NodeTypeDefinitionProvider ntDefinitionProvider) throws IOException, RepositoryException {
+        if (nodeType == null || written.contains(nodeType)) {
+            return;
+        }
+        QNodeTypeDefinition ntDefinition = ntDefinitionProvider.getNodeTypeDefinition(nodeType);
+        writeNodeType(ntDefinition, cndWriter, written, ntDefinitionProvider);
+    }
+
+    private void writeNodeType(QNodeTypeDefinition ntDefinition, CompactNodeTypeDefWriter cndWriter, Set<Name> written, NodeTypeDefinitionProvider ntDefinitionProvider)
+            throws IOException, RepositoryException {
+        cndWriter.write(ntDefinition);
+        written.add(ntDefinition.getName());
+        // also write all referenced node types
+        for (Name superType: ntDefinition.getSupertypes()) {
+            writeNodeType(superType, cndWriter, written, ntDefinitionProvider);
+        }
+        for (QNodeDefinition cntDefinition: ntDefinition.getChildNodeDefs()) {
+            writeNodeType(cntDefinition.getDefaultPrimaryType(), cndWriter, written, ntDefinitionProvider);
+            if (cntDefinition.getRequiredPrimaryTypes() != null) {
+                for (Name name: cntDefinition.getRequiredPrimaryTypes()) {
+                    writeNodeType(name, cndWriter, written, ntDefinitionProvider);
+                }
+            }
+        }
+    }
 }