Search in sources :

Example 11 with ConfigurableComponent

use of org.apache.nifi.components.ConfigurableComponent 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 12 with ConfigurableComponent

use of org.apache.nifi.components.ConfigurableComponent in project nifi by apache.

the class StandardNiFiServiceFacade method ensureDefaultPropertyValuesArePopulated.

/**
 * Ensures default values are populated for all components in this snippet. This is necessary to handle old templates without default values
 * and when existing properties have default values introduced.
 *
 * @param snippet snippet
 */
private void ensureDefaultPropertyValuesArePopulated(final FlowSnippetDTO snippet) {
    if (snippet != null) {
        if (snippet.getControllerServices() != null) {
            snippet.getControllerServices().forEach(dto -> {
                if (dto.getProperties() == null) {
                    dto.setProperties(new LinkedHashMap<>());
                }
                try {
                    final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(dto.getType(), dto.getBundle());
                    configurableComponent.getPropertyDescriptors().forEach(descriptor -> {
                        if (dto.getProperties().get(descriptor.getName()) == null) {
                            dto.getProperties().put(descriptor.getName(), descriptor.getDefaultValue());
                        }
                    });
                } catch (final Exception e) {
                    logger.warn(String.format("Unable to create ControllerService of type %s to populate default values.", dto.getType()));
                }
            });
        }
        if (snippet.getProcessors() != null) {
            snippet.getProcessors().forEach(dto -> {
                if (dto.getConfig() == null) {
                    dto.setConfig(new ProcessorConfigDTO());
                }
                final ProcessorConfigDTO config = dto.getConfig();
                if (config.getProperties() == null) {
                    config.setProperties(new LinkedHashMap<>());
                }
                try {
                    final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(dto.getType(), dto.getBundle());
                    configurableComponent.getPropertyDescriptors().forEach(descriptor -> {
                        if (config.getProperties().get(descriptor.getName()) == null) {
                            config.getProperties().put(descriptor.getName(), descriptor.getDefaultValue());
                        }
                    });
                } catch (final Exception e) {
                    logger.warn(String.format("Unable to create Processor of type %s to populate default values.", dto.getType()));
                }
            });
        }
        if (snippet.getProcessGroups() != null) {
            snippet.getProcessGroups().forEach(processGroup -> {
                ensureDefaultPropertyValuesArePopulated(processGroup.getContents());
            });
        }
    }
}
Also used : ProcessorConfigDTO(org.apache.nifi.web.api.dto.ProcessorConfigDTO) ConfigurableComponent(org.apache.nifi.components.ConfigurableComponent) NiFiRegistryException(org.apache.nifi.registry.client.NiFiRegistryException) IOException(java.io.IOException) UnknownNodeException(org.apache.nifi.cluster.manager.exception.UnknownNodeException) IllegalNodeDeletionException(org.apache.nifi.cluster.manager.exception.IllegalNodeDeletionException) WebApplicationException(javax.ws.rs.WebApplicationException) AccessDeniedException(org.apache.nifi.authorization.AccessDeniedException) ExpiredRevisionClaimException(org.apache.nifi.web.revision.ExpiredRevisionClaimException)

Example 13 with ConfigurableComponent

use of org.apache.nifi.components.ConfigurableComponent in project nifi by apache.

the class ExtensionManager method loadExtensions.

/**
 * Loads extensions from the specified bundle.
 *
 * @param bundle from which to load extensions
 */
@SuppressWarnings("unchecked")
private static void loadExtensions(final Bundle bundle) {
    for (final Map.Entry<Class, Set<Class>> entry : definitionMap.entrySet()) {
        final boolean isControllerService = ControllerService.class.equals(entry.getKey());
        final boolean isProcessor = Processor.class.equals(entry.getKey());
        final boolean isReportingTask = ReportingTask.class.equals(entry.getKey());
        final ServiceLoader<?> serviceLoader = ServiceLoader.load(entry.getKey(), bundle.getClassLoader());
        for (final Object o : serviceLoader) {
            // create a cache of temp ConfigurableComponent instances, the initialize here has to happen before the checks below
            if ((isControllerService || isProcessor || isReportingTask) && o instanceof ConfigurableComponent) {
                final ConfigurableComponent configurableComponent = (ConfigurableComponent) o;
                initializeTempComponent(configurableComponent);
                final String cacheKey = getClassBundleKey(o.getClass().getCanonicalName(), bundle.getBundleDetails().getCoordinate());
                tempComponentLookup.put(cacheKey, (ConfigurableComponent) o);
            }
            // only consider extensions discovered directly in this bundle
            boolean registerExtension = bundle.getClassLoader().equals(o.getClass().getClassLoader());
            if (registerExtension) {
                final Class extensionType = o.getClass();
                if (isControllerService && !checkControllerServiceEligibility(extensionType)) {
                    registerExtension = false;
                    logger.error(String.format("Skipping Controller Service %s because it is bundled with its supporting APIs and requires instance class loading.", extensionType.getName()));
                }
                final boolean canReferenceControllerService = (isControllerService || isProcessor || isReportingTask) && o instanceof ConfigurableComponent;
                if (canReferenceControllerService && !checkControllerServiceReferenceEligibility((ConfigurableComponent) o, bundle.getClassLoader())) {
                    registerExtension = false;
                    logger.error(String.format("Skipping component %s because it is bundled with its referenced Controller Service APIs and requires instance class loading.", extensionType.getName()));
                }
                if (registerExtension) {
                    registerServiceClass(o.getClass(), classNameBundleLookup, bundle, entry.getValue());
                }
            }
        }
        classLoaderBundleLookup.put(bundle.getClassLoader(), bundle);
    }
}
Also used : HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) ConfigurableComponent(org.apache.nifi.components.ConfigurableComponent) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 14 with ConfigurableComponent

use of org.apache.nifi.components.ConfigurableComponent 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)

Example 15 with ConfigurableComponent

use of org.apache.nifi.components.ConfigurableComponent in project nifi by apache.

the class FingerprintFactory method addControllerServiceFingerprint.

private void addControllerServiceFingerprint(final StringBuilder builder, final ControllerServiceDTO dto) {
    builder.append(dto.getId());
    builder.append(dto.getVersionedComponentId());
    builder.append(dto.getType());
    builder.append(dto.getName());
    addBundleFingerprint(builder, dto.getBundle());
    builder.append(dto.getComments());
    builder.append(dto.getAnnotationData());
    builder.append(dto.getState());
    // get the temp instance of the ControllerService so that we know the default property values
    final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
    final ConfigurableComponent configurableComponent = ExtensionManager.getTempComponent(dto.getType(), coordinate);
    if (configurableComponent == null) {
        logger.warn("Unable to get ControllerService of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
    }
    addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
}
Also used : ConfigurableComponent(org.apache.nifi.components.ConfigurableComponent) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate)

Aggregations

ConfigurableComponent (org.apache.nifi.components.ConfigurableComponent)20 BundleCoordinate (org.apache.nifi.bundle.BundleCoordinate)9 LinkedHashSet (java.util.LinkedHashSet)6 URL (java.net.URL)5 HashSet (java.util.HashSet)5 HashMap (java.util.HashMap)4 Map (java.util.Map)4 Set (java.util.Set)4 ApiOperation (io.swagger.annotations.ApiOperation)3 ApiResponses (io.swagger.annotations.ApiResponses)3 IOException (java.io.IOException)3 Consumes (javax.ws.rs.Consumes)3 POST (javax.ws.rs.POST)3 Path (javax.ws.rs.Path)3 Produces (javax.ws.rs.Produces)3 AccessDeniedException (org.apache.nifi.authorization.AccessDeniedException)3 NiFiCoreException (org.apache.nifi.web.NiFiCoreException)3 BundleDTO (org.apache.nifi.web.api.dto.BundleDTO)3 Api (io.swagger.annotations.Api)2 ApiParam (io.swagger.annotations.ApiParam)2