NIFI-10004: Allow loading .class files that are relative to the NAR directory, in addition to the .jar / .nar files

NIFI-10004: When determining classname from a file, consider File.separator instead of just /
Signed-off-by: Matthew Burgess <mattyb149@apache.org>

This closes #6026
This commit is contained in:
Mark Payne 2022-05-09 11:35:48 -04:00 committed by Matthew Burgess
parent c3829e2198
commit 9311188785
No known key found for this signature in database
GPG Key ID: 05D3DEB8126DAD24
4 changed files with 105 additions and 1 deletions

View File

@ -74,4 +74,18 @@
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<configuration>
<excludes combine.children="append">
<exclude>src/test/resources/FakeBootstrap.class</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -158,6 +158,8 @@ public class StatelessBootstrap {
filesAllowed.add(file.getName());
}
findClassNamesInDirectory(narDirectory, narDirectory, classesAllowed, filesAllowed);
final File java11Directory = new File(narDirectory, "java11");
final File[] java11DirectoryFiles = java11Directory.listFiles();
if (java11DirectoryFiles != null) {
@ -174,7 +176,7 @@ public class StatelessBootstrap {
javaHomeFilenames.add(file.getName());
}
logger.debug("The following JAR files will be explicitly allowed to be loaded by Stateless Extensions ClassLoaders from parent {}: {}", parent, filesAllowed);
logger.debug("The following class/JAR files will be explicitly allowed to be loaded by Stateless Extensions ClassLoaders from parent {}: {}", parent, filesAllowed);
logger.debug("The following JAR/JMOD files from ${JAVA_HOME} will be explicitly allowed to be loaded by Stateless Extensions ClassLoaders from parent {}: {}", parent, javaHomeFilenames);
logger.debug("The final list of classes allowed to be loaded by Stateless Extension ClassLoaders from parent {}: {}", parent, classesAllowed);
@ -258,6 +260,36 @@ public class StatelessBootstrap {
}
}
static void findClassNamesInDirectory(final File file, final File baseDirectory, final Set<String> classNames, final Set<String> fileNames) {
if (file.isDirectory()) {
final File[] children = file.listFiles();
if (children != null) {
for (final File child : children) {
findClassNamesInDirectory(child, baseDirectory, classNames, fileNames);
}
}
return;
}
final String filename = file.getName();
if (filename.endsWith(".class")) {
final String absolutePath = file.getAbsolutePath();
final String baseDirectoryPath = baseDirectory.getAbsolutePath();
if (!absolutePath.startsWith(baseDirectoryPath)) {
return;
}
final File relativeFile = baseDirectory.toPath().relativize(file.toPath()).toFile();
final String relativePath = relativeFile.getPath();
final int lastIndex = relativePath.lastIndexOf(".class");
final String className = relativePath.substring(0, lastIndex).replace(File.separator, ".");
classNames.add(className);
fileNames.add(filename);
}
}
private static void findClassesInJmod(final File file, final Set<String> classNames) throws IOException {
if (!file.getName().endsWith(".jmod") || !file.isFile() || !file.exists()) {
return;

View File

@ -0,0 +1,45 @@
/*
* 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.stateless.bootstrap;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TestStatelessBootstrap {
@Test
public void testAllowsClassFiles() {
final File libDir = new File("src/test/resources/test-lib");
final Set<String> classNames = new HashSet<>();
final Set<String> fileNames = new HashSet<>();
StatelessBootstrap.findClassNamesInDirectory(libDir, libDir, classNames, fileNames);
assertEquals(1, classNames.size());
assertEquals(1, fileNames.size());
assertTrue(classNames.contains("org.apache.nifi.stateless.FakeBootstrap"));
assertTrue(fileNames.contains("FakeBootstrap.class"));
}
}

View File

@ -0,0 +1,13 @@
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.