proxiedLoggableComponent = new LoggableComponent<>(proxiedService, bundleCoordinate, null);
final ControllerServiceNode serviceNode = new StandardControllerServiceNode(proxiedLoggableComponent, proxiedLoggableComponent, invocationHandler, id,
- new StandardValidationContextFactory(this, variableRegistry), this, componentType, type, variableRegistry, true);
+ new StandardValidationContextFactory(this, variableRegistry), this, componentType, type, variableRegistry, flowController, true);
return serviceNode;
}
@@ -537,7 +538,7 @@ public class StandardControllerServiceProvider implements ControllerServiceProvi
}
group.removeControllerService(serviceNode);
- ExtensionManager.removeInstanceClassLoaderIfExists(serviceNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(serviceNode.getIdentifier());
}
@Override
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
index 3bbe9e3462..1db80fc82f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
@@ -20,17 +20,13 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.exception.ProcessorInstantiationException;
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
-import org.apache.nifi.util.LoggingXmlParserErrorHandler;
import org.apache.nifi.encrypt.StringEncryptor;
import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.processor.Processor;
-import org.apache.nifi.reporting.ReportingTask;
import org.apache.nifi.util.BundleUtils;
import org.apache.nifi.util.DomUtils;
+import org.apache.nifi.util.LoggingXmlParserErrorHandler;
import org.apache.nifi.web.api.dto.BundleDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
@@ -58,7 +54,6 @@ import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.UUID;
/**
* Creates a fingerprint of a flow.xml. The order of elements or attributes in the flow.xml does not influence the fingerprint generation.
@@ -232,7 +227,7 @@ public class FingerprintFactory {
});
for (final ControllerServiceDTO dto : serviceDtos) {
- addControllerServiceFingerprint(builder, dto, controller);
+ addControllerServiceFingerprint(builder, dto);
}
}
@@ -262,7 +257,7 @@ public class FingerprintFactory {
});
for (final ReportingTaskDTO dto : reportingTaskDtos) {
- addReportingTaskFingerprint(builder, dto, controller);
+ addReportingTaskFingerprint(builder, dto);
}
}
@@ -277,7 +272,7 @@ public class FingerprintFactory {
final List processorElems = DomUtils.getChildElementsByTagName(processGroupElem, "processor");
Collections.sort(processorElems, getIdsComparator());
for (final Element processorElem : processorElems) {
- addFlowFileProcessorFingerprint(builder, processorElem, controller);
+ addFlowFileProcessorFingerprint(builder, processorElem);
}
// input ports
@@ -332,7 +327,7 @@ public class FingerprintFactory {
return builder;
}
- private StringBuilder addFlowFileProcessorFingerprint(final StringBuilder builder, final Element processorElem, final FlowController controller) throws FingerprintException {
+ private StringBuilder addFlowFileProcessorFingerprint(final StringBuilder builder, final Element processorElem) throws FingerprintException {
// id
appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "id"));
// class
@@ -346,24 +341,11 @@ public class FingerprintFactory {
final BundleDTO bundle = FlowFromDOMFactory.getBundle(DomUtils.getChild(processorElem, "bundle"));
addBundleFingerprint(builder, bundle);
- // create an instance of the Processor so that we know the default property values
- Processor processor = null;
- try {
- if (controller != null) {
- final BundleCoordinate coordinate = getCoordinate(className, bundle);
- processor = controller.createProcessor(className, UUID.randomUUID().toString(), coordinate, false).getProcessor();
- }
- } catch (ProcessorInstantiationException | IllegalStateException e) {
- logger.warn("Unable to create Processor of type {} due to {}; its default properties will be fingerprinted instead of being ignored.", className, e.toString());
- if (logger.isDebugEnabled()) {
- logger.warn("", e);
- }
- } finally {
- // The processor instance is only for fingerprinting so we can remove the InstanceClassLoader here
- // since otherwise it will stick around in the map forever
- if (processor != null) {
- ExtensionManager.removeInstanceClassLoaderIfExists(processor.getIdentifier());
- }
+ // get the temp instance of the Processor so that we know the default property values
+ final BundleCoordinate coordinate = getCoordinate(className, bundle);
+ final ConfigurableComponent configurableComponent = ExtensionManager.getTempComponent(className, coordinate);
+ if (configurableComponent == null) {
+ logger.warn("Unable to get Processor of type {}; its default properties will be fingerprinted instead of being ignored.", className);
}
// properties
@@ -372,7 +354,7 @@ public class FingerprintFactory {
for (final Element propertyElem : sortedPropertyElems) {
final String propName = DomUtils.getChildElementsByTagName(propertyElem, "name").get(0).getTextContent();
String propValue = getFirstValue(DomUtils.getChildNodesByTagName(propertyElem, "value"), null);
- addPropertyFingerprint(builder, processor, propName, propValue);
+ addPropertyFingerprint(builder, configurableComponent, propName, propValue);
}
final NodeList autoTerminateElems = DomUtils.getChildNodesByTagName(processorElem, "autoTerminatedRelationship");
@@ -571,7 +553,7 @@ public class FingerprintFactory {
return builder;
}
- private void addControllerServiceFingerprint(final StringBuilder builder, final ControllerServiceDTO dto, final FlowController controller) {
+ private void addControllerServiceFingerprint(final StringBuilder builder, final ControllerServiceDTO dto) {
builder.append(dto.getId());
builder.append(dto.getType());
builder.append(dto.getName());
@@ -582,21 +564,14 @@ public class FingerprintFactory {
builder.append(dto.getAnnotationData());
builder.append(dto.getState());
- // create an instance of the ControllerService so that we know the default property values
- ControllerService controllerService = null;
- try {
- if (controller != null) {
- final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
- controllerService = controller.createControllerService(dto.getType(), UUID.randomUUID().toString(), coordinate, false).getControllerServiceImplementation();
- }
- } catch (Exception e) {
- logger.warn("Unable to create ControllerService of type {} due to {}; its default properties will be fingerprinted instead of being ignored.", dto.getType(), e.toString());
- if (logger.isDebugEnabled()) {
- logger.warn("", e);
- }
+ // 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, controllerService, dto.getProperties());
+ addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
}
private void addPropertiesFingerprint(final StringBuilder builder, final ConfigurableComponent component, final Map properties) {
@@ -634,7 +609,7 @@ public class FingerprintFactory {
return coordinate;
}
- private void addReportingTaskFingerprint(final StringBuilder builder, final ReportingTaskDTO dto, final FlowController controller) {
+ private void addReportingTaskFingerprint(final StringBuilder builder, final ReportingTaskDTO dto) {
builder.append(dto.getId());
builder.append(dto.getType());
builder.append(dto.getName());
@@ -646,21 +621,14 @@ public class FingerprintFactory {
builder.append(dto.getSchedulingStrategy());
builder.append(dto.getAnnotationData());
- // create an instance of the ReportingTask so that we know the default property values
- ReportingTask reportingTask = null;
- try {
- if (controller != null) {
- final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
- reportingTask = controller.createReportingTask(dto.getType(), UUID.randomUUID().toString(), coordinate, false, false).getReportingTask();
- }
- } catch (Exception e) {
- logger.warn("Unable to create ReportingTask of type {} due to {}; its default properties will be fingerprinted instead of being ignored.", dto.getType(), e.toString());
- if (logger.isDebugEnabled()) {
- logger.warn("", e);
- }
+ // get the temp instance of the ReportingTask 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 ReportingTask of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
}
- addPropertiesFingerprint(builder, reportingTask, dto.getProperties());
+ addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
}
private Comparator getIdsComparator() {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
index 8d8fd19138..452f3cc491 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
@@ -767,7 +767,7 @@ public final class StandardProcessGroup implements ProcessGroup {
} finally {
if (removed) {
try {
- ExtensionManager.removeInstanceClassLoaderIfExists(id);
+ ExtensionManager.removeInstanceClassLoader(id);
} catch (Throwable t) {
}
}
@@ -1914,7 +1914,7 @@ public final class StandardProcessGroup implements ProcessGroup {
} finally {
if (removed) {
try {
- ExtensionManager.removeInstanceClassLoaderIfExists(service.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(service.getIdentifier());
} catch (Throwable t) {
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/groovy/org/apache/nifi/controller/StandardFlowSynchronizerSpec.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/groovy/org/apache/nifi/controller/StandardFlowSynchronizerSpec.groovy
index 738b25d148..098814a9f7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/groovy/org/apache/nifi/controller/StandardFlowSynchronizerSpec.groovy
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/groovy/org/apache/nifi/controller/StandardFlowSynchronizerSpec.groovy
@@ -26,6 +26,7 @@ import org.apache.nifi.controller.queue.FlowFileQueue
import org.apache.nifi.groups.ProcessGroup
import org.apache.nifi.groups.RemoteProcessGroup
import org.apache.nifi.nar.ExtensionManager
+import org.apache.nifi.nar.SystemBundle
import org.apache.nifi.processor.Relationship
import org.apache.nifi.reporting.BulletinRepository
import org.apache.nifi.util.NiFiProperties
@@ -43,7 +44,7 @@ class StandardFlowSynchronizerSpec extends Specification {
System.setProperty NiFiProperties.PROPERTIES_FILE_PATH, propFile
def niFiProperties = NiFiProperties.createBasicNiFiProperties(null, null);
- systemBundle = ExtensionManager.createSystemBundle(niFiProperties);
+ systemBundle = SystemBundle.create(niFiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
index 557bd62492..1b51be61b0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestFlowController.java
@@ -44,6 +44,8 @@ import org.apache.nifi.logging.LogLevel;
import org.apache.nifi.logging.LogRepository;
import org.apache.nifi.logging.LogRepositoryFactory;
import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.InstanceClassLoader;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.provenance.MockProvenanceRepository;
import org.apache.nifi.registry.VariableRegistry;
@@ -67,6 +69,8 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -115,7 +119,7 @@ public class TestFlowController {
encryptor = StringEncryptor.createEncryptor(nifiProperties);
// use the system bundle
- systemBundle = ExtensionManager.createSystemBundle(nifiProperties);
+ systemBundle = SystemBundle.create(nifiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build();
@@ -465,7 +469,7 @@ public class TestFlowController {
@Test
public void testCreateMissingControllerService() throws ProcessorInstantiationException {
final ControllerServiceNode serviceNode = controller.createControllerService("org.apache.nifi.NonExistingControllerService", "1234-Controller-Service",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
assertNotNull(serviceNode);
assertEquals("org.apache.nifi.NonExistingControllerService", serviceNode.getCanonicalClassName());
assertEquals("(Missing) NonExistingControllerService", serviceNode.getComponentType());
@@ -518,7 +522,7 @@ public class TestFlowController {
ProcessGroup pg = controller.createProcessGroup("my-process-group");
pg.setName("my-process-group");
ControllerServiceNode cs = controller.createControllerService("org.apache.nifi.NonExistingControllerService", "my-controller-service",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
pg.addControllerService(cs);
controller.getRootGroup().addProcessGroup(pg);
controller.getRootGroup().removeProcessGroup(pg);
@@ -527,7 +531,7 @@ public class TestFlowController {
}
@Test
- public void testChangeProcessorType() throws ProcessorInstantiationException {
+ public void testReloadProcessor() throws ProcessorInstantiationException {
final String id = "1234-ScheduledProcessor" + System.currentTimeMillis();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
final ProcessorNode processorNode = controller.createProcessor(DummyScheduledProcessor.class.getName(), id, coordinate);
@@ -548,7 +552,7 @@ public class TestFlowController {
assertEquals(LogLevel.WARN, processorNode.getBulletinLevel());
// now change the type of the processor from DummyScheduledProcessor to DummySettingsProcessor
- controller.changeProcessorType(processorNode, DummySettingsProcessor.class.getName(), coordinate);
+ controller.reload(processorNode, DummySettingsProcessor.class.getName(), coordinate, Collections.emptySet());
// ids and coordinate should stay the same
assertEquals(id, processorNode.getIdentifier());
@@ -573,10 +577,42 @@ public class TestFlowController {
}
@Test
- public void testChangeControllerServiceType() {
+ public void testReloadProcessorWithAdditionalResources() throws ProcessorInstantiationException, MalformedURLException {
+ final URL resource1 = new File("src/test/resources/TestClasspathResources/resource1.txt").toURI().toURL();
+ final URL resource2 = new File("src/test/resources/TestClasspathResources/resource2.txt").toURI().toURL();
+ final URL resource3 = new File("src/test/resources/TestClasspathResources/resource3.txt").toURI().toURL();
+ final Set additionalUrls = new LinkedHashSet<>(Arrays.asList(resource1, resource2, resource3));
+
+ final String id = "1234-ScheduledProcessor" + System.currentTimeMillis();
+ final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
+ final ProcessorNode processorNode = controller.createProcessor(DummyScheduledProcessor.class.getName(), id, coordinate);
+ final String originalName = processorNode.getName();
+
+ // the instance class loader shouldn't have any of the resources yet
+ InstanceClassLoader instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertTrue(instanceClassLoader.getAdditionalResourceUrls().isEmpty());
+
+ // now change the type of the processor from DummyScheduledProcessor to DummySettingsProcessor
+ controller.reload(processorNode, DummySettingsProcessor.class.getName(), coordinate, additionalUrls);
+
+ // the instance class loader shouldn't have any of the resources yet
+ instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertEquals(3, instanceClassLoader.getAdditionalResourceUrls().size());
+ }
+
+ @Test
+ public void testReloadControllerService() {
final String id = "ServiceA" + System.currentTimeMillis();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
- final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, true);
+ final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, null, true);
final String originalName = controllerServiceNode.getName();
assertEquals(id, controllerServiceNode.getIdentifier());
@@ -586,7 +622,7 @@ public class TestFlowController {
assertEquals(ServiceA.class.getSimpleName(), controllerServiceNode.getComponentType());
assertEquals(ServiceA.class.getCanonicalName(), controllerServiceNode.getComponent().getClass().getCanonicalName());
- controller.changeControllerServiceType(controllerServiceNode, ServiceB.class.getName(), coordinate);
+ controller.reload(controllerServiceNode, ServiceB.class.getName(), coordinate, Collections.emptySet());
// ids and coordinate should stay the same
assertEquals(id, controllerServiceNode.getIdentifier());
@@ -603,7 +639,38 @@ public class TestFlowController {
}
@Test
- public void testChangeReportingTaskType() throws ReportingTaskInstantiationException {
+ public void testReloadControllerServiceWithAdditionalResources() throws MalformedURLException {
+ final URL resource1 = new File("src/test/resources/TestClasspathResources/resource1.txt").toURI().toURL();
+ final URL resource2 = new File("src/test/resources/TestClasspathResources/resource2.txt").toURI().toURL();
+ final URL resource3 = new File("src/test/resources/TestClasspathResources/resource3.txt").toURI().toURL();
+ final Set additionalUrls = new LinkedHashSet<>(Arrays.asList(resource1, resource2, resource3));
+
+ final String id = "ServiceA" + System.currentTimeMillis();
+ final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
+ final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, null, true);
+ final String originalName = controllerServiceNode.getName();
+
+ // the instance class loader shouldn't have any of the resources yet
+ InstanceClassLoader instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertTrue(instanceClassLoader.getAdditionalResourceUrls().isEmpty());
+
+ controller.reload(controllerServiceNode, ServiceB.class.getName(), coordinate, additionalUrls);
+
+ // the instance class loader shouldn't have any of the resources yet
+ instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertEquals(3, instanceClassLoader.getAdditionalResourceUrls().size());
+ }
+
+ @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);
@@ -616,7 +683,7 @@ public class TestFlowController {
assertEquals(DummyReportingTask.class.getSimpleName(), node.getComponentType());
assertEquals(DummyReportingTask.class.getCanonicalName(), node.getComponent().getClass().getCanonicalName());
- controller.changeReportingTaskType(node, DummyScheduledReportingTask.class.getName(), coordinate);
+ controller.reload(node, DummyScheduledReportingTask.class.getName(), coordinate, Collections.emptySet());
// ids and coordinate should stay the same
assertEquals(id, node.getIdentifier());
@@ -630,7 +697,45 @@ public class TestFlowController {
assertEquals(DummyReportingTask.class.getCanonicalName(), node.getCanonicalClassName());
assertEquals(DummyReportingTask.class.getSimpleName(), node.getComponentType());
assertEquals(DummyScheduledReportingTask.class.getCanonicalName(), node.getComponent().getClass().getCanonicalName());
+ }
+ @Test
+ public void testReloadReportingTaskWithAdditionalResources() throws ReportingTaskInstantiationException, MalformedURLException {
+ final URL resource1 = new File("src/test/resources/TestClasspathResources/resource1.txt").toURI().toURL();
+ final URL resource2 = new File("src/test/resources/TestClasspathResources/resource2.txt").toURI().toURL();
+ final URL resource3 = new File("src/test/resources/TestClasspathResources/resource3.txt").toURI().toURL();
+ final Set additionalUrls = new LinkedHashSet<>(Arrays.asList(resource1, resource2, resource3));
+
+ final String id = "ReportingTask" + System.currentTimeMillis();
+ final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
+ final ReportingTaskNode node = controller.createReportingTask(DummyReportingTask.class.getName(), id, coordinate, true);
+
+ // the instance class loader shouldn't have any of the resources yet
+ InstanceClassLoader instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertFalse(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertTrue(instanceClassLoader.getAdditionalResourceUrls().isEmpty());
+
+ controller.reload(node, DummyScheduledReportingTask.class.getName(), coordinate, additionalUrls);
+
+ // the instance class loader shouldn't have any of the resources yet
+ instanceClassLoader = ExtensionManager.getInstanceClassLoader(id);
+ assertNotNull(instanceClassLoader);
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource1));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource2));
+ assertTrue(containsResource(instanceClassLoader.getURLs(), resource3));
+ assertEquals(3, instanceClassLoader.getAdditionalResourceUrls().size());
+ }
+
+ private boolean containsResource(URL[] resources, URL resourceToFind) {
+ for (URL resource : resources) {
+ if (resourceToFind.getPath().equals(resource.getPath())) {
+ return true;
+ }
+ }
+ return false;
}
@Test(expected = IllegalArgumentException.class)
@@ -744,7 +849,7 @@ public class TestFlowController {
public void testInstantiateSnippetWhenControllerServiceMissingBundle() throws ProcessorInstantiationException {
final String id = UUID.randomUUID().toString();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
- final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, true);
+ final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, null, true);
// create the controller service dto
final ControllerServiceDTO csDto = new ControllerServiceDTO();
@@ -775,7 +880,7 @@ public class TestFlowController {
public void testInstantiateSnippetWithControllerService() throws ProcessorInstantiationException {
final String id = UUID.randomUUID().toString();
final BundleCoordinate coordinate = systemBundle.getBundleDetails().getCoordinate();
- final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, true);
+ final ControllerServiceNode controllerServiceNode = controller.createControllerService(ServiceA.class.getName(), id, coordinate, null, true);
// create the controller service dto
final ControllerServiceDTO csDto = new ControllerServiceDTO();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
index a86b7b395a..c248d25788 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
@@ -25,12 +25,16 @@ import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.controller.exception.ControllerServiceInstantiationException;
+import org.apache.nifi.controller.exception.ProcessorInstantiationException;
+import org.apache.nifi.controller.reporting.ReportingTaskInstantiationException;
+import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.engine.FlowEngine;
import org.apache.nifi.expression.ExpressionLanguageCompiler;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.nar.InstanceClassLoader;
import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
@@ -55,10 +59,10 @@ import org.mockito.Mockito;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -88,11 +92,12 @@ public class TestStandardProcessorNode {
ProcessorInitializationContext initContext = new StandardProcessorInitializationContext(uuid, null, null, null, null);
processor.initialize(initContext);
+ final ReloadComponent reloadComponent = Mockito.mock(ReloadComponent.class);
final BundleCoordinate coordinate = Mockito.mock(BundleCoordinate.class);
final LoggableComponent loggableComponent = new LoggableComponent<>(processor, coordinate, null);
final StandardProcessorNode procNode = new StandardProcessorNode(loggableComponent, uuid, createValidationContextFactory(), null, null,
- NiFiProperties.createBasicNiFiProperties(null, null), VariableRegistry.EMPTY_REGISTRY);
+ NiFiProperties.createBasicNiFiProperties(null, null), VariableRegistry.EMPTY_REGISTRY, reloadComponent);
final ScheduledExecutorService taskScheduler = new FlowEngine(2, "TestClasspathResources", true);
final StandardProcessContext processContext = new StandardProcessContext(procNode, null, null, null, null);
@@ -122,8 +127,9 @@ public class TestStandardProcessorNode {
@Test
public void testDisabledValidationErrors() {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
final ModifiesClasspathNoAnnotationProcessor processor = new ModifiesClasspathNoAnnotationProcessor();
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
// Set a property to an invalid value
final Map properties = new HashMap<>();
@@ -138,22 +144,19 @@ public class TestStandardProcessorNode {
@Test
public void testSinglePropertyDynamicallyModifiesClasspath() throws MalformedURLException {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
+
final PropertyDescriptor classpathProp = new PropertyDescriptor.Builder().name("Classpath Resources")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final ModifiesClasspathProcessor processor = new ModifiesClasspathProcessor(Arrays.asList(classpathProp));
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(procNode.getProcessor().getClass(), procNode.getIdentifier())){
- // Should have an InstanceClassLoader here
- final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
- assertTrue(contextClassLoader instanceof InstanceClassLoader);
-
- final InstanceClassLoader instanceClassLoader = (InstanceClassLoader) contextClassLoader;
// Should not have any of the test resources loaded at this point
final URL[] testResources = getTestResources();
for (URL testResource : testResources) {
- if (containsResource(instanceClassLoader.getInstanceResources(), testResource)) {
+ if (containsResource(reloadComponent.getAdditionalUrls(), testResource)) {
fail("found resource that should not have been loaded");
}
}
@@ -165,18 +168,22 @@ public class TestStandardProcessorNode {
// Should have all of the resources loaded into the InstanceClassLoader now
for (URL testResource : testResources) {
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResource));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResource));
}
+ assertEquals(ModifiesClasspathProcessor.class.getCanonicalName(), reloadComponent.getNewType());
+
// Should pass validation
assertTrue(procNode.isValid());
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(procNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(procNode.getIdentifier());
}
}
@Test
public void testUpdateOtherPropertyDoesNotImpactClasspath() throws MalformedURLException {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
+
final PropertyDescriptor classpathProp = new PropertyDescriptor.Builder().name("Classpath Resources")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
@@ -184,19 +191,13 @@ public class TestStandardProcessorNode {
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final ModifiesClasspathProcessor processor = new ModifiesClasspathProcessor(Arrays.asList(classpathProp, otherProp));
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(procNode.getProcessor().getClass(), procNode.getIdentifier())){
- // Should have an InstanceClassLoader here
- final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
- assertTrue(contextClassLoader instanceof InstanceClassLoader);
-
- final InstanceClassLoader instanceClassLoader = (InstanceClassLoader) contextClassLoader;
-
// Should not have any of the test resources loaded at this point
final URL[] testResources = getTestResources();
for (URL testResource : testResources) {
- if (containsResource(instanceClassLoader.getInstanceResources(), testResource)) {
+ if (containsResource(reloadComponent.getAdditionalUrls(), testResource)) {
fail("found resource that should not have been loaded");
}
}
@@ -208,7 +209,7 @@ public class TestStandardProcessorNode {
// Should have all of the resources loaded into the InstanceClassLoader now
for (URL testResource : testResources) {
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResource));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResource));
}
// Should pass validation
@@ -221,7 +222,7 @@ public class TestStandardProcessorNode {
// Should STILL have all of the resources loaded into the InstanceClassLoader now
for (URL testResource : testResources) {
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResource));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResource));
}
// Should STILL pass validation
@@ -233,38 +234,37 @@ public class TestStandardProcessorNode {
procNode.setProperties(newClasspathProperties);
// Should only have resource1 loaded now
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResources[0]));
- assertFalse(containsResource(instanceClassLoader.getInstanceResources(), testResources[1]));
- assertFalse(containsResource(instanceClassLoader.getInstanceResources(), testResources[2]));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResources[0]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[1]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[2]));
+
+ assertEquals(ModifiesClasspathProcessor.class.getCanonicalName(), reloadComponent.getNewType());
// Should STILL pass validation
assertTrue(procNode.isValid());
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(procNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(procNode.getIdentifier());
}
}
@Test
public void testMultiplePropertiesDynamicallyModifyClasspathWithExpressionLanguage() throws MalformedURLException {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
+
final PropertyDescriptor classpathProp1 = new PropertyDescriptor.Builder().name("Classpath Resource 1")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final PropertyDescriptor classpathProp2 = new PropertyDescriptor.Builder().name("Classpath Resource 2")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final ModifiesClasspathProcessor processor = new ModifiesClasspathProcessor(Arrays.asList(classpathProp1, classpathProp2));
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(procNode.getProcessor().getClass(), procNode.getIdentifier())){
- // Should have an InstanceClassLoader here
- final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
- assertTrue(contextClassLoader instanceof InstanceClassLoader);
-
- final InstanceClassLoader instanceClassLoader = (InstanceClassLoader) contextClassLoader;
// Should not have any of the test resources loaded at this point
final URL[] testResources = getTestResources();
for (URL testResource : testResources) {
- if (containsResource(instanceClassLoader.getInstanceResources(), testResource)) {
+ if (containsResource(reloadComponent.getAdditionalUrls(), testResource)) {
fail("found resource that should not have been loaded");
}
}
@@ -279,38 +279,37 @@ public class TestStandardProcessorNode {
procNode.setProperties(properties);
// Should have resources 1 and 3 loaded into the InstanceClassLoader now
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResources[0]));
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResources[2]));
- assertFalse(containsResource(instanceClassLoader.getInstanceResources(), testResources[1]));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResources[0]));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResources[2]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[1]));
+
+ assertEquals(ModifiesClasspathProcessor.class.getCanonicalName(), reloadComponent.getNewType());
// Should pass validation
assertTrue(procNode.isValid());
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(procNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(procNode.getIdentifier());
}
}
@Test
public void testSomeNonExistentPropertiesDynamicallyModifyClasspath() throws MalformedURLException {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
+
final PropertyDescriptor classpathProp1 = new PropertyDescriptor.Builder().name("Classpath Resource 1")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final PropertyDescriptor classpathProp2 = new PropertyDescriptor.Builder().name("Classpath Resource 2")
.dynamicallyModifiesClasspath(true).addValidator(StandardValidators.NON_EMPTY_VALIDATOR).build();
final ModifiesClasspathProcessor processor = new ModifiesClasspathProcessor(Arrays.asList(classpathProp1, classpathProp2));
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(procNode.getProcessor().getClass(), procNode.getIdentifier())){
- // Should have an InstanceClassLoader here
- final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
- assertTrue(contextClassLoader instanceof InstanceClassLoader);
-
- final InstanceClassLoader instanceClassLoader = (InstanceClassLoader) contextClassLoader;
// Should not have any of the test resources loaded at this point
final URL[] testResources = getTestResources();
for (URL testResource : testResources) {
- if (containsResource(instanceClassLoader.getInstanceResources(), testResource)) {
+ if (containsResource(reloadComponent.getAdditionalUrls(), testResource)) {
fail("found resource that should not have been loaded");
}
}
@@ -322,53 +321,52 @@ public class TestStandardProcessorNode {
procNode.setProperties(properties);
// Should have resources 1 and 3 loaded into the InstanceClassLoader now
- assertTrue(containsResource(instanceClassLoader.getInstanceResources(), testResources[0]));
- assertFalse(containsResource(instanceClassLoader.getInstanceResources(), testResources[1]));
- assertFalse(containsResource(instanceClassLoader.getInstanceResources(), testResources[2]));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResources[0]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[1]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[2]));
+
+ assertEquals(ModifiesClasspathProcessor.class.getCanonicalName(), reloadComponent.getNewType());
// Should pass validation
assertTrue(procNode.isValid());
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(procNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(procNode.getIdentifier());
}
}
@Test
public void testPropertyModifiesClasspathWhenProcessorMissingAnnotation() throws MalformedURLException {
+ final MockReloadComponent reloadComponent = new MockReloadComponent();
final ModifiesClasspathNoAnnotationProcessor processor = new ModifiesClasspathNoAnnotationProcessor();
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(procNode.getProcessor().getClass(), procNode.getIdentifier())){
- // Can't validate the ClassLoader here b/c the class is missing the annotation
- // Simulate setting the properties pointing to two of the resources
final Map properties = new HashMap<>();
properties.put(ModifiesClasspathNoAnnotationProcessor.CLASSPATH_RESOURCE.getName(),
"src/test/resources/TestClasspathResources/resource1.txt");
procNode.setProperties(properties);
- // Should not have loaded any of the resources
- final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- assertTrue(classLoader instanceof URLClassLoader);
-
final URL[] testResources = getTestResources();
- final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
- assertFalse(containsResource(urlClassLoader.getURLs(), testResources[0]));
- assertFalse(containsResource(urlClassLoader.getURLs(), testResources[1]));
- assertFalse(containsResource(urlClassLoader.getURLs(), testResources[2]));
+ assertTrue(containsResource(reloadComponent.getAdditionalUrls(), testResources[0]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[1]));
+ assertFalse(containsResource(reloadComponent.getAdditionalUrls(), testResources[2]));
+
+ assertEquals(ModifiesClasspathNoAnnotationProcessor.class.getCanonicalName(), reloadComponent.getNewType());
// Should pass validation
assertTrue(procNode.isValid());
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(procNode.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(procNode.getIdentifier());
}
}
@Test
public void testVerifyCanUpdateBundle() {
+ final ReloadComponent reloadComponent = new MockReloadComponent();
final ModifiesClasspathNoAnnotationProcessor processor = new ModifiesClasspathNoAnnotationProcessor();
- final StandardProcessorNode procNode = createProcessorNode(processor);
+ final StandardProcessorNode procNode = createProcessorNode(processor, reloadComponent);
final BundleCoordinate existingCoordinate = procNode.getBundleCoordinate();
// should be allowed to update when the bundle is the same
@@ -400,30 +398,68 @@ public class TestStandardProcessorNode {
}
}
- @Test
- public void testValidateControllerServiceApiRequired() {
-
- }
-
- private StandardProcessorNode createProcessorNode(Processor processor) {
+ private StandardProcessorNode createProcessorNode(final Processor processor, final ReloadComponent reloadComponent) {
final String uuid = UUID.randomUUID().toString();
final ValidationContextFactory validationContextFactory = createValidationContextFactory();
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties("src/test/resources/conf/nifi.properties", null);
final ProcessScheduler processScheduler = Mockito.mock(ProcessScheduler.class);
final ComponentLog componentLog = Mockito.mock(ComponentLog.class);
- final Bundle systemBundle = ExtensionManager.createSystemBundle(niFiProperties);
+ final Bundle systemBundle = SystemBundle.create(niFiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
- ExtensionManager.createInstanceClassLoader(processor.getClass().getName(), uuid, systemBundle);
+ ExtensionManager.createInstanceClassLoader(processor.getClass().getName(), uuid, systemBundle, null);
ProcessorInitializationContext initContext = new StandardProcessorInitializationContext(uuid, componentLog, null, null, null);
processor.initialize(initContext);
final LoggableComponent loggableComponent = new LoggableComponent<>(processor, systemBundle.getBundleDetails().getCoordinate(), componentLog);
- return new StandardProcessorNode(loggableComponent, uuid, validationContextFactory, processScheduler, null, niFiProperties, variableRegistry);
+ return new StandardProcessorNode(loggableComponent, uuid, validationContextFactory, processScheduler, null, niFiProperties, variableRegistry, reloadComponent);
}
- private boolean containsResource(URL[] resources, URL resourceToFind) {
+ private static class MockReloadComponent implements ReloadComponent {
+
+ private String newType;
+ private BundleCoordinate bundleCoordinate;
+ private final Set additionalUrls = new LinkedHashSet<>();
+
+ public Set getAdditionalUrls() {
+ return this.additionalUrls;
+ }
+
+ public String getNewType() {
+ return newType;
+ }
+
+ public BundleCoordinate getBundleCoordinate() {
+ return bundleCoordinate;
+ }
+
+ @Override
+ public void reload(ProcessorNode existingNode, String newType, BundleCoordinate bundleCoordinate, Set additionalUrls) throws ProcessorInstantiationException {
+ reload(newType, bundleCoordinate, additionalUrls);
+ }
+
+ @Override
+ public void reload(ControllerServiceNode existingNode, String newType, BundleCoordinate bundleCoordinate, Set additionalUrls) throws ControllerServiceInstantiationException {
+ reload(newType, bundleCoordinate, additionalUrls);
+ }
+
+ @Override
+ public void reload(ReportingTaskNode existingNode, String newType, BundleCoordinate bundleCoordinate, Set additionalUrls) throws ReportingTaskInstantiationException {
+ reload(newType, bundleCoordinate, additionalUrls);
+ }
+
+ private void reload(String newType, BundleCoordinate bundleCoordinate, Set additionalUrls) {
+ this.newType = newType;
+ this.bundleCoordinate = bundleCoordinate;
+ this.additionalUrls.clear();
+ if (additionalUrls != null) {
+ this.additionalUrls.addAll(additionalUrls);
+ }
+ }
+ }
+
+ private boolean containsResource(Set resources, URL resourceToFind) {
for (URL resource : resources) {
if (resourceToFind.getPath().equals(resource.getPath())) {
return true;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java
index 5c8d447125..9533751906 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestProcessorLifecycle.java
@@ -39,6 +39,7 @@ import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.events.VolatileBulletinRepository;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
@@ -542,7 +543,7 @@ public class TestProcessorLifecycle {
this.setControllerRootGroup(fc, testGroup);
ControllerServiceNode testServiceNode = fc.createControllerService(TestService.class.getName(), "serv",
- fcsb.getSystemBundle().getBundleDetails().getCoordinate(), true);
+ fcsb.getSystemBundle().getBundleDetails().getCoordinate(), null, true);
ProcessorNode testProcNode = fc.createProcessor(TestProcessor.class.getName(), UUID.randomUUID().toString(),
fcsb.getSystemBundle().getBundleDetails().getCoordinate());
@@ -569,7 +570,7 @@ public class TestProcessorLifecycle {
this.setControllerRootGroup(fc, testGroup);
ControllerServiceNode testServiceNode = fc.createControllerService(TestService.class.getName(), "foo",
- fcsb.getSystemBundle().getBundleDetails().getCoordinate(), true);
+ fcsb.getSystemBundle().getBundleDetails().getCoordinate(), null, true);
testGroup.addControllerService(testServiceNode);
ProcessorNode testProcNode = fc.createProcessor(TestProcessor.class.getName(), UUID.randomUUID().toString(),
@@ -731,7 +732,7 @@ public class TestProcessorLifecycle {
}
final NiFiProperties nifiProperties = NiFiProperties.createBasicNiFiProperties(null, addProps);
- final Bundle systemBundle = ExtensionManager.createSystemBundle(nifiProperties);
+ final Bundle systemBundle = SystemBundle.create(nifiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
final FlowController flowController = FlowController.createStandaloneInstance(mock(FlowFileEventRepository.class), nifiProperties,
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
index b69701eb10..dbbd614820 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/scheduling/TestStandardProcessScheduler.java
@@ -28,6 +28,7 @@ import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.LoggableComponent;
import org.apache.nifi.controller.ProcessScheduler;
import org.apache.nifi.controller.ProcessorNode;
+import org.apache.nifi.controller.ReloadComponent;
import org.apache.nifi.controller.ReportingTaskNode;
import org.apache.nifi.controller.StandardProcessorNode;
import org.apache.nifi.controller.ValidationContextFactory;
@@ -43,6 +44,7 @@ import org.apache.nifi.controller.service.mock.MockProcessGroup;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
@@ -98,7 +100,7 @@ public class TestStandardProcessScheduler {
this.nifiProperties = NiFiProperties.createBasicNiFiProperties(null, null);
// load the system bundle
- systemBundle = ExtensionManager.createSystemBundle(nifiProperties);
+ systemBundle = SystemBundle.create(nifiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
scheduler = new StandardProcessScheduler(Mockito.mock(ControllerServiceProvider.class), null, stateMgrProvider, variableRegistry, nifiProperties);
@@ -111,8 +113,9 @@ public class TestStandardProcessScheduler {
final ValidationContextFactory validationContextFactory = new StandardValidationContextFactory(null, variableRegistry);
final ComponentLog logger = Mockito.mock(ComponentLog.class);
+ final ReloadComponent reloadComponent = Mockito.mock(ReloadComponent.class);
final LoggableComponent loggableComponent = new LoggableComponent<>(reportingTask, systemBundle.getBundleDetails().getCoordinate(), logger);
- taskNode = new StandardReportingTaskNode(loggableComponent, UUID.randomUUID().toString(), null, scheduler, validationContextFactory, variableRegistry);
+ taskNode = new StandardReportingTaskNode(loggableComponent, UUID.randomUUID().toString(), null, scheduler, validationContextFactory, variableRegistry, reloadComponent);
controller = Mockito.mock(FlowController.class);
rootGroup = new MockProcessGroup();
@@ -150,16 +153,18 @@ public class TestStandardProcessScheduler {
final Processor proc = new ServiceReferencingProcessor();
proc.initialize(new StandardProcessorInitializationContext(uuid, null, null, null, null));
+ final ReloadComponent reloadComponent = Mockito.mock(ReloadComponent.class);
+
final StandardControllerServiceProvider serviceProvider =
new StandardControllerServiceProvider(controller, scheduler, null, Mockito.mock(StateManagerProvider.class), variableRegistry, nifiProperties);
final ControllerServiceNode service = serviceProvider.createControllerService(NoStartServiceImpl.class.getName(), "service",
- systemBundle.getBundleDetails().getCoordinate(), true);
+ systemBundle.getBundleDetails().getCoordinate(), null, true);
rootGroup.addControllerService(service);
final LoggableComponent loggableComponent = new LoggableComponent<>(proc, systemBundle.getBundleDetails().getCoordinate(), null);
final ProcessorNode procNode = new StandardProcessorNode(loggableComponent, uuid,
new StandardValidationContextFactory(serviceProvider, variableRegistry),
- scheduler, serviceProvider, nifiProperties, VariableRegistry.EMPTY_REGISTRY);
+ scheduler, serviceProvider, nifiProperties, VariableRegistry.EMPTY_REGISTRY, reloadComponent);
rootGroup.addProcessor(procNode);
Map procProps = new HashMap<>();
@@ -233,7 +238,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(SimpleTestService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
assertFalse(serviceNode.isActive());
final SimpleTestService ts = (SimpleTestService) serviceNode.getControllerServiceImplementation();
final ExecutorService executor = Executors.newCachedThreadPool();
@@ -272,7 +277,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(SimpleTestService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
final SimpleTestService ts = (SimpleTestService) serviceNode.getControllerServiceImplementation();
final ExecutorService executor = Executors.newCachedThreadPool();
@@ -310,7 +315,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(SimpleTestService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
final SimpleTestService ts = (SimpleTestService) serviceNode.getControllerServiceImplementation();
scheduler.enableControllerService(serviceNode);
assertTrue(serviceNode.isActive());
@@ -344,7 +349,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(FailingService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
scheduler.enableControllerService(serviceNode);
Thread.sleep(1000);
scheduler.shutdown();
@@ -378,7 +383,7 @@ public class TestStandardProcessScheduler {
final ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 200; i++) {
final ControllerServiceNode serviceNode = provider.createControllerService(RandomShortDelayEnablingService.class.getName(), "1",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
executor.execute(new Runnable() {
@Override
@@ -419,7 +424,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(LongEnablingService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
final LongEnablingService ts = (LongEnablingService) serviceNode.getControllerServiceImplementation();
ts.setLimit(Long.MAX_VALUE);
scheduler.enableControllerService(serviceNode);
@@ -445,7 +450,7 @@ public class TestStandardProcessScheduler {
final ProcessScheduler scheduler = createScheduler();
final StandardControllerServiceProvider provider = new StandardControllerServiceProvider(controller, scheduler, null, stateMgrProvider, variableRegistry, nifiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(LongEnablingService.class.getName(),
- "1", systemBundle.getBundleDetails().getCoordinate(), false);
+ "1", systemBundle.getBundleDetails().getCoordinate(), null, false);
final LongEnablingService ts = (LongEnablingService) serviceNode.getControllerServiceImplementation();
ts.setLimit(3000);
scheduler.enableControllerService(serviceNode);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/StandardControllerServiceProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/StandardControllerServiceProviderTest.java
index 15c35d92c2..4a97b8a29d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/StandardControllerServiceProviderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/StandardControllerServiceProviderTest.java
@@ -22,6 +22,7 @@ import org.apache.nifi.components.state.StateManagerProvider;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.nar.NarClassLoaders;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.registry.VariableRegistry;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.util.FileBasedVariableRegistry;
@@ -48,7 +49,7 @@ public class StandardControllerServiceProviderTest {
NarClassLoaders.getInstance().init(nifiProperties.getFrameworkWorkingDirectory(), nifiProperties.getExtensionsWorkingDirectory());
// load the system bundle
- systemBundle = ExtensionManager.createSystemBundle(nifiProperties);
+ systemBundle = SystemBundle.create(nifiProperties);
ExtensionManager.discoverExtensions(systemBundle, NarClassLoaders.getInstance().getBundles());
variableRegistry = new FileBasedVariableRegistry(nifiProperties.getVariableRegistryPropertiesPaths());
@@ -80,7 +81,7 @@ public class StandardControllerServiceProviderTest {
public void onComponentRemoved(String componentId) {
}
}, variableRegistry, nifiProperties);
- ControllerServiceNode node = provider.createControllerService(clazz, id, systemBundle.getBundleDetails().getCoordinate(), true);
+ ControllerServiceNode node = provider.createControllerService(clazz, id, systemBundle.getBundleDetails().getCoordinate(), null, true);
proxied = node.getProxiedControllerService();
implementation = node.getControllerServiceImplementation();
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/TestStandardControllerServiceProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/TestStandardControllerServiceProvider.java
index 40d9357dfb..3a28cb004a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/TestStandardControllerServiceProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/TestStandardControllerServiceProvider.java
@@ -24,6 +24,7 @@ import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.LoggableComponent;
import org.apache.nifi.controller.ProcessScheduler;
import org.apache.nifi.controller.ProcessorNode;
+import org.apache.nifi.controller.ReloadComponent;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.StandardProcessorNode;
import org.apache.nifi.controller.scheduling.StandardProcessScheduler;
@@ -35,6 +36,7 @@ import org.apache.nifi.controller.service.mock.ServiceC;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.StandardProcessGroup;
import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.SystemBundle;
import org.apache.nifi.processor.Processor;
import org.apache.nifi.processor.StandardValidationContextFactory;
import org.apache.nifi.registry.VariableRegistry;
@@ -93,7 +95,7 @@ public class TestStandardControllerServiceProvider {
niFiProperties = NiFiProperties.createBasicNiFiProperties(null, null);
// load the system bundle
- systemBundle = ExtensionManager.createSystemBundle(niFiProperties);
+ systemBundle = SystemBundle.create(niFiProperties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
}
@@ -118,7 +120,7 @@ public class TestStandardControllerServiceProvider {
new StandardControllerServiceProvider(controller, scheduler, null, stateManagerProvider, variableRegistry, niFiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(ServiceB.class.getName(), "B",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null,false);
provider.enableControllerService(serviceNode);
provider.disableControllerService(serviceNode);
}
@@ -134,9 +136,9 @@ public class TestStandardControllerServiceProvider {
new StandardControllerServiceProvider(controller, scheduler, null, stateManagerProvider, variableRegistry, niFiProperties);
final ControllerServiceNode serviceNodeB = provider.createControllerService(ServiceB.class.getName(), "B",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNodeA = provider.createControllerService(ServiceA.class.getName(), "A",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
group.addControllerService(serviceNodeA);
group.addControllerService(serviceNodeB);
@@ -208,13 +210,13 @@ public class TestStandardControllerServiceProvider {
// we enable C and B, even if we attempt to enable C before B... i.e., if we try to enable C, we cannot do so
// until B is first enabled so ensure that we enable B first.
final ControllerServiceNode serviceNode1 = provider.createControllerService(ServiceA.class.getName(), "1",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNode2 = provider.createControllerService(ServiceA.class.getName(), "2",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNode3 = provider.createControllerService(ServiceA.class.getName(), "3",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNode4 = provider.createControllerService(ServiceB.class.getName(), "4",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
procGroup.addControllerService(serviceNode1);
procGroup.addControllerService(serviceNode2);
@@ -251,9 +253,9 @@ public class TestStandardControllerServiceProvider {
final StandardControllerServiceProvider provider =
new StandardControllerServiceProvider(controller, null, null, stateManagerProvider, variableRegistry, niFiProperties);
final ControllerServiceNode serviceNode1 = provider.createControllerService(ServiceA.class.getName(), "1",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNode2 = provider.createControllerService(ServiceB.class.getName(), "2",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
setProperty(serviceNode1, ServiceA.OTHER_SERVICE.getName(), "2");
@@ -312,7 +314,7 @@ public class TestStandardControllerServiceProvider {
// like that.
nodeMap.clear();
final ControllerServiceNode serviceNode3 = provider.createControllerService(ServiceA.class.getName(), "3",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
setProperty(serviceNode1, ServiceA.OTHER_SERVICE.getName(), "3");
setProperty(serviceNode3, ServiceA.OTHER_SERVICE.getName(), "1");
nodeMap.put("1", serviceNode1);
@@ -338,9 +340,9 @@ public class TestStandardControllerServiceProvider {
nodeMap.clear();
setProperty(serviceNode1, ServiceA.OTHER_SERVICE.getName(), "2");
final ControllerServiceNode serviceNode4 = provider.createControllerService(ServiceB.class.getName(), "4",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ControllerServiceNode serviceNode5 = provider.createControllerService(ServiceB.class.getName(), "5",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
setProperty(serviceNode3, ServiceA.OTHER_SERVICE.getName(), "4");
nodeMap.put("1", serviceNode1);
nodeMap.put("2", serviceNode2);
@@ -397,10 +399,11 @@ public class TestStandardControllerServiceProvider {
}
private ProcessorNode createProcessor(final StandardProcessScheduler scheduler, final ControllerServiceProvider serviceProvider) {
+ final ReloadComponent reloadComponent = Mockito.mock(ReloadComponent.class);
final LoggableComponent dummyProcessor = new LoggableComponent<>(new DummyProcessor(), systemBundle.getBundleDetails().getCoordinate(), null);
final ProcessorNode procNode = new StandardProcessorNode(dummyProcessor, UUID.randomUUID().toString(),
new StandardValidationContextFactory(serviceProvider, null), scheduler, serviceProvider, niFiProperties,
- VariableRegistry.EMPTY_REGISTRY);
+ VariableRegistry.EMPTY_REGISTRY, reloadComponent);
final ProcessGroup group = new StandardProcessGroup(UUID.randomUUID().toString(), serviceProvider, scheduler, null, null, null, variableRegistry);
group.addProcessor(procNode);
@@ -419,7 +422,7 @@ public class TestStandardControllerServiceProvider {
final StandardControllerServiceProvider provider =
new StandardControllerServiceProvider(controller, null, null, stateManagerProvider, variableRegistry, niFiProperties);
final ControllerServiceNode serviceNode = provider.createControllerService(ServiceA.class.getName(), "1",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
final ProcessorNode procNode = createProcessor(scheduler, provider);
serviceNode.addReference(procNode);
@@ -443,17 +446,17 @@ public class TestStandardControllerServiceProvider {
Mockito.when(controller.getGroup(Mockito.anyString())).thenReturn(procGroup);
ControllerServiceNode A = provider.createControllerService(ServiceA.class.getName(), "A",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode B = provider.createControllerService(ServiceA.class.getName(), "B",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode C = provider.createControllerService(ServiceA.class.getName(), "C",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode D = provider.createControllerService(ServiceB.class.getName(), "D",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode E = provider.createControllerService(ServiceA.class.getName(), "E",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode F = provider.createControllerService(ServiceB.class.getName(), "F",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
procGroup.addControllerService(A);
procGroup.addControllerService(B);
@@ -494,15 +497,15 @@ public class TestStandardControllerServiceProvider {
Mockito.when(controller.getGroup(Mockito.anyString())).thenReturn(procGroup);
ControllerServiceNode A = provider.createControllerService(ServiceC.class.getName(), "A",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode B = provider.createControllerService(ServiceA.class.getName(), "B",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode C = provider.createControllerService(ServiceB.class.getName(), "C",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode D = provider.createControllerService(ServiceA.class.getName(), "D",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode F = provider.createControllerService(ServiceA.class.getName(), "F",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
procGroup.addControllerService(A);
procGroup.addControllerService(B);
@@ -536,19 +539,19 @@ public class TestStandardControllerServiceProvider {
Mockito.when(controller.getGroup(Mockito.anyString())).thenReturn(procGroup);
ControllerServiceNode serviceNode1 = provider.createControllerService(ServiceA.class.getName(), "1",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode2 = provider.createControllerService(ServiceA.class.getName(), "2",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode3 = provider.createControllerService(ServiceA.class.getName(), "3",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode4 = provider.createControllerService(ServiceB.class.getName(), "4",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode5 = provider.createControllerService(ServiceA.class.getName(), "5",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode6 = provider.createControllerService(ServiceB.class.getName(), "6",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
ControllerServiceNode serviceNode7 = provider.createControllerService(ServiceC.class.getName(), "7",
- systemBundle.getBundleDetails().getCoordinate(), false);
+ systemBundle.getBundleDetails().getCoordinate(), null, false);
procGroup.addControllerService(serviceNode1);
procGroup.addControllerService(serviceNode2);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/pom.xml
new file mode 100644
index 0000000000..ba20a37e16
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ org.apache.nifi
+ nifi-framework
+ 1.2.0-SNAPSHOT
+
+ nifi-framework-nar-utils
+ jar
+
+
+ org.apache.nifi
+ nifi-nar-utils
+
+
+ org.apache.nifi
+ nifi-properties
+
+
+ org.apache.nifi
+ nifi-api
+
+
+ org.apache.nifi
+ nifi-framework-api
+
+
+
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializer.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializer.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializer.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializerFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializerFactory.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializerFactory.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ConfigurableComponentInitializerFactory.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java
similarity index 96%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java
index 5939b96d42..21b107fa86 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ControllerServiceInitializer.java
@@ -53,7 +53,7 @@ public class ControllerServiceInitializer implements ConfigurableComponentInitia
final MockConfigurationContext context = new MockConfigurationContext();
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnShutdown.class, controllerService, logger, context);
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(component.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(component.getIdentifier());
}
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java
similarity index 96%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java
index 3274f6e1af..06fdead6cf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ProcessorInitializer.java
@@ -52,7 +52,7 @@ public class ProcessorInitializer implements ConfigurableComponentInitializer {
final MockProcessContext context = new MockProcessContext();
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnShutdown.class, processor, logger, context);
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(component.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(component.getIdentifier());
}
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReflectionUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ReflectionUtils.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReflectionUtils.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ReflectionUtils.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
similarity index 96%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
index 546e67c782..f0f495ddf0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/init/ReportingTaskingInitializer.java
@@ -51,7 +51,7 @@ public class ReportingTaskingInitializer implements ConfigurableComponentInitial
final MockConfigurationContext context = new MockConfigurationContext();
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnShutdown.class, reportingTask, new MockComponentLogger(), context);
} finally {
- ExtensionManager.removeInstanceClassLoaderIfExists(component.getIdentifier());
+ ExtensionManager.removeInstanceClassLoader(component.getIdentifier());
}
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockComponentLogger.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceInitializationContext.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockControllerServiceLookup.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockNodeTypeProvider.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessorInitializationContext.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockReportingInitializationContext.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
similarity index 68%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
index 1cff3af972..14d3dccdbd 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java
@@ -21,7 +21,6 @@ import org.apache.nifi.authentication.LoginIdentityProvider;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.bundle.BundleCoordinate;
-import org.apache.nifi.bundle.BundleDetails;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.state.StateProvider;
@@ -37,12 +36,10 @@ import org.apache.nifi.processor.Processor;
import org.apache.nifi.provenance.ProvenanceRepository;
import org.apache.nifi.reporting.InitializationException;
import org.apache.nifi.reporting.ReportingTask;
-import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
@@ -50,6 +47,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
@@ -67,18 +65,16 @@ public class ExtensionManager {
private static final Logger logger = LoggerFactory.getLogger(ExtensionManager.class);
- public static final BundleCoordinate SYSTEM_BUNDLE_COORDINATE = new BundleCoordinate(
- BundleCoordinate.DEFAULT_GROUP, "system", BundleCoordinate.DEFAULT_VERSION);
-
// Maps a service definition (interface) to those classes that implement the interface
private static final Map> definitionMap = new HashMap<>();
private static final Map> classNameBundleLookup = new HashMap<>();
private static final Map bundleCoordinateBundleLookup = new HashMap<>();
private static final Map classLoaderBundleLookup = new HashMap<>();
+ private static final Map tempComponentLookup = new HashMap<>();
- private static final Set requiresInstanceClassLoading = new HashSet<>();
- private static final Map instanceClassloaderLookup = new ConcurrentHashMap<>();
+ private static final Map> requiresInstanceClassLoading = new HashMap<>();
+ private static final Map instanceClassloaderLookup = new ConcurrentHashMap<>();
static {
definitionMap.put(Processor.class, new HashSet<>());
@@ -126,29 +122,6 @@ public class ExtensionManager {
}
}
- /**
- * Returns a bundle representing the system class loader.
- *
- * @param niFiProperties a NiFiProperties instance which will be used to obtain the default NAR library path,
- * which will become the working directory of the returned bundle
- * @return a bundle for the system class loader
- */
- public static Bundle createSystemBundle(final NiFiProperties niFiProperties) {
- final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
-
- final String narLibraryDirectory = niFiProperties.getProperty(NiFiProperties.NAR_LIBRARY_DIRECTORY);
- if (StringUtils.isBlank(narLibraryDirectory)) {
- throw new IllegalStateException("Unable to create system bundle because " + NiFiProperties.NAR_LIBRARY_DIRECTORY + " was null or empty");
- }
-
- final BundleDetails systemBundleDetails = new BundleDetails.Builder()
- .workingDir(new File(narLibraryDirectory))
- .coordinate(SYSTEM_BUNDLE_COORDINATE)
- .build();
-
- return new Bundle(systemBundleDetails, systemClassLoader);
- }
-
/**
* Loads extensions from the specified bundle.
*
@@ -163,6 +136,15 @@ public class ExtensionManager {
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());
@@ -185,50 +167,48 @@ public class ExtensionManager {
registerServiceClass(o.getClass(), classNameBundleLookup, bundle, entry.getValue());
}
}
+
}
classLoaderBundleLookup.put(bundle.getClassLoader(), bundle);
}
}
+ private static void initializeTempComponent(final ConfigurableComponent configurableComponent) {
+ ConfigurableComponentInitializer initializer = null;
+ try {
+ initializer = ConfigurableComponentInitializerFactory.createComponentInitializer(configurableComponent.getClass());
+ initializer.initialize(configurableComponent);
+ } catch (final InitializationException e) {
+ logger.warn(String.format("Unable to initialize component %s due to %s", configurableComponent.getClass().getName(), e.getMessage()));
+ }
+ }
+
private static boolean checkControllerServiceReferenceEligibility(final ConfigurableComponent component, final ClassLoader classLoader) {
// if the extension does not require instance classloading, its eligible
final boolean requiresInstanceClassLoading = component.getClass().isAnnotationPresent(RequiresInstanceClassLoading.class);
- ConfigurableComponentInitializer initializer = null;
- try {
- initializer = ConfigurableComponentInitializerFactory.createComponentInitializer(component.getClass());
- initializer.initialize(component);
-
- final Set cobundledApis = new HashSet<>();
- try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) {
- final List descriptors = component.getPropertyDescriptors();
- if (descriptors != null && !descriptors.isEmpty()) {
- for (final PropertyDescriptor descriptor : descriptors) {
- final Class extends ControllerService> serviceApi = descriptor.getControllerServiceDefinition();
- if (serviceApi != null && classLoader.equals(serviceApi.getClassLoader())) {
- cobundledApis.add(serviceApi);
- }
+ final Set cobundledApis = new HashSet<>();
+ try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) {
+ final List descriptors = component.getPropertyDescriptors();
+ if (descriptors != null && !descriptors.isEmpty()) {
+ for (final PropertyDescriptor descriptor : descriptors) {
+ final Class extends ControllerService> serviceApi = descriptor.getControllerServiceDefinition();
+ if (serviceApi != null && classLoader.equals(serviceApi.getClassLoader())) {
+ cobundledApis.add(serviceApi);
}
}
}
-
- if (!cobundledApis.isEmpty()) {
- logger.warn(String.format(
- "Component %s is bundled with its referenced Controller Service APIs %s. The service APIs should not be bundled with component implementations that reference it.",
- component.getClass().getName(), StringUtils.join(cobundledApis.stream().map(cls -> cls.getName()).collect(Collectors.toSet()), ", ")));
- }
-
- // the component is eligible when it does not require instance classloading or when the supporting APIs are bundled in a parent NAR
- return requiresInstanceClassLoading == false || cobundledApis.isEmpty();
- } catch (final InitializationException e) {
- logger.warn(String.format("Unable to verify if component %s references any bundled Controller Service APIs due to %s", component.getClass().getName(), e.getMessage()));
- return true;
- } finally {
- if (initializer != null) {
- initializer.teardown(component);
- }
}
+
+ if (!cobundledApis.isEmpty()) {
+ logger.warn(String.format(
+ "Component %s is bundled with its referenced Controller Service APIs %s. The service APIs should not be bundled with component implementations that reference it.",
+ component.getClass().getName(), StringUtils.join(cobundledApis.stream().map(cls -> cls.getName()).collect(Collectors.toSet()), ", ")));
+ }
+
+ // the component is eligible when it does not require instance classloading or when the supporting APIs are bundled in a parent NAR
+ return requiresInstanceClassLoading == false || cobundledApis.isEmpty();
}
private static boolean checkControllerServiceEligibility(Class extensionType) {
@@ -304,7 +284,8 @@ public class ExtensionManager {
classes.add(type);
if (type.isAnnotationPresent(RequiresInstanceClassLoading.class)) {
- requiresInstanceClassLoading.add(className);
+ final String cacheKey = getClassBundleKey(className, bundle.getBundleDetails().getCoordinate());
+ requiresInstanceClassLoading.put(cacheKey, type);
}
}
@@ -324,9 +305,10 @@ public class ExtensionManager {
* @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 ClassLoader createInstanceClassLoader(final String classType, final String instanceIdentifier, final Bundle bundle) {
+ public static InstanceClassLoader createInstanceClassLoader(final String classType, final String instanceIdentifier, final Bundle bundle, final Set additionalUrls) {
if (StringUtils.isEmpty(classType)) {
throw new IllegalArgumentException("Class-Type is required");
}
@@ -339,67 +321,128 @@ public class ExtensionManager {
throw new IllegalArgumentException("Bundle is required");
}
- final ClassLoader bundleClassLoader = bundle.getClassLoader();
-
// 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
- ClassLoader instanceClassLoader;
- if (requiresInstanceClassLoading.contains(classType) && (bundleClassLoader instanceof URLClassLoader)) {
- final URLClassLoader registeredUrlClassLoader = (URLClassLoader) bundleClassLoader;
- instanceClassLoader = new InstanceClassLoader(instanceIdentifier, classType, registeredUrlClassLoader.getURLs(), registeredUrlClassLoader.getParent());
+
+ 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 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 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, new URL[0], bundleClassLoader);
+ 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;
}
+ /**
+ * 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 findReachableApiBundles(final ConfigurableComponent component) {
+ final Set reachableApiBundles = new HashSet<>();
+
+ try (final NarCloseable closeable = NarCloseable.withComponentNarLoader(component.getClass().getClassLoader())) {
+ final List 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;
+ }
+
/**
* Retrieves the InstanceClassLoader for the component with the given identifier.
*
* @param instanceIdentifier the identifier of a component
* @return the instance class loader for the component
*/
- public static ClassLoader getInstanceClassLoader(final String instanceIdentifier) {
+ public static InstanceClassLoader getInstanceClassLoader(final String instanceIdentifier) {
return instanceClassloaderLookup.get(instanceIdentifier);
}
/**
- * Removes the ClassLoader for the given instance and closes it if necessary.
+ * Removes the InstanceClassLoader for a given component.
*
- * @param instanceIdentifier the identifier of a component to remove the ClassLoader for
- * @return the removed ClassLoader for the given instance, or null if not found
+ * @param instanceIdentifier the of a component
*/
- public static ClassLoader removeInstanceClassLoaderIfExists(final String instanceIdentifier) {
+ public static InstanceClassLoader removeInstanceClassLoader(final String instanceIdentifier) {
if (instanceIdentifier == null) {
return null;
}
- final ClassLoader classLoader = instanceClassloaderLookup.remove(instanceIdentifier);
+ final InstanceClassLoader classLoader = instanceClassloaderLookup.remove(instanceIdentifier);
+ closeURLClassLoader(instanceIdentifier, classLoader);
+ return classLoader;
+ }
+
+ /**
+ * Closes the given ClassLoader if it is an instance of URLClassLoader.
+ *
+ * @param instanceIdentifier the instance id the class loader corresponds to
+ * @param classLoader the class loader to close
+ */
+ public static void closeURLClassLoader(final String instanceIdentifier, final ClassLoader classLoader) {
if (classLoader != null && (classLoader instanceof URLClassLoader)) {
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
try {
urlClassLoader.close();
} catch (IOException e) {
- logger.warn("Unable to class URLClassLoader for " + instanceIdentifier);
+ logger.warn("Unable to close URLClassLoader for " + instanceIdentifier);
}
}
- return classLoader;
- }
-
- /**
- * Checks if the given class type requires per-instance class loading (i.e. contains the @RequiresInstanceClassLoading annotation)
- *
- * @param classType the class to check
- * @return true if the class is found in the set of classes requiring instance level class loading, false otherwise
- */
- public static boolean requiresInstanceClassLoading(final String classType) {
- if (classType == null) {
- throw new IllegalArgumentException("Class type cannot be null");
- }
- return requiresInstanceClassLoading.contains(classType);
}
/**
@@ -450,6 +493,22 @@ public class ExtensionManager {
return (extensions == null) ? Collections.emptySet() : extensions;
}
+ public static ConfigurableComponent getTempComponent(final String classType, final BundleCoordinate bundleCoordinate) {
+ if (classType == null) {
+ throw new IllegalArgumentException("Class type cannot be null");
+ }
+
+ if (bundleCoordinate == null) {
+ throw new IllegalArgumentException("Bundle Coordinate cannot be null");
+ }
+
+ return tempComponentLookup.get(getClassBundleKey(classType, bundleCoordinate));
+ }
+
+ private static String getClassBundleKey(final String classType, final BundleCoordinate bundleCoordinate) {
+ return classType + "_" + bundleCoordinate.getCoordinate();
+ }
+
public static void logClassLoaderMapping() {
final StringBuilder builder = new StringBuilder();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java
new file mode 100644
index 0000000000..d9e23fa216
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java
@@ -0,0 +1,89 @@
+/*
+ * 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.nar;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Each processor, controller service, and reporting task will have an InstanceClassLoader.
+ *
+ * The InstanceClassLoader will either be an empty pass-through to the NARClassLoader, or will contain a
+ * copy of all the NAR's resources in the case of components that @RequireInstanceClassLoading.
+ */
+public class InstanceClassLoader extends URLClassLoader {
+
+ private static final Logger logger = LoggerFactory.getLogger(InstanceClassLoader.class);
+
+ private final String identifier;
+ private final String instanceType;
+
+ private final Set instanceUrls;
+ private final Set additionalResourceUrls;
+
+ /**
+ * @param identifier the id of the component this ClassLoader was created for
+ * @param instanceUrls the urls for the instance, will either be empty or a copy of the NARs urls
+ * @param additionalResourceUrls the urls that came from runtime properties of the component
+ * @param parent the parent ClassLoader
+ */
+ public InstanceClassLoader(final String identifier, final String type, final Set instanceUrls, final Set additionalResourceUrls, final ClassLoader parent) {
+ super(combineURLs(instanceUrls, additionalResourceUrls), parent);
+ this.identifier = identifier;
+ this.instanceType = type;
+ this.instanceUrls = Collections.unmodifiableSet(
+ instanceUrls == null ? Collections.emptySet() : new LinkedHashSet<>(instanceUrls));
+ this.additionalResourceUrls = Collections.unmodifiableSet(
+ additionalResourceUrls == null ? Collections.emptySet() : new LinkedHashSet<>(additionalResourceUrls));
+ }
+
+ private static URL[] combineURLs(final Set instanceUrls, final Set additionalResourceUrls) {
+ final Set allUrls = new LinkedHashSet<>();
+
+ if (instanceUrls != null) {
+ allUrls.addAll(instanceUrls);
+ }
+
+ if (additionalResourceUrls != null) {
+ allUrls.addAll(additionalResourceUrls);
+ }
+
+ return allUrls.toArray(new URL[allUrls.size()]);
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public String getInstanceType() {
+ return instanceType;
+ }
+
+ public Set getInstanceUrls() {
+ return instanceUrls;
+ }
+
+ public Set getAdditionalResourceUrls() {
+ return additionalResourceUrls;
+ }
+}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarCloseable.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/NarThreadContextClassLoader.java
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java
similarity index 94%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java
index 4528c0aaa5..39014bc617 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarThreadContextClassLoaderTest.java
@@ -36,7 +36,7 @@ public class NarThreadContextClassLoaderTest {
@Test
public void validateWithPropertiesConstructor() throws Exception {
NiFiProperties properties = NiFiProperties.createBasicNiFiProperties("src/test/resources/nifi.properties", null);
- Bundle systemBundle = ExtensionManager.createSystemBundle(properties);
+ Bundle systemBundle = SystemBundle.create(properties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
Object obj = NarThreadContextClassLoader.createInstance(WithPropertiesConstructor.class.getName(),
@@ -51,7 +51,7 @@ public class NarThreadContextClassLoaderTest {
Map additionalProperties = new HashMap<>();
additionalProperties.put("fail", "true");
NiFiProperties properties = NiFiProperties.createBasicNiFiProperties("src/test/resources/nifi.properties", additionalProperties);
- Bundle systemBundle = ExtensionManager.createSystemBundle(properties);
+ Bundle systemBundle = SystemBundle.create(properties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
NarThreadContextClassLoader.createInstance(WithPropertiesConstructor.class.getName(), WithPropertiesConstructor.class, properties);
}
@@ -59,7 +59,7 @@ public class NarThreadContextClassLoaderTest {
@Test
public void validateWithDefaultConstructor() throws Exception {
NiFiProperties properties = NiFiProperties.createBasicNiFiProperties("src/test/resources/nifi.properties", null);
- Bundle systemBundle = ExtensionManager.createSystemBundle(properties);
+ Bundle systemBundle = SystemBundle.create(properties);
ExtensionManager.discoverExtensions(systemBundle, Collections.emptySet());
assertTrue(NarThreadContextClassLoader.createInstance(WithDefaultConstructor.class.getName(),
WithDefaultConstructor.class, properties) instanceof WithDefaultConstructor);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
similarity index 96%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
index 8cc2ccd606..ac666ca844 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
@@ -88,7 +88,7 @@ public class NarUnpackerTest {
assertEquals("./target/NarUnpacker/lib2/",
properties.getProperty("nifi.nar.library.directory.alt"));
- final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, ExtensionManager.createSystemBundle(properties));
+ final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, SystemBundle.create(properties));
assertEquals(2, extensionMapping.getAllExtensionNames().size());
@@ -119,7 +119,7 @@ public class NarUnpackerTest {
others.put("nifi.nar.library.directory.alt", emptyDir.toString());
NiFiProperties properties = loadSpecifiedProperties("/NarUnpacker/conf/nifi.properties", others);
- final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, ExtensionManager.createSystemBundle(properties));
+ final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, SystemBundle.create(properties));
assertEquals(1, extensionMapping.getAllExtensionNames().size());
assertTrue(extensionMapping.getAllExtensionNames().keySet().contains("org.apache.nifi.processors.dummy.one"));
@@ -142,7 +142,7 @@ public class NarUnpackerTest {
others.put("nifi.nar.library.directory.alt", nonExistantDir.toString());
NiFiProperties properties = loadSpecifiedProperties("/NarUnpacker/conf/nifi.properties", others);
- final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, ExtensionManager.createSystemBundle(properties));
+ final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, SystemBundle.create(properties));
assertTrue(extensionMapping.getAllExtensionNames().keySet().contains("org.apache.nifi.processors.dummy.one"));
@@ -166,7 +166,7 @@ public class NarUnpackerTest {
others.put("nifi.nar.library.directory.alt", nonDir.toString());
NiFiProperties properties = loadSpecifiedProperties("/NarUnpacker/conf/nifi.properties", others);
- final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, ExtensionManager.createSystemBundle(properties));
+ final ExtensionMapping extensionMapping = NarUnpacker.unpackNars(properties, SystemBundle.create(properties));
assertNull(extensionMapping);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/META-INF/services/org.apache.nifi.processor.Processor
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties
similarity index 98%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties
index 0559752ec8..3a17e0daeb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/conf/nifi.properties
@@ -30,6 +30,7 @@ nifi.nar.library.directory=./target/NarUnpacker/lib/
nifi.nar.library.directory.alt=./target/NarUnpacker/lib2/
nifi.nar.working.directory=./target/work/nar/
+nifi.documentation.working.directory=./target/work/docs/components
# H2 Settings
nifi.database.directory=./target/database_repository
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib/dummy-one.nar b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib/dummy-one.nar
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib/dummy-one.nar
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib/dummy-one.nar
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib/nifi-framework-nar.nar b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib/nifi-framework-nar.nar
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib/nifi-framework-nar.nar
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib/nifi-framework-nar.nar
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib2/dummy-two.nar b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib2/dummy-two.nar
similarity index 100%
rename from nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/resources/NarUnpacker/lib2/dummy-two.nar
rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/NarUnpacker/lib2/dummy-two.nar
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/nifi.properties
new file mode 100644
index 0000000000..bbec9680f2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/resources/nifi.properties
@@ -0,0 +1,198 @@
+# 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.
+
+# Core Properties #
+nifi.flow.configuration.file=./conf/flow.xml.gz
+nifi.flow.configuration.archive.enabled=true
+nifi.flow.configuration.archive.dir=./conf/archive/
+nifi.flow.configuration.archive.max.time=30 days
+nifi.flow.configuration.archive.max.storage=500 MB
+nifi.flowcontroller.autoResumeState=true
+nifi.flowcontroller.graceful.shutdown.period=10 sec
+nifi.flowservice.writedelay.interval=500 ms
+nifi.administrative.yield.duration=30 sec
+# If a component has no work to do (is "bored"), how long should we wait before checking again for work?
+nifi.bored.yield.duration=10 millis
+
+nifi.authorizer.configuration.file=./conf/authorizers.xml
+nifi.login.identity.provider.configuration.file=./conf/login-identity-providers.xml
+nifi.templates.directory=./conf/templates
+nifi.ui.banner.text=
+nifi.ui.autorefresh.interval=30 sec
+nifi.nar.library.directory=./lib
+nifi.nar.working.directory=./target/work/nar/
+nifi.documentation.working.directory=./target/work/docs/components
+
+####################
+# State Management #
+####################
+nifi.state.management.configuration.file=./conf/state-management.xml
+# The ID of the local state provider
+nifi.state.management.provider.local=local-provider
+# The ID of the cluster-wide state provider. This will be ignored if NiFi is not clustered but must be populated if running in a cluster.
+nifi.state.management.provider.cluster=zk-provider
+# Specifies whether or not this instance of NiFi should run an embedded ZooKeeper server
+nifi.state.management.embedded.zookeeper.start=false
+# Properties file that provides the ZooKeeper properties to use if is set to true
+nifi.state.management.embedded.zookeeper.properties=./conf/zookeeper.properties
+
+
+# H2 Settings
+nifi.database.directory=./database_repository
+nifi.h2.url.append=;LOCK_TIMEOUT=25000;WRITE_DELAY=0;AUTO_SERVER=FALSE
+
+# FlowFile Repository
+nifi.flowfile.repository.implementation=org.apache.nifi.controller.repository.WriteAheadFlowFileRepository
+nifi.flowfile.repository.directory=./flowfile_repository
+nifi.flowfile.repository.partitions=256
+nifi.flowfile.repository.checkpoint.interval=2 mins
+nifi.flowfile.repository.always.sync=false
+
+nifi.swap.manager.implementation=org.apache.nifi.controller.FileSystemSwapManager
+nifi.queue.swap.threshold=20000
+nifi.swap.in.period=5 sec
+nifi.swap.in.threads=1
+nifi.swap.out.period=5 sec
+nifi.swap.out.threads=4
+
+# Content Repository
+nifi.content.repository.implementation=org.apache.nifi.controller.repository.FileSystemRepository
+nifi.content.claim.max.appendable.size=10 MB
+nifi.content.claim.max.flow.files=100
+nifi.content.repository.directory.default=./content_repository
+nifi.content.repository.directory.content1=/tmp/foo/repo
+nifi.content.repository.archive.max.retention.period=12 hours
+nifi.content.repository.archive.max.usage.percentage=50%
+nifi.content.repository.archive.enabled=true
+nifi.content.repository.always.sync=false
+nifi.content.viewer.url=/nifi-content-viewer/
+
+# Provenance Repository Properties
+nifi.provenance.repository.implementation=org.apache.nifi.provenance.PersistentProvenanceRepository
+
+# Persistent Provenance Repository Properties
+nifi.provenance.repository.directory.default=./provenance_repository
+nifi.provenance.repository.max.storage.time=24 hours
+nifi.provenance.repository.max.storage.size=1 GB
+nifi.provenance.repository.rollover.time=30 secs
+nifi.provenance.repository.rollover.size=100 MB
+nifi.provenance.repository.query.threads=2
+nifi.provenance.repository.index.threads=1
+nifi.provenance.repository.compress.on.rollover=true
+nifi.provenance.repository.always.sync=false
+nifi.provenance.repository.journal.count=16
+# Comma-separated list of fields. Fields that are not indexed will not be searchable. Valid fields are:
+# EventType, FlowFileUUID, Filename, TransitURI, ProcessorID, AlternateIdentifierURI, Relationship, Details
+nifi.provenance.repository.indexed.fields=EventType, FlowFileUUID, Filename, ProcessorID, Relationship
+# FlowFile Attributes that should be indexed and made searchable. Some examples to consider are filename, uuid, mime.type
+nifi.provenance.repository.indexed.attributes=
+# Large values for the shard size will result in more Java heap usage when searching the Provenance Repository
+# but should provide better performance
+nifi.provenance.repository.index.shard.size=500 MB
+# Indicates the maximum length that a FlowFile attribute can be when retrieving a Provenance Event from
+# the repository. If the length of any attribute exceeds this value, it will be truncated when the event is retrieved.
+nifi.provenance.repository.max.attribute.length=65536
+
+# Volatile Provenance Respository Properties
+nifi.provenance.repository.buffer.size=100000
+
+# Component Status Repository
+nifi.components.status.repository.implementation=org.apache.nifi.controller.status.history.VolatileComponentStatusRepository
+nifi.components.status.repository.buffer.size=1440
+nifi.components.status.snapshot.frequency=1 min
+
+# Site to Site properties
+nifi.remote.input.host=
+nifi.remote.input.secure=false
+nifi.remote.input.socket.port=
+nifi.remote.input.http.enabled=true
+nifi.remote.input.http.transaction.ttl=30 sec
+
+# web properties #
+nifi.web.war.directory=./lib
+nifi.web.http.host=
+nifi.web.http.port=8080
+nifi.web.https.host=
+nifi.web.https.port=
+nifi.web.jetty.working.directory=./work/jetty
+nifi.web.jetty.threads=200
+
+# security properties #
+nifi.sensitive.props.key=
+nifi.sensitive.props.key.protected=
+nifi.sensitive.props.algorithm=PBEWITHMD5AND256BITAES-CBC-OPENSSL
+nifi.sensitive.props.provider=BC
+nifi.sensitive.props.additional.keys=
+
+nifi.security.keystore=
+nifi.security.keystoreType=
+nifi.security.keystorePasswd=
+nifi.security.keyPasswd=
+nifi.security.truststore=
+nifi.security.truststoreType=
+nifi.security.truststorePasswd=
+nifi.security.needClientAuth=
+nifi.security.user.authorizer=file-provider
+nifi.security.user.login.identity.provider=
+nifi.security.ocsp.responder.url=
+nifi.security.ocsp.responder.certificate=
+
+# Identity Mapping Properties #
+# These properties allow normalizing user identities such that identities coming from different identity providers
+# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
+# DNs from certificates and principals from Kerberos into a common identity string:
+#
+# nifi.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
+# nifi.security.identity.mapping.value.dn=$1@$2
+# nifi.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
+# nifi.security.identity.mapping.value.kerb=$1@$2
+
+# cluster common properties (all nodes must have same values) #
+nifi.cluster.protocol.heartbeat.interval=5 sec
+nifi.cluster.protocol.is.secure=false
+
+# cluster node properties (only configure for cluster nodes) #
+nifi.cluster.is.node=false
+nifi.cluster.node.address=
+nifi.cluster.node.protocol.port=
+nifi.cluster.node.protocol.threads=10
+nifi.cluster.node.event.history.size=25
+nifi.cluster.node.connection.timeout=5 sec
+nifi.cluster.node.read.timeout=5 sec
+nifi.cluster.firewall.file=
+nifi.cluster.flow.election.max.wait.time=5 mins
+nifi.cluster.flow.election.max.candidates=
+
+# zookeeper properties, used for cluster management #
+nifi.zookeeper.connect.string=
+nifi.zookeeper.connect.timeout=3 secs
+nifi.zookeeper.session.timeout=3 secs
+nifi.zookeeper.root.node=/nifi
+
+# kerberos #
+nifi.kerberos.krb5.file=
+
+# kerberos service principal #
+nifi.kerberos.service.principal=
+nifi.kerberos.service.keytab.location=
+
+# kerberos spnego principal #
+nifi.kerberos.spnego.principal=
+nifi.kerberos.spnego.keytab.location=
+nifi.kerberos.spnego.authentication.expiration=12 hours
+
+# external properties files for variable registry
+# supports a comma delimited list of file locations
+nifi.variable.registry.properties=
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/pom.xml
index 7f9b84b6ed..192d4f10d5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/pom.xml
@@ -45,6 +45,7 @@
src/test/resources/nars/nar-with-versioning/META-INF/MANIFEST.MF
src/test/resources/nars/nar-without-versioning/META-INF/MANIFEST.MF
src/test/resources/nars/nar-without-dependency/META-INF/MANIFEST.MF
+ src/test/resources/nars/nar-requires-cloning/META-INF/MANIFEST.MF
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java
deleted file mode 100644
index 2a9c72d00d..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/InstanceClassLoader.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * 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.nar;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-
-/**
- * A ClassLoader created for an instance of a component which lets a client add resources to an intermediary ClassLoader
- * that will be checked first when loading/finding classes.
- *
- * Typically an instance of this ClassLoader will be created by passing in the URLs and parent from a NARClassLoader in
- * order to create a copy of the NARClassLoader without modifying it.
- */
-public class InstanceClassLoader extends URLClassLoader {
-
- private static final Logger logger = LoggerFactory.getLogger(InstanceClassLoader.class);
-
- private final String identifier;
- private final String instanceType;
- private ShimClassLoader shimClassLoader;
-
- /**
- * @param identifier the id of the component this ClassLoader was created for
- * @param urls the URLs for the ClassLoader
- * @param parent the parent ClassLoader
- */
- public InstanceClassLoader(final String identifier, final String type, final URL[] urls, final ClassLoader parent) {
- super(urls, parent);
- this.identifier = identifier;
- this.instanceType = type;
- }
-
- /**
- * Initializes a new ShimClassLoader for the provided resources, closing the previous ShimClassLoader if one existed.
- *
- * @param urls the URLs for the ShimClassLoader
- * @throws IOException if the previous ShimClassLoader existed and couldn't be closed
- */
- public synchronized void setInstanceResources(final URL[] urls) {
- if (shimClassLoader != null) {
- try {
- shimClassLoader.close();
- } catch (IOException e) {
- logger.warn("Unable to close inner URLClassLoader for " + identifier);
- }
- }
-
- shimClassLoader = new ShimClassLoader(urls, getParent());
- }
-
- /**
- * @return the URLs for the instance resources that have been set
- */
- public synchronized URL[] getInstanceResources() {
- if (shimClassLoader != null) {
- return shimClassLoader.getURLs();
- }
- return new URL[0];
- }
-
- @Override
- public Class> loadClass(String name) throws ClassNotFoundException {
- return this.loadClass(name, false);
- }
-
- @Override
- protected Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- Class> c = null;
- // first try the shim
- if (shimClassLoader != null) {
- try {
- c = shimClassLoader.loadClass(name, resolve);
- } catch (ClassNotFoundException e) {
- c = null;
- }
- }
- // if it wasn't in the shim try our self
- if (c == null) {
- return super.loadClass(name, resolve);
- } else {
- return c;
- }
- }
-
- @Override
- protected Class> findClass(String name) throws ClassNotFoundException {
- Class> c = null;
- // first try the shim
- if (shimClassLoader != null) {
- try {
- c = shimClassLoader.findClass(name);
- } catch (ClassNotFoundException cnf) {
- c = null;
- }
- }
- // if it wasn't in the shim try our self
- if (c == null) {
- return super.findClass(name);
- } else {
- return c;
- }
- }
-
- @Override
- public void close() throws IOException {
- if (shimClassLoader != null) {
- try {
- shimClassLoader.close();
- } catch (IOException e) {
- logger.warn("Unable to close inner URLClassLoader for " + identifier);
- }
- }
- super.close();
- }
-
- /**
- * Extend URLClassLoader to increase visibility of protected methods so that InstanceClassLoader can delegate.
- */
- private static class ShimClassLoader extends URLClassLoader {
-
- public ShimClassLoader(URL[] urls, ClassLoader parent) {
- super(urls, parent);
- }
-
- public ShimClassLoader(URL[] urls) {
- super(urls);
- }
-
- @Override
- public Class> findClass(String name) throws ClassNotFoundException {
- return super.findClass(name);
- }
-
- @Override
- public Class> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- return super.loadClass(name, resolve);
- }
-
- }
-
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoaders.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoaders.java
index a656e7681a..005a8faa27 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoaders.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarClassLoaders.java
@@ -184,6 +184,7 @@ public final class NarClassLoaders {
jettyClassLoader = createNarClassLoader(narDetail.getWorkingDirectory(), systemClassLoader);
// remove the jetty nar since its already loaded
+ narDirectoryBundleLookup.put(narDetail.getWorkingDirectory().getCanonicalPath(), new Bundle(narDetail, jettyClassLoader));
narCoordinateClassLoaderLookup.put(narDetail.getCoordinate().getCoordinate(), jettyClassLoader);
narDetailsIter.remove();
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarManifestEntry.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarManifestEntry.java
index da54c4ea1a..8b027420b2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarManifestEntry.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarManifestEntry.java
@@ -32,7 +32,7 @@ public enum NarManifestEntry {
BUILD_BRANCH("Build-Branch"),
BUILD_TIMESTAMP("Build-Timestamp"),
BUILD_JDK("Build-Jdk"),
- BUILT_BY("Built-By")
+ BUILT_BY("Built-By"),
;
final String manifestName;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/SystemBundle.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/SystemBundle.java
new file mode 100644
index 0000000000..0fb2bade40
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/SystemBundle.java
@@ -0,0 +1,57 @@
+/*
+ * 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.nar;
+
+import org.apache.nifi.bundle.Bundle;
+import org.apache.nifi.bundle.BundleCoordinate;
+import org.apache.nifi.bundle.BundleDetails;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.util.StringUtils;
+
+import java.io.File;
+
+/**
+ * Utility to create the system bundle.
+ */
+public final class SystemBundle {
+
+ public static final BundleCoordinate SYSTEM_BUNDLE_COORDINATE = new BundleCoordinate(
+ BundleCoordinate.DEFAULT_GROUP, "system", BundleCoordinate.DEFAULT_VERSION);
+
+ /**
+ * Returns a bundle representing the system class loader.
+ *
+ * @param niFiProperties a NiFiProperties instance which will be used to obtain the default NAR library path,
+ * which will become the working directory of the returned bundle
+ * @return a bundle for the system class loader
+ */
+ public static Bundle create(final NiFiProperties niFiProperties) {
+ final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+
+ final String narLibraryDirectory = niFiProperties.getProperty(NiFiProperties.NAR_LIBRARY_DIRECTORY);
+ if (StringUtils.isBlank(narLibraryDirectory)) {
+ throw new IllegalStateException("Unable to create system bundle because " + NiFiProperties.NAR_LIBRARY_DIRECTORY + " was null or empty");
+ }
+
+ final BundleDetails systemBundleDetails = new BundleDetails.Builder()
+ .workingDir(new File(narLibraryDirectory))
+ .coordinate(SYSTEM_BUNDLE_COORDINATE)
+ .build();
+
+ return new Bundle(systemBundleDetails, systemClassLoader);
+ }
+}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarBundleUtilTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarBundleUtilTest.java
index aa526c6ca8..df6a36154f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarBundleUtilTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/test/java/org/apache/nifi/nar/NarBundleUtilTest.java
@@ -16,9 +16,6 @@
*/
package org.apache.nifi.nar;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
import org.apache.nifi.bundle.BundleCoordinate;
import org.apache.nifi.bundle.BundleDetails;
import org.junit.Test;
@@ -26,6 +23,9 @@ import org.junit.Test;
import java.io.File;
import java.io.IOException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
public class NarBundleUtilTest {
@Test
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml
index 44ec7ea388..f97cc69fba 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-runtime/pom.xml
@@ -43,11 +43,6 @@
provided