blob: 1f05cd3bb6a4b874152f45d0431dea676115b77c [file] [log] [blame]
/*
* 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.registry.security.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class ClassLoaderUtils {
static final Logger LOGGER = LoggerFactory.getLogger(ClassLoaderUtils.class);
public static ClassLoader getCustomClassLoader(String modulePath, ClassLoader parentClassLoader, FilenameFilter filenameFilter) throws MalformedURLException {
URL[] classpaths = getURLsForClasspath(modulePath, filenameFilter, false);
return createModuleClassLoader(classpaths, parentClassLoader);
}
/**
*
* @param modulePath a module path to get URLs from, the module path may be
* a comma-separated list of paths
* @param filenameFilter a filter to apply when a module path is a directory
* and performs a listing, a null filter will return all matches
* @param suppressExceptions indicates whether to suppress exceptions
* @return an array of URL instances representing all of the modules
* resolved from processing modulePath
* @throws MalformedURLException if a module path does not exist
*/
public static URL[] getURLsForClasspath(String modulePath, FilenameFilter filenameFilter, boolean suppressExceptions) throws MalformedURLException {
return getURLsForClasspath(modulePath == null ? Collections.emptySet() : Collections.singleton(modulePath), filenameFilter, suppressExceptions);
}
/**
*
* @param modulePaths one or modules paths to get URLs from, each module
* path may be a comma-separated list of paths
* @param filenameFilter a filter to apply when a module path is a directory
* and performs a listing, a null filter will return all matches
* @param suppressExceptions if true then all modules will attempt to be
* resolved even if some throw an exception, if false the first exception
* will be thrown
* @return an array of URL instances representing all of the modules
* resolved from processing modulePaths
* @throws MalformedURLException if a module path does not exist
*/
public static URL[] getURLsForClasspath(Set<String> modulePaths, FilenameFilter filenameFilter, boolean suppressExceptions) throws MalformedURLException {
// use LinkedHashSet to maintain the ordering that the incoming paths are processed
Set<String> modules = new LinkedHashSet<>();
if (modulePaths != null) {
modulePaths.stream()
.flatMap(path -> Arrays.stream(path.split(",")))
.filter(path -> isNotBlank(path))
.map(String::trim)
.forEach(m -> modules.add(m));
}
return toURLs(modules, filenameFilter, suppressExceptions);
}
private static boolean isNotBlank(final String value) {
return value != null && !value.trim().isEmpty();
}
protected static URL[] toURLs(Set<String> modulePaths, FilenameFilter filenameFilter, boolean suppressExceptions) throws MalformedURLException {
List<URL> additionalClasspath = new LinkedList<>();
if (modulePaths != null) {
for (String modulePathString : modulePaths) {
// If the path is already a URL, just add it (but don't check if it exists, too expensive and subject to network availability)
boolean isUrl = true;
try {
additionalClasspath.add(new URL(modulePathString));
} catch (MalformedURLException mue) {
isUrl = false;
}
if (!isUrl) {
try {
File modulePath = new File(modulePathString);
if (modulePath.exists()) {
additionalClasspath.add(modulePath.toURI().toURL());
if (modulePath.isDirectory()) {
File[] files = modulePath.listFiles(filenameFilter);
if (files != null) {
for (File classpathResource : files) {
if (classpathResource.isDirectory()) {
LOGGER.warn("Recursive directories are not supported, skipping " + classpathResource.getAbsolutePath());
} else {
additionalClasspath.add(classpathResource.toURI().toURL());
}
}
}
}
} else {
throw new MalformedURLException("Path specified does not exist");
}
} catch (MalformedURLException e) {
if (!suppressExceptions) {
throw e;
}
}
}
}
}
return additionalClasspath.toArray(new URL[additionalClasspath.size()]);
}
protected static ClassLoader createModuleClassLoader(URL[] modules, ClassLoader parentClassLoader) {
return new URLClassLoader(modules, parentClassLoader);
}
}