Search in sources :

Example 1 with RequiresInstanceClassLoading

use of org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading in project nifi-minifi by apache.

the class ExtensionManager method createInstanceClassLoader.

/**
 * Determines the effective ClassLoader for the instance of the given type.
 *
 * @param classType          the type of class to lookup the ClassLoader for
 * @param instanceIdentifier the identifier of the specific instance of the classType to look up the ClassLoader for
 * @param bundle             the bundle where the classType exists
 * @param additionalUrls     additional URLs to add to the instance class loader
 * @return the ClassLoader for the given instance of the given type, or null if the type is not a detected extension type
 */
public static InstanceClassLoader createInstanceClassLoader(final String classType, final String instanceIdentifier, final Bundle bundle, final Set<URL> additionalUrls) {
    if (StringUtils.isEmpty(classType)) {
        throw new IllegalArgumentException("Class-Type is required");
    }
    if (StringUtils.isEmpty(instanceIdentifier)) {
        throw new IllegalArgumentException("Instance Identifier is required");
    }
    if (bundle == null) {
        throw new IllegalArgumentException("Bundle is required");
    }
    // If the class is annotated with @RequiresInstanceClassLoading and the registered ClassLoader is a URLClassLoader
    // then make a new InstanceClassLoader that is a full copy of the NAR Class Loader, otherwise create an empty
    // InstanceClassLoader that has the NAR ClassLoader as a parent
    InstanceClassLoader instanceClassLoader;
    final ClassLoader bundleClassLoader = bundle.getClassLoader();
    final String key = getClassBundleKey(classType, bundle.getBundleDetails().getCoordinate());
    if (requiresInstanceClassLoading.containsKey(key) && bundleClassLoader instanceof NarClassLoader) {
        final Class<?> type = requiresInstanceClassLoading.get(key);
        final RequiresInstanceClassLoading requiresInstanceClassLoading = type.getAnnotation(RequiresInstanceClassLoading.class);
        final NarClassLoader narBundleClassLoader = (NarClassLoader) bundleClassLoader;
        logger.debug("Including ClassLoader resources from {} for component {}", new Object[] { bundle.getBundleDetails(), instanceIdentifier });
        final Set<URL> instanceUrls = new LinkedHashSet<>();
        for (final URL url : narBundleClassLoader.getURLs()) {
            instanceUrls.add(url);
        }
        ClassLoader ancestorClassLoader = narBundleClassLoader.getParent();
        if (requiresInstanceClassLoading.cloneAncestorResources()) {
            final ConfigurableComponent component = getTempComponent(classType, bundle.getBundleDetails().getCoordinate());
            final Set<BundleCoordinate> reachableApiBundles = findReachableApiBundles(component);
            while (ancestorClassLoader != null && ancestorClassLoader instanceof NarClassLoader) {
                final Bundle ancestorNarBundle = classLoaderBundleLookup.get(ancestorClassLoader);
                // stop including ancestor resources when we reach one of the APIs
                if (ancestorNarBundle == null || reachableApiBundles.contains(ancestorNarBundle.getBundleDetails().getCoordinate())) {
                    break;
                }
                final NarClassLoader ancestorNarClassLoader = (NarClassLoader) ancestorClassLoader;
                for (final URL url : ancestorNarClassLoader.getURLs()) {
                    instanceUrls.add(url);
                }
                ancestorClassLoader = ancestorNarClassLoader.getParent();
            }
        }
        instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, instanceUrls, additionalUrls, ancestorClassLoader);
    } else {
        instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, Collections.emptySet(), additionalUrls, bundleClassLoader);
    }
    if (logger.isTraceEnabled()) {
        for (URL url : instanceClassLoader.getURLs()) {
            logger.trace("URL resource {} for {}...", new Object[] { url.toExternalForm(), instanceIdentifier });
        }
    }
    instanceClassloaderLookup.put(instanceIdentifier, instanceClassLoader);
    return instanceClassLoader;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Bundle(org.apache.nifi.bundle.Bundle) RequiresInstanceClassLoading(org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading) ConfigurableComponent(org.apache.nifi.components.ConfigurableComponent) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) URL(java.net.URL) URLClassLoader(java.net.URLClassLoader)

Example 2 with RequiresInstanceClassLoading

use of org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading in project nifi by apache.

the class ExtensionManager method createInstanceClassLoader.

/**
 * Determines the effective ClassLoader for the instance of the given type.
 *
 * @param classType the type of class to lookup the ClassLoader for
 * @param instanceIdentifier the identifier of the specific instance of the classType to look up the ClassLoader for
 * @param bundle the bundle where the classType exists
 * @param additionalUrls additional URLs to add to the instance class loader
 * @return the ClassLoader for the given instance of the given type, or null if the type is not a detected extension type
 */
public static InstanceClassLoader createInstanceClassLoader(final String classType, final String instanceIdentifier, final Bundle bundle, final Set<URL> additionalUrls) {
    if (StringUtils.isEmpty(classType)) {
        throw new IllegalArgumentException("Class-Type is required");
    }
    if (StringUtils.isEmpty(instanceIdentifier)) {
        throw new IllegalArgumentException("Instance Identifier is required");
    }
    if (bundle == null) {
        throw new IllegalArgumentException("Bundle is required");
    }
    // If the class is annotated with @RequiresInstanceClassLoading and the registered ClassLoader is a URLClassLoader
    // then make a new InstanceClassLoader that is a full copy of the NAR Class Loader, otherwise create an empty
    // InstanceClassLoader that has the NAR ClassLoader as a parent
    InstanceClassLoader instanceClassLoader;
    final ClassLoader bundleClassLoader = bundle.getClassLoader();
    final String key = getClassBundleKey(classType, bundle.getBundleDetails().getCoordinate());
    if (requiresInstanceClassLoading.containsKey(key) && bundleClassLoader instanceof NarClassLoader) {
        final Class<?> type = requiresInstanceClassLoading.get(key);
        final RequiresInstanceClassLoading requiresInstanceClassLoading = type.getAnnotation(RequiresInstanceClassLoading.class);
        final NarClassLoader narBundleClassLoader = (NarClassLoader) bundleClassLoader;
        logger.debug("Including ClassLoader resources from {} for component {}", new Object[] { bundle.getBundleDetails(), instanceIdentifier });
        final Set<URL> instanceUrls = new LinkedHashSet<>();
        for (final URL url : narBundleClassLoader.getURLs()) {
            instanceUrls.add(url);
        }
        ClassLoader ancestorClassLoader = narBundleClassLoader.getParent();
        if (requiresInstanceClassLoading.cloneAncestorResources()) {
            final ConfigurableComponent component = getTempComponent(classType, bundle.getBundleDetails().getCoordinate());
            final Set<BundleCoordinate> reachableApiBundles = findReachableApiBundles(component);
            while (ancestorClassLoader != null && ancestorClassLoader instanceof NarClassLoader) {
                final Bundle ancestorNarBundle = classLoaderBundleLookup.get(ancestorClassLoader);
                // stop including ancestor resources when we reach one of the APIs, or when we hit the Jetty NAR
                if (ancestorNarBundle == null || reachableApiBundles.contains(ancestorNarBundle.getBundleDetails().getCoordinate()) || ancestorNarBundle.getBundleDetails().getCoordinate().getId().equals(NarClassLoaders.JETTY_NAR_ID)) {
                    break;
                }
                final NarClassLoader ancestorNarClassLoader = (NarClassLoader) ancestorClassLoader;
                for (final URL url : ancestorNarClassLoader.getURLs()) {
                    instanceUrls.add(url);
                }
                ancestorClassLoader = ancestorNarClassLoader.getParent();
            }
        }
        instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, instanceUrls, additionalUrls, ancestorClassLoader);
    } else {
        instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, Collections.emptySet(), additionalUrls, bundleClassLoader);
    }
    if (logger.isTraceEnabled()) {
        for (URL url : instanceClassLoader.getURLs()) {
            logger.trace("URL resource {} for {}...", new Object[] { url.toExternalForm(), instanceIdentifier });
        }
    }
    instanceClassloaderLookup.put(instanceIdentifier, instanceClassLoader);
    return instanceClassLoader;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Bundle(org.apache.nifi.bundle.Bundle) RequiresInstanceClassLoading(org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading) ConfigurableComponent(org.apache.nifi.components.ConfigurableComponent) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) URL(java.net.URL) URLClassLoader(java.net.URLClassLoader)

Aggregations

URL (java.net.URL)2 URLClassLoader (java.net.URLClassLoader)2 LinkedHashSet (java.util.LinkedHashSet)2 RequiresInstanceClassLoading (org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading)2 Bundle (org.apache.nifi.bundle.Bundle)2 BundleCoordinate (org.apache.nifi.bundle.BundleCoordinate)2 ConfigurableComponent (org.apache.nifi.components.ConfigurableComponent)2