Search in sources :

Example 26 with BundleCoordinate

use of org.apache.nifi.bundle.BundleCoordinate 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 27 with BundleCoordinate

use of org.apache.nifi.bundle.BundleCoordinate in project nifi-minifi by apache.

the class ExtensionManager method findReachableApiBundles.

/**
 * Find the bundle coordinates for any service APIs that are referenced by this component and not part of the same bundle.
 *
 * @param component the component being instantiated
 */
protected static Set<BundleCoordinate> findReachableApiBundles(final ConfigurableComponent component) {
    final Set<BundleCoordinate> reachableApiBundles = new HashSet<>();
    try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) {
        final List<PropertyDescriptor> descriptors = component.getPropertyDescriptors();
        if (descriptors != null && !descriptors.isEmpty()) {
            for (final PropertyDescriptor descriptor : descriptors) {
                final Class<? extends ControllerService> serviceApi = descriptor.getControllerServiceDefinition();
                if (serviceApi != null && !component.getClass().getClassLoader().equals(serviceApi.getClassLoader())) {
                    final Bundle apiBundle = classLoaderBundleLookup.get(serviceApi.getClassLoader());
                    reachableApiBundles.add(apiBundle.getBundleDetails().getCoordinate());
                }
            }
        }
    }
    return reachableApiBundles;
}
Also used : PropertyDescriptor(org.apache.nifi.components.PropertyDescriptor) Bundle(org.apache.nifi.bundle.Bundle) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Example 28 with BundleCoordinate

use of org.apache.nifi.bundle.BundleCoordinate in project nifi-minifi by apache.

the class NarBundleUtil method fromNarDirectory.

/**
 * Creates a BundleDetails from the given NAR working directory.
 *
 * @param narDirectory the directory of an exploded NAR which contains a META-INF/MANIFEST.MF
 *
 * @return the BundleDetails constructed from the information in META-INF/MANIFEST.MF
 */
public static BundleDetails fromNarDirectory(final File narDirectory) throws IOException, IllegalStateException {
    if (narDirectory == null) {
        throw new IllegalArgumentException("NAR Directory cannot be null");
    }
    final File manifestFile = new File(narDirectory, "META-INF/MANIFEST.MF");
    try (final FileInputStream fis = new FileInputStream(manifestFile)) {
        final Manifest manifest = new Manifest(fis);
        final Attributes attributes = manifest.getMainAttributes();
        final BundleDetails.Builder builder = new BundleDetails.Builder();
        builder.workingDir(narDirectory);
        final String group = attributes.getValue(NarManifestEntry.NAR_GROUP.getManifestName());
        final String id = attributes.getValue(NarManifestEntry.NAR_ID.getManifestName());
        final String version = attributes.getValue(NarManifestEntry.NAR_VERSION.getManifestName());
        builder.coordinate(new BundleCoordinate(group, id, version));
        final String dependencyGroup = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_GROUP.getManifestName());
        final String dependencyId = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_ID.getManifestName());
        final String dependencyVersion = attributes.getValue(NarManifestEntry.NAR_DEPENDENCY_VERSION.getManifestName());
        if (!StringUtils.isBlank(dependencyId)) {
            builder.dependencyCoordinate(new BundleCoordinate(dependencyGroup, dependencyId, dependencyVersion));
        }
        builder.buildBranch(attributes.getValue(NarManifestEntry.BUILD_BRANCH.getManifestName()));
        builder.buildTag(attributes.getValue(NarManifestEntry.BUILD_TAG.getManifestName()));
        builder.buildRevision(attributes.getValue(NarManifestEntry.BUILD_REVISION.getManifestName()));
        builder.buildTimestamp(attributes.getValue(NarManifestEntry.BUILD_TIMESTAMP.getManifestName()));
        builder.buildJdk(attributes.getValue(NarManifestEntry.BUILD_JDK.getManifestName()));
        builder.builtBy(attributes.getValue(NarManifestEntry.BUILT_BY.getManifestName()));
        return builder.build();
    }
}
Also used : BundleDetails(org.apache.nifi.bundle.BundleDetails) Attributes(java.util.jar.Attributes) Manifest(java.util.jar.Manifest) File(java.io.File) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) FileInputStream(java.io.FileInputStream)

Example 29 with BundleCoordinate

use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.

the class TestFlowController method testInstantiateSnippetWithProcessor.

@Test
public void testInstantiateSnippetWithProcessor() throws ProcessorInstantiationException {
    final String id = UUID.randomUUID().toString();
    final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
    final ProcessorNode processorNode = controller.createProcessor(DummyProcessor.class.getName(), id, coordinate);
    // create a processor dto
    final ProcessorDTO processorDTO = new ProcessorDTO();
    // use a different id here
    processorDTO.setId(UUID.randomUUID().toString());
    processorDTO.setPosition(new PositionDTO(new Double(0), new Double(0)));
    processorDTO.setStyle(processorNode.getStyle());
    processorDTO.setParentGroupId("1234");
    processorDTO.setInputRequirement(processorNode.getInputRequirement().name());
    processorDTO.setPersistsState(processorNode.getProcessor().getClass().isAnnotationPresent(Stateful.class));
    processorDTO.setRestricted(processorNode.isRestricted());
    processorDTO.setExtensionMissing(processorNode.isExtensionMissing());
    processorDTO.setType(processorNode.getCanonicalClassName());
    processorDTO.setBundle(new BundleDTO(coordinate.getGroup(), coordinate.getId(), coordinate.getVersion()));
    processorDTO.setName(processorNode.getName());
    processorDTO.setState(processorNode.getScheduledState().toString());
    processorDTO.setRelationships(new ArrayList<>());
    processorDTO.setDescription("description");
    processorDTO.setSupportsParallelProcessing(!processorNode.isTriggeredSerially());
    processorDTO.setSupportsEventDriven(processorNode.isEventDrivenSupported());
    processorDTO.setSupportsBatching(processorNode.isSessionBatchingSupported());
    ProcessorConfigDTO configDTO = new ProcessorConfigDTO();
    configDTO.setSchedulingPeriod(processorNode.getSchedulingPeriod());
    configDTO.setPenaltyDuration(processorNode.getPenalizationPeriod());
    configDTO.setYieldDuration(processorNode.getYieldPeriod());
    configDTO.setRunDurationMillis(processorNode.getRunDuration(TimeUnit.MILLISECONDS));
    configDTO.setConcurrentlySchedulableTaskCount(processorNode.getMaxConcurrentTasks());
    configDTO.setLossTolerant(processorNode.isLossTolerant());
    configDTO.setComments(processorNode.getComments());
    configDTO.setBulletinLevel(processorNode.getBulletinLevel().name());
    configDTO.setSchedulingStrategy(processorNode.getSchedulingStrategy().name());
    configDTO.setExecutionNode(processorNode.getExecutionNode().name());
    configDTO.setAnnotationData(processorNode.getAnnotationData());
    processorDTO.setConfig(configDTO);
    // create the snippet with the processor
    final FlowSnippetDTO flowSnippetDTO = new FlowSnippetDTO();
    flowSnippetDTO.setProcessors(Collections.singleton(processorDTO));
    // instantiate the snippet
    assertEquals(0, controller.getRootGroup().getProcessors().size());
    controller.instantiateSnippet(controller.getRootGroup(), flowSnippetDTO);
    assertEquals(1, controller.getRootGroup().getProcessors().size());
}
Also used : Stateful(org.apache.nifi.annotation.behavior.Stateful) ProcessorConfigDTO(org.apache.nifi.web.api.dto.ProcessorConfigDTO) FlowSnippetDTO(org.apache.nifi.web.api.dto.FlowSnippetDTO) ProcessorDTO(org.apache.nifi.web.api.dto.ProcessorDTO) DummyProcessor(org.apache.nifi.controller.service.mock.DummyProcessor) BundleDTO(org.apache.nifi.web.api.dto.BundleDTO) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) PositionDTO(org.apache.nifi.web.api.dto.PositionDTO) Test(org.junit.Test)

Example 30 with BundleCoordinate

use of org.apache.nifi.bundle.BundleCoordinate in project nifi by apache.

the class TestFlowController method testReloadReportingTask.

@Test
public void testReloadReportingTask() throws ReportingTaskInstantiationException {
    final String id = "ReportingTask" + System.currentTimeMillis();
    final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
    final ReportingTaskNode node = controller.createReportingTask(DummyReportingTask.class.getName(), id, coordinate, true);
    final String originalName = node.getName();
    assertEquals(id, node.getIdentifier());
    assertEquals(id, node.getComponent().getIdentifier());
    assertEquals(coordinate.getCoordinate(), node.getBundleCoordinate().getCoordinate());
    assertEquals(DummyReportingTask.class.getCanonicalName(), node.getCanonicalClassName());
    assertEquals(DummyReportingTask.class.getSimpleName(), node.getComponentType());
    assertEquals(DummyReportingTask.class.getCanonicalName(), node.getComponent().getClass().getCanonicalName());
    controller.reload(node, DummyScheduledReportingTask.class.getName(), coordinate, Collections.emptySet());
    // ids and coordinate should stay the same
    assertEquals(id, node.getIdentifier());
    assertEquals(id, node.getComponent().getIdentifier());
    assertEquals(coordinate.getCoordinate(), node.getBundleCoordinate().getCoordinate());
    // in this test we happened to change between two services that have different canonical class names
    // but in the running application the DAO layer would call verifyCanUpdateBundle and would prevent this so
    // for the sake of this test it is ok that the canonical class name hasn't changed
    assertEquals(originalName, node.getName());
    assertEquals(DummyReportingTask.class.getCanonicalName(), node.getCanonicalClassName());
    assertEquals(DummyReportingTask.class.getSimpleName(), node.getComponentType());
    assertEquals(DummyScheduledReportingTask.class.getCanonicalName(), node.getComponent().getClass().getCanonicalName());
}
Also used : DummyReportingTask(org.apache.nifi.controller.service.mock.DummyReportingTask) BundleCoordinate(org.apache.nifi.bundle.BundleCoordinate) Test(org.junit.Test)

Aggregations

BundleCoordinate (org.apache.nifi.bundle.BundleCoordinate)65 Bundle (org.apache.nifi.bundle.Bundle)23 LinkedHashSet (java.util.LinkedHashSet)18 ArrayList (java.util.ArrayList)16 BundleDTO (org.apache.nifi.web.api.dto.BundleDTO)16 HashMap (java.util.HashMap)14 Test (org.junit.Test)14 URL (java.net.URL)13 HashSet (java.util.HashSet)13 File (java.io.File)12 PropertyDescriptor (org.apache.nifi.components.PropertyDescriptor)12 ControllerServiceNode (org.apache.nifi.controller.service.ControllerServiceNode)12 ConfigurableComponent (org.apache.nifi.components.ConfigurableComponent)10 List (java.util.List)8 Map (java.util.Map)8 Set (java.util.Set)8 Position (org.apache.nifi.connectable.Position)7 IOException (java.io.IOException)6 Collectors (java.util.stream.Collectors)6 Collections (java.util.Collections)5