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;
}
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;
}
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();
}
}
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());
}
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());
}
Aggregations