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

bbende pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-maven.git


The following commit(s) were added to refs/heads/main by this push:
     new b3dafe9  NIFI-11217 Fix building external NARs with transitive 
dependencies... (#29)
b3dafe9 is described below

commit b3dafe979030c1b797ea2535c8cbbc44c22e9dfc
Author: Kevin Doran <[email protected]>
AuthorDate: Wed Mar 8 12:56:34 2023 -0500

    NIFI-11217 Fix building external NARs with transitive dependencies... (#29)
    
    * NIFI-11217 Fix building external NARs with transitive dependencies marked 
as provided
    * Add unit test for ExtensionClassLoaderFactory
    * Bump maven-surefire-plugin version
    * Clean up
---
 pom.xml                                            |  21 ++-
 src/main/java/org/apache/nifi/NarMojo.java         |  19 +-
 .../extraction/ExtensionClassLoaderFactory.java    |  27 ++-
 .../ExtensionClassLoaderFactoryTest.java           | 204 +++++++++++++++++++++
 4 files changed, 255 insertions(+), 16 deletions(-)

diff --git a/pom.xml b/pom.xml
index a578b83..0654543 100644
--- a/pom.xml
+++ b/pom.xml
@@ -109,7 +109,7 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
-                    <version>2.18</version>
+                    <version>3.0.0-M8</version>
                     <configuration>
                         
<redirectTestOutputToFile>true</redirectTestOutputToFile>
                         <argLine>-Xmx1G</argLine>
@@ -340,6 +340,25 @@
             <scope>provided</scope>
             <version>3.3</version>
         </dependency>
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>5.9.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>3.12.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>3.12.4</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <profiles>
         <profile>
diff --git a/src/main/java/org/apache/nifi/NarMojo.java 
b/src/main/java/org/apache/nifi/NarMojo.java
index e1cb252..31a16dd 100644
--- a/src/main/java/org/apache/nifi/NarMojo.java
+++ b/src/main/java/org/apache/nifi/NarMojo.java
@@ -850,15 +850,16 @@ public class NarMojo extends AbstractMojo {
 
     private ExtensionClassLoaderFactory createClassLoaderFactory() {
         return new ExtensionClassLoaderFactory.Builder()
-            .artifactResolver(resolver)
-            .dependencyGraphBuilder(dependencyGraphBuilder)
-            .localRepository(local)
-            .log(getLog())
-            .project(project)
-            .projectBuilder(projectBuilder)
-            .repositorySession(repoSession)
-            .artifactHandlerManager(artifactHandlerManager)
-            .build();
+                .artifactResolver(resolver)
+                .dependencyGraphBuilder(dependencyGraphBuilder)
+                .localRepository(local)
+                .remoteRepositories(remoteRepos)
+                .log(getLog())
+                .project(project)
+                .projectBuilder(projectBuilder)
+                .repositorySession(repoSession)
+                .artifactHandlerManager(artifactHandlerManager)
+                .build();
     }
 
 
diff --git 
a/src/main/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactory.java
 
b/src/main/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactory.java
index 57bbc7d..c5e4888 100644
--- 
a/src/main/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactory.java
+++ 
b/src/main/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactory.java
@@ -51,6 +51,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.function.Supplier;
 
 public class ExtensionClassLoaderFactory {
 
@@ -67,6 +68,7 @@ public class ExtensionClassLoaderFactory {
     private final RepositorySystemSession repoSession;
     private final ProjectBuilder projectBuilder;
     private final ArtifactRepository localRepo;
+    private final List<ArtifactRepository> remoteRepos;
     private final DependencyGraphBuilder dependencyGraphBuilder;
     private final ArtifactResolver artifactResolver;
     private final ArtifactHandlerManager artifactHandlerManager;
@@ -77,6 +79,7 @@ public class ExtensionClassLoaderFactory {
         this.repoSession = builder.repositorySession;
         this.projectBuilder = builder.projectBuilder;
         this.localRepo = builder.localRepo;
+        this.remoteRepos = new ArrayList<>(builder.remoteRepos);
         this.dependencyGraphBuilder = builder.dependencyGraphBuilder;
         this.artifactResolver = builder.artifactResolver;
         this.artifactHandlerManager = builder.artifactHandlerManager;
@@ -149,8 +152,7 @@ public class ExtensionClassLoaderFactory {
 
         final ProjectBuildingResult narResult = 
projectBuilder.build(narArtifact, narRequest);
 
-        final Set<Artifact> narDependencies = new TreeSet<>();
-        gatherArtifacts(narResult.getProject(), narDependencies);
+        final Set<Artifact> narDependencies = 
gatherArtifacts(narResult.getProject(), TreeSet::new);
         narDependencies.remove(narArtifact);
         narDependencies.remove(project.getArtifact());
 
@@ -177,10 +179,9 @@ public class ExtensionClassLoaderFactory {
         projectRequest.setLocalRepository(localRepo);
 
         for (final Artifact artifact : artifacts) {
-            final Set<Artifact> artifactDependencies = new HashSet<>();
             try {
                 final ProjectBuildingResult projectResult = 
projectBuilder.build(artifact, projectRequest);
-                gatherArtifacts(projectResult.getProject(), 
artifactDependencies);
+                final Set<Artifact> artifactDependencies = 
gatherArtifacts(projectResult.getProject(), HashSet::new);
                 getLog().debug("For Artifact " + artifact + ", found the 
following dependencies:");
                 artifactDependencies.forEach(dep -> 
getLog().debug(dep.toString()));
 
@@ -213,6 +214,7 @@ public class ExtensionClassLoaderFactory {
 
         final ArtifactResolutionRequest request = new 
ArtifactResolutionRequest();
         request.setLocalRepository(localRepo);
+        request.setRemoteRepositories(remoteRepos);
         request.setArtifact(artifact);
 
         final ArtifactResolutionResult result = 
artifactResolver.resolve(request);
@@ -266,7 +268,8 @@ public class ExtensionClassLoaderFactory {
         return createClassLoader(providedArtifacts, null, null);
     }
 
-    private ExtensionClassLoader createClassLoader(final Set<Artifact> 
artifacts, final ExtensionClassLoader parent, final Artifact narArtifact) 
throws MojoExecutionException {
+    /* package visible for testing reasons */
+    ExtensionClassLoader createClassLoader(final Set<Artifact> artifacts, 
final ExtensionClassLoader parent, final Artifact narArtifact) throws 
MojoExecutionException {
         final Set<URL> urls = new HashSet<>();
         for (final Artifact artifact : artifacts) {
             final Set<URL> artifactUrls = toURLs(artifact);
@@ -284,7 +287,8 @@ public class ExtensionClassLoaderFactory {
     }
 
 
-    private void gatherArtifacts(final MavenProject mavenProject, final 
Set<Artifact> artifacts) throws MojoExecutionException {
+    private Set<Artifact> gatherArtifacts(final MavenProject mavenProject, 
final Supplier<Set<Artifact>> setSupplier) throws MojoExecutionException {
+        final Set<Artifact> artifacts = setSupplier.get();
         final DependencyNodeVisitor nodeVisitor = new DependencyNodeVisitor() {
             @Override
             public boolean visit(final DependencyNode dependencyNode) {
@@ -312,6 +316,7 @@ public class ExtensionClassLoaderFactory {
         } catch (DependencyGraphBuilderException e) {
             throw new MojoExecutionException("Failed to build dependency 
tree", e);
         }
+        return artifacts;
     }
 
     private Set<URL> toURLs(final Artifact artifact) throws 
MojoExecutionException {
@@ -323,6 +328,7 @@ public class ExtensionClassLoaderFactory {
 
             final ArtifactResolutionRequest request = new 
ArtifactResolutionRequest();
             request.setLocalRepository(localRepo);
+            request.setRemoteRepositories(remoteRepos);
             request.setArtifact(artifact);
 
             final ArtifactResolutionResult result = 
artifactResolver.resolve(request);
@@ -348,12 +354,16 @@ public class ExtensionClassLoaderFactory {
         return urls;
     }
 
+    public static Builder builder() {
+        return new Builder();
+    }
 
 
     public static class Builder {
         private Log log;
         private MavenProject project;
         private ArtifactRepository localRepo;
+        private List<ArtifactRepository> remoteRepos;
         private DependencyGraphBuilder dependencyGraphBuilder;
         private ArtifactResolver artifactResolver;
         private ProjectBuilder projectBuilder;
@@ -380,6 +390,11 @@ public class ExtensionClassLoaderFactory {
             return this;
         }
 
+        public Builder remoteRepositories(final List<ArtifactRepository> 
remoteRepos) {
+            this.remoteRepos = remoteRepos;
+            return this;
+        }
+
         public Builder dependencyGraphBuilder(final DependencyGraphBuilder 
dependencyGraphBuilder) {
             this.dependencyGraphBuilder = dependencyGraphBuilder;
             return this;
diff --git 
a/src/test/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactoryTest.java
 
b/src/test/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactoryTest.java
new file mode 100644
index 0000000..c6e6cf0
--- /dev/null
+++ 
b/src/test/java/org/apache/nifi/extension/definition/extraction/ExtensionClassLoaderFactoryTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.nifi.extension.definition.extraction;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
+import org.eclipse.aether.RepositorySystemSession;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class ExtensionClassLoaderFactoryTest {
+
+    @Mock private Log log;
+    @Mock private ArtifactResolver artifactResolver;
+    @Mock private ArtifactRepository localRepository;
+    @Mock private ArtifactRepository remoteRepository;
+    @Mock private ArtifactHandlerManager artifactHandlerManager;
+    @Mock private DependencyGraphBuilder dependencyGraphBuilder;
+    @Mock private MavenProject project;
+    @Mock private ProjectBuilder projectBuilder;
+    @Mock private RepositorySystemSession repositorySession;
+    private Artifact artifact1;
+    private Artifact artifact2;
+    private Artifact artifact3;
+
+    // Test Subject
+    private ExtensionClassLoaderFactory factory;
+
+    @BeforeEach
+    void setUp() {
+        artifact1 = projectArtifact();
+        artifact2 = localRepositoryDependencyArtifact();
+        artifact3 = remoteRepositoryDependencyArtifact();
+
+        when(artifactResolver.resolve(any(ArtifactResolutionRequest.class)))
+                .thenAnswer(args -> resolved(args.getArgument(0, 
ArtifactResolutionRequest.class).getArtifact()));
+
+        factory = ExtensionClassLoaderFactory
+                .builder()
+                .log(log)
+                .project(project)
+                .projectBuilder(projectBuilder)
+                .dependencyGraphBuilder(dependencyGraphBuilder)
+                .artifactHandlerManager(artifactHandlerManager)
+                .artifactResolver(artifactResolver)
+                .localRepository(localRepository)
+                
.remoteRepositories(Collections.singletonList(remoteRepository))
+                .repositorySession(repositorySession)
+                .build();
+    }
+
+    @Test
+    void createClassLoaderTest() throws Exception {
+        Set<Artifact> dependencyArtifacts = new TreeSet<>();
+        dependencyArtifacts.add(localRepositoryDependencyArtifact());
+        dependencyArtifacts.add(remoteRepositoryDependencyArtifact());
+
+        ExtensionClassLoader classLoader = 
factory.createClassLoader(dependencyArtifacts, null, artifact1);
+
+        String[] expectedURLs = new String[]{
+                "/path/to/service-api-nar",
+                "/path/to/service-nar"
+        };
+        assertEquals(expectedURLs.length, classLoader.getURLs().length);
+        List<String> expectedUrlsList = Arrays.asList(expectedURLs);
+        List<String> actualUrlsList = 
Arrays.stream(classLoader.getURLs()).map(URL::getFile).collect(Collectors.toList());
+        assertTrue(expectedUrlsList.containsAll(actualUrlsList));
+
+        InOrder inOrder = inOrder(artifactResolver);
+        for (ArtifactResolutionRequest req : 
getExpectedArtifactResolutionRequests()) {
+            inOrder.verify(artifactResolver).resolve(argThat(arg ->
+                
req.getArtifact().getArtifactId().equals(arg.getArtifact().getArtifactId())
+                        && req.getLocalRepository() == arg.getLocalRepository()
+                        && 
req.getRemoteRepositories().equals(arg.getRemoteRepositories())
+            ));
+        }
+        verifyNoMoreInteractions(artifactResolver);
+    }
+    
+    private List<ArtifactResolutionRequest> 
getExpectedArtifactResolutionRequests() {
+        ArtifactResolutionRequest request1 = new ArtifactResolutionRequest();
+        request1.setArtifact(artifact2);
+        request1.setLocalRepository(localRepository);
+        
request1.setRemoteRepositories(Collections.singletonList(remoteRepository));
+
+        ArtifactResolutionRequest request2 = new ArtifactResolutionRequest();
+        request2.setArtifact(artifact3);
+        request2.setLocalRepository(localRepository);
+        
request2.setRemoteRepositories(Collections.singletonList(remoteRepository));
+
+        List<ArtifactResolutionRequest> resolutionRequests = new ArrayList<>();
+        resolutionRequests.add(request1);
+        resolutionRequests.add(request2);
+        return resolutionRequests;
+    }
+
+    private Artifact projectArtifact() {
+        Artifact artifact = new DefaultArtifact(
+                "org.apache.nifi",
+                "processor-nar",
+                "1.0.0",
+                "compile",
+                "nar",
+                "arbitrary",
+                mock(ArtifactHandler.class)
+        );
+        artifact.setFile(new File("/path/to/" + artifact.getArtifactId()));
+        return artifact;
+    }
+
+    private Artifact localRepositoryDependencyArtifact() {
+        Artifact artifact = new DefaultArtifact(
+                "org.apache.nifi",
+                "service-api-nar",
+                "1.0.0",
+                "compile",
+                "nar",
+                "arbitrary",
+                mock(ArtifactHandler.class)
+        );
+        artifact.setFile(null);
+        artifact.setRepository(localRepository);
+        return artifact;
+    }
+
+    private Artifact remoteRepositoryDependencyArtifact() {
+        Artifact artifact = new DefaultArtifact(
+                "org.apache.nifi",
+                "service-nar",
+                "1.0.0",
+                "provided",
+                "nar",
+                "arbitrary",
+                mock(ArtifactHandler.class)
+        );
+        artifact.setFile(null);
+        artifact.setRepository(remoteRepository);
+        return artifact;
+    }
+
+    private ArtifactResolutionResult resolved(Artifact artifact) {
+        Artifact resolvedArtifact = new DefaultArtifact(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion(),
+                artifact.getScope(),
+                artifact.getType(),
+                artifact.getClassifier(),
+                artifact.getArtifactHandler()
+        );
+        resolvedArtifact.setFile(new File("/path/to/" + 
artifact.getArtifactId()));
+        ArtifactResolutionResult result = new ArtifactResolutionResult();
+        result.setArtifacts(Collections.singleton(resolvedArtifact));
+        return result;
+    }
+}
\ No newline at end of file

Reply via email to