NIFI-3520 Refactoring instance class loading
- Fixing FlowController to use appropriate class loader when instantiating 
processor
- Updating ExtensionManager to leverage new flag in MANIFEST from NAR plugin
- Adding ReloadComponent interface and refactoring instance class loading to 
use it
- Fixing FetchHDFS issue with TDE by using ugi.doAs
- Refactoring nifi-nar-utils so that ExtensionManager only lives in 
nifi-framework
- Caching temp components found during service loader in ExtensionManager
- Updating authorizables, docs, and fingerprinting to use the cached components
- Introducing a flag on @RequiresInstanceClassLoading to indicate if ancestor 
resources should be cloned
- Updating developer guide regarding cloneAncestorResources flag
- This closes #1635


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/556f309d
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/556f309d
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/556f309d

Branch: refs/heads/master
Commit: 556f309df086fefdcc6ca717294eaa91d3a4e113
Parents: 8f37ad4
Author: Bryan Bende <[email protected]>
Authored: Fri Mar 24 17:14:24 2017 -0400
Committer: Matt Gilman <[email protected]>
Committed: Thu Apr 6 13:51:08 2017 -0400

----------------------------------------------------------------------
 .../behavior/RequiresInstanceClassLoading.java  |  18 +-
 .../src/main/asciidoc/developer-guide.adoc      |   5 +
 .../apache/nifi/bundle/BundleDetailsTest.java   |   2 +
 .../nifi-framework/nifi-documentation/pom.xml   |  12 +-
 .../apache/nifi/documentation/DocGenerator.java |  14 +-
 .../nifi/documentation/DocGeneratorTest.java    |   3 +-
 .../apache/nifi/cluster/integration/Node.java   |   3 +-
 .../nifi-framework-core-api/pom.xml             |   2 +-
 .../controller/AbstractConfiguredComponent.java |  41 +-
 .../nifi/controller/ConfiguredComponent.java    |   4 +
 .../apache/nifi/controller/ProcessorNode.java   |   4 +-
 .../apache/nifi/controller/ReloadComponent.java |  69 +++
 .../reporting/ReportingTaskProvider.java        |  10 -
 .../service/ControllerServiceProvider.java      |   4 +-
 .../nifi-framework/nifi-framework-core/pom.xml  |   8 +-
 .../apache/nifi/controller/FlowController.java  |  76 +--
 .../nifi/controller/StandardProcessorNode.java  |  19 +-
 .../reporting/AbstractReportingTaskNode.java    |  21 +-
 .../reporting/StandardReportingTaskNode.java    |  10 +-
 .../service/ControllerServiceLoader.java        |   6 +-
 .../service/StandardControllerServiceNode.java  |  22 +-
 .../StandardControllerServiceProvider.java      |  11 +-
 .../nifi/fingerprint/FingerprintFactory.java    |  82 +--
 .../nifi/groups/StandardProcessGroup.java       |   4 +-
 .../StandardFlowSynchronizerSpec.groovy         |   3 +-
 .../nifi/controller/TestFlowController.java     | 129 ++++-
 .../controller/TestStandardProcessorNode.java   | 180 ++++---
 .../scheduling/TestProcessorLifecycle.java      |   7 +-
 .../TestStandardProcessScheduler.java           |  27 +-
 .../StandardControllerServiceProviderTest.java  |   5 +-
 .../TestStandardControllerServiceProvider.java  |  69 +--
 .../nifi-framework-nar-utils/pom.xml            |  42 ++
 .../init/ConfigurableComponentInitializer.java  |  45 ++
 ...ConfigurableComponentInitializerFactory.java |  44 ++
 .../nifi/init/ControllerServiceInitializer.java |  59 ++
 .../apache/nifi/init/ProcessorInitializer.java  |  58 ++
 .../org/apache/nifi/init/ReflectionUtils.java   | 133 +++++
 .../nifi/init/ReportingTaskingInitializer.java  |  57 ++
 .../apache/nifi/mock/MockComponentLogger.java   | 258 +++++++++
 .../nifi/mock/MockConfigurationContext.java     |  48 ++
 ...kControllerServiceInitializationContext.java |  68 +++
 .../nifi/mock/MockControllerServiceLookup.java  |  63 +++
 .../apache/nifi/mock/MockNodeTypeProvider.java  |  40 ++
 .../apache/nifi/mock/MockProcessContext.java    | 116 ++++
 .../MockProcessorInitializationContext.java     |  68 +++
 .../MockReportingInitializationContext.java     |  83 +++
 .../org/apache/nifi/nar/ExtensionManager.java   | 537 +++++++++++++++++++
 .../apache/nifi/nar/InstanceClassLoader.java    |  89 +++
 .../java/org/apache/nifi/nar/NarCloseable.java  | 112 ++++
 .../nifi/nar/NarThreadContextClassLoader.java   | 235 ++++++++
 .../nar/NarThreadContextClassLoaderTest.java    |  99 ++++
 .../org/apache/nifi/nar/NarUnpackerTest.java    | 183 +++++++
 .../org.apache.nifi.processor.Processor         |  16 +
 .../resources/NarUnpacker/conf/nifi.properties  | 125 +++++
 .../resources/NarUnpacker/lib/dummy-one.nar     | Bin 0 -> 1749 bytes
 .../NarUnpacker/lib/nifi-framework-nar.nar      | Bin 0 -> 406 bytes
 .../resources/NarUnpacker/lib2/dummy-two.nar    | Bin 0 -> 1751 bytes
 .../src/test/resources/nifi.properties          | 198 +++++++
 .../nifi-framework/nifi-nar-utils/pom.xml       |   1 +
 .../init/ConfigurableComponentInitializer.java  |  45 --
 ...ConfigurableComponentInitializerFactory.java |  44 --
 .../nifi/init/ControllerServiceInitializer.java |  59 --
 .../apache/nifi/init/ProcessorInitializer.java  |  58 --
 .../org/apache/nifi/init/ReflectionUtils.java   | 133 -----
 .../nifi/init/ReportingTaskingInitializer.java  |  57 --
 .../apache/nifi/mock/MockComponentLogger.java   | 258 ---------
 .../nifi/mock/MockConfigurationContext.java     |  48 --
 ...kControllerServiceInitializationContext.java |  68 ---
 .../nifi/mock/MockControllerServiceLookup.java  |  63 ---
 .../apache/nifi/mock/MockNodeTypeProvider.java  |  40 --
 .../apache/nifi/mock/MockProcessContext.java    | 116 ----
 .../MockProcessorInitializationContext.java     |  68 ---
 .../MockReportingInitializationContext.java     |  83 ---
 .../org/apache/nifi/nar/ExtensionManager.java   | 478 -----------------
 .../apache/nifi/nar/InstanceClassLoader.java    | 160 ------
 .../org/apache/nifi/nar/NarClassLoaders.java    |   1 +
 .../java/org/apache/nifi/nar/NarCloseable.java  | 112 ----
 .../org/apache/nifi/nar/NarManifestEntry.java   |   2 +-
 .../nifi/nar/NarThreadContextClassLoader.java   | 235 --------
 .../java/org/apache/nifi/nar/SystemBundle.java  |  57 ++
 .../org/apache/nifi/nar/NarBundleUtilTest.java  |   6 +-
 .../nar/NarThreadContextClassLoaderTest.java    |  99 ----
 .../org/apache/nifi/nar/NarUnpackerTest.java    | 183 -------
 .../org.apache.nifi.processor.Processor         |  16 -
 .../resources/NarUnpacker/conf/nifi.properties  | 124 -----
 .../resources/NarUnpacker/lib/dummy-one.nar     | Bin 1749 -> 0 bytes
 .../NarUnpacker/lib/nifi-framework-nar.nar      | Bin 406 -> 0 bytes
 .../resources/NarUnpacker/lib2/dummy-two.nar    | Bin 1751 -> 0 bytes
 .../nifi-framework/nifi-runtime/pom.xml         |   5 -
 .../src/main/java/org/apache/nifi/NiFi.java     |  11 +-
 .../main/java/org/apache/nifi/NiFiServer.java   |   5 +
 .../nifi-framework/nifi-web/nifi-jetty/pom.xml  |   5 +
 .../org/apache/nifi/web/server/JettyServer.java |  16 +
 .../nifi/authorization/AuthorizableLookup.java  |  43 +-
 .../AuthorizeControllerServiceReference.java    |   6 +-
 .../authorization/ComponentAuthorizable.java    |  69 +++
 .../ConfigurableComponentAuthorizable.java      |  69 ---
 .../authorization/ProcessGroupAuthorizable.java |   4 +-
 .../nifi/authorization/SnippetAuthorizable.java |   2 +-
 .../StandardAuthorizableLookup.java             | 142 +++--
 .../TemplateContentsAuthorizable.java           |   4 +-
 .../nifi/web/StandardNiFiServiceFacade.java     |  10 +-
 .../StandardNiFiWebConfigurationContext.java    |   8 +-
 .../apache/nifi/web/api/ControllerResource.java |  10 +-
 .../nifi/web/api/ControllerServiceResource.java |   6 +-
 .../nifi/web/api/ProcessGroupResource.java      |  14 +-
 .../apache/nifi/web/api/ProcessorResource.java  |   6 +-
 .../nifi/web/api/ReportingTaskResource.java     |   6 +-
 .../nifi/web/controller/ControllerFacade.java   |  40 +-
 .../dao/impl/StandardControllerServiceDAO.java  |   5 +-
 .../nifi/web/dao/impl/StandardProcessorDAO.java |   3 +-
 .../web/dao/impl/StandardReportingTaskDAO.java  |   9 +-
 .../src/main/resources/nifi-web-api-context.xml |   1 +
 .../accesscontrol/AccessControlHelper.java      |   3 +-
 .../accesscontrol/ITAccessTokenEndpoint.java    |   3 +-
 .../nifi/web/StandardNiFiServiceFacadeTest.java |   4 +-
 .../nifi-framework/pom.xml                      |   1 +
 nifi-nar-bundles/nifi-framework-bundle/pom.xml  |   5 +
 .../nifi-hadoop-bundle/nifi-hadoop-nar/pom.xml  |   2 +-
 .../nifi-hdfs-processors/pom.xml                |  12 +-
 .../hadoop/AbstractHadoopProcessor.java         |  33 +-
 .../nifi/processors/hadoop/FetchHDFS.java       | 103 ++--
 .../nifi/controller/MonitorMemoryTest.java      |   3 +-
 123 files changed, 3763 insertions(+), 3165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-api/src/main/java/org/apache/nifi/annotation/behavior/RequiresInstanceClassLoading.java
----------------------------------------------------------------------
diff --git 
a/nifi-api/src/main/java/org/apache/nifi/annotation/behavior/RequiresInstanceClassLoading.java
 
b/nifi-api/src/main/java/org/apache/nifi/annotation/behavior/RequiresInstanceClassLoading.java
index f7566a6..0796199 100644
--- 
a/nifi-api/src/main/java/org/apache/nifi/annotation/behavior/RequiresInstanceClassLoading.java
+++ 
b/nifi-api/src/main/java/org/apache/nifi/annotation/behavior/RequiresInstanceClassLoading.java
@@ -28,10 +28,19 @@ import java.lang.annotation.Target;
  *  for each instance of the component, copying all resources from the 
component's NARClassLoader to a
  *  new ClassLoader which will only be used by a given instance of the 
component.
  *
- *  This annotation is typically used when a component has one or more 
PropertyDescriptors which set
- *  dynamicallyModifiesClasspath(boolean) to true.
+ *  If cloneAncestorResources is set to true, the instance ClassLoader will 
include ancestor resources up to the
+ *  first ClassLoader containing a controller service API referenced by the 
component, or up to the Jetty NAR.
  *
- *  When this annotation is used it is important to note that each added 
instance of the component will increase
+ *  Example #1 - PutHDFS has this flag set to true and does not reference any 
controller services, so it will include
+ *  resources from nifi-hadoop-nar, nifi-hadoop-libraries-nar, and 
nifi-standard-services-api-nar, stopping at nifi-jetty-nar.
+ *
+ *  Example #2 - If PutHDFS referenced an SSLContext and has this flag set to 
true, then it would include
+ *  resources from nifi-hadoop-nar, nifi-hadoop-libraries-nar, and stop before 
nifi-standard-services-api-nar.
+ *
+ *  Example #3 - HBaseClientService_1_1_2 does not have this flag set so it 
defaults to false, and therefore includes
+ *  only resources from the nifi-hbase-client-service-1_1_2-nar.
+ *
+ *  NOTE: When this annotation is used it is important to note that each added 
instance of the component will increase
  *  the overall memory footprint more than that of a component without this 
annotation.
  */
 @Documented
@@ -39,4 +48,7 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Inherited
 public @interface RequiresInstanceClassLoading {
+
+    boolean cloneAncestorResources() default false;
+
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-docs/src/main/asciidoc/developer-guide.adoc
----------------------------------------------------------------------
diff --git a/nifi-docs/src/main/asciidoc/developer-guide.adoc 
b/nifi-docs/src/main/asciidoc/developer-guide.adoc
index 429bd2c..7b2ba35 100644
--- a/nifi-docs/src/main/asciidoc/developer-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/developer-guide.adoc
@@ -2357,6 +2357,11 @@ component's NAR ClassLoader. When 
`@RequiresInstanceClassLoading` is not present
 instance ClassLoader simply has it's parent ClassLoader set to the NAR 
ClassLoader, rather than
 copying resources.
 
+The `@RequiresInstanceClassLoading` annotation also provides an optional flag 
`cloneAncestorResources'. If
+set to true, the instance ClassLoader will include ancestor resources up to 
the first ClassLoader containing a
+controller service API referenced by the component, or up to the Jetty NAR. If 
set to false, or not specified,
+only the resources from the component's NAR will be included.
+
 Because @RequiresInstanceClassLoading copies resources from the NAR 
ClassLoader for each instance of the
 component, use this capability judiciously. If ten instances of one component 
are created, all classes
 from the component's NAR ClassLoader are loaded into memory ten times. This 
could eventually increase the

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-framework-api/src/test/java/org/apache/nifi/bundle/BundleDetailsTest.java
----------------------------------------------------------------------
diff --git 
a/nifi-framework-api/src/test/java/org/apache/nifi/bundle/BundleDetailsTest.java
 
b/nifi-framework-api/src/test/java/org/apache/nifi/bundle/BundleDetailsTest.java
index e2475b6..62765dd 100644
--- 
a/nifi-framework-api/src/test/java/org/apache/nifi/bundle/BundleDetailsTest.java
+++ 
b/nifi-framework-api/src/test/java/org/apache/nifi/bundle/BundleDetailsTest.java
@@ -38,6 +38,8 @@ public class BundleDetailsTest {
         final String buildJdk = "JDK8";
         final String builtBy = "bbende";
 
+        final boolean cloneDuringInstanceClassLoading = true;
+
         final BundleDetails bundleDetails = new BundleDetails.Builder()
                 .workingDir(workingDirectory)
                 .coordinate(coordinate)

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
index 01467ab..0e02174 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
@@ -20,10 +20,6 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-nar-utils</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-api</artifactId>
         </dependency>
         <dependency>
@@ -36,6 +32,14 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-nar-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-framework-nar-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-utils</artifactId>
             <scope>test</scope>
         </dependency>

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/DocGenerator.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/DocGenerator.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/DocGenerator.java
index 9ae1705..dd99927 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/DocGenerator.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/main/java/org/apache/nifi/documentation/DocGenerator.java
@@ -22,8 +22,6 @@ import org.apache.nifi.components.ConfigurableComponent;
 import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.documentation.html.HtmlDocumentationWriter;
 import org.apache.nifi.documentation.html.HtmlProcessorDocumentationWriter;
-import org.apache.nifi.init.ConfigurableComponentInitializer;
-import org.apache.nifi.init.ConfigurableComponentInitializerFactory;
 import org.apache.nifi.nar.ExtensionManager;
 import org.apache.nifi.nar.ExtensionMapping;
 import org.apache.nifi.processor.Processor;
@@ -93,7 +91,7 @@ public class DocGenerator {
                 final Class<? extends ConfigurableComponent> componentClass = 
extensionClass.asSubclass(ConfigurableComponent.class);
                 try {
                     logger.debug("Documenting: " + componentClass);
-                    document(componentDirectory, componentClass);
+                    document(componentDirectory, componentClass, coordinate);
                 } catch (Exception e) {
                     logger.warn("Unable to document: " + componentClass, e);
                 }
@@ -113,12 +111,12 @@ public class DocGenerator {
      * @throws IOException ioe
      * @throws InitializationException ie
      */
-    private static void document(final File componentDocsDir, final Class<? 
extends ConfigurableComponent> componentClass)
+    private static void document(final File componentDocsDir, final Class<? 
extends ConfigurableComponent> componentClass, final BundleCoordinate 
bundleCoordinate)
             throws InstantiationException, IllegalAccessException, 
IOException, InitializationException {
 
-        final ConfigurableComponent component = componentClass.newInstance();
-        final ConfigurableComponentInitializer initializer = 
ConfigurableComponentInitializerFactory.createComponentInitializer(componentClass);
-        initializer.initialize(component);
+        // use temp components from ExtensionManager which should always be 
populated before doc generation
+        final String classType = componentClass.getCanonicalName();
+        final ConfigurableComponent component = 
ExtensionManager.getTempComponent(classType, bundleCoordinate);
 
         final DocumentationWriter writer = getDocumentWriter(componentClass);
 
@@ -130,8 +128,6 @@ public class DocGenerator {
         try (final OutputStream output = new BufferedOutputStream(new 
FileOutputStream(baseDocumentationFile))) {
             writer.write(component, output, 
hasAdditionalInfo(componentDocsDir));
         }
-
-        initializer.teardown(component);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/DocGeneratorTest.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/DocGeneratorTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/DocGeneratorTest.java
index b00ab8a..a165de1 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/DocGeneratorTest.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/DocGeneratorTest.java
@@ -23,6 +23,7 @@ import org.apache.nifi.nar.ExtensionManager;
 import org.apache.nifi.nar.ExtensionMapping;
 import org.apache.nifi.nar.NarClassLoaders;
 import org.apache.nifi.nar.NarUnpacker;
+import org.apache.nifi.nar.SystemBundle;
 import org.apache.nifi.util.NiFiProperties;
 import org.junit.Assert;
 import org.junit.Test;
@@ -47,7 +48,7 @@ public class DocGeneratorTest {
                 NiFiProperties.COMPONENT_DOCS_DIRECTORY,
                 temporaryFolder.getRoot().getAbsolutePath());
 
-        final Bundle systemBundle = 
ExtensionManager.createSystemBundle(properties);
+        final Bundle systemBundle = SystemBundle.create(properties);
         final ExtensionMapping mapping = NarUnpacker.unpackNars(properties, 
systemBundle);
 
         
NarClassLoaders.getInstance().init(properties.getFrameworkWorkingDirectory(), 
properties.getExtensionsWorkingDirectory());

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/integration/Node.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/integration/Node.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/integration/Node.java
index 20dbfe1..cace715 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/integration/Node.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/integration/Node.java
@@ -64,6 +64,7 @@ import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.io.socket.ServerSocketConfiguration;
 import org.apache.nifi.io.socket.SocketConfiguration;
 import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.SystemBundle;
 import org.apache.nifi.registry.VariableRegistry;
 import org.apache.nifi.reporting.BulletinRepository;
 import org.apache.nifi.reporting.Severity;
@@ -120,7 +121,7 @@ public class Node {
             }
         };
 
-        final Bundle systemBundle = 
ExtensionManager.createSystemBundle(properties);
+        final Bundle systemBundle = SystemBundle.create(properties);
         ExtensionManager.discoverExtensions(systemBundle, 
Collections.emptySet());
 
         revisionManager = Mockito.mock(RevisionManager.class);

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
index 78d895e..c3bb182 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
@@ -24,7 +24,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-nar-utils</artifactId>
+            <artifactId>nifi-framework-nar-utils</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractConfiguredComponent.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractConfiguredComponent.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractConfiguredComponent.java
index 345ce64..1156987 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractConfiguredComponent.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractConfiguredComponent.java
@@ -27,12 +27,10 @@ import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.controller.service.ControllerServiceNode;
 import org.apache.nifi.controller.service.ControllerServiceProvider;
 import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.nar.InstanceClassLoader;
 import org.apache.nifi.nar.NarCloseable;
 import org.apache.nifi.registry.VariableRegistry;
 import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
 
-import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -60,6 +58,7 @@ public abstract class AbstractConfiguredComponent implements 
ConfigurableCompone
     private final String componentType;
     private final String componentCanonicalClass;
     private final VariableRegistry variableRegistry;
+    private final ReloadComponent reloadComponent;
 
     private final AtomicBoolean isExtensionMissing;
 
@@ -69,7 +68,7 @@ public abstract class AbstractConfiguredComponent implements 
ConfigurableCompone
     public AbstractConfiguredComponent(final String id,
                                        final ValidationContextFactory 
validationContextFactory, final ControllerServiceProvider serviceProvider,
                                        final String componentType, final 
String componentCanonicalClass, final VariableRegistry variableRegistry,
-                                       final boolean isExtensionMissing) {
+                                       final ReloadComponent reloadComponent, 
final boolean isExtensionMissing) {
         this.id = id;
         this.validationContextFactory = validationContextFactory;
         this.serviceProvider = serviceProvider;
@@ -78,6 +77,7 @@ public abstract class AbstractConfiguredComponent implements 
ConfigurableCompone
         this.componentCanonicalClass = componentCanonicalClass;
         this.variableRegistry = variableRegistry;
         this.isExtensionMissing = new AtomicBoolean(isExtensionMissing);
+        this.reloadComponent = reloadComponent;
     }
 
     @Override
@@ -234,37 +234,28 @@ public abstract class AbstractConfiguredComponent 
implements ConfigurableCompone
     }
 
     /**
-     * Adds all of the modules identified by the given module paths to the 
InstanceClassLoader for this component.
+     * Triggers the reloading of the underlying component using a new 
InstanceClassLoader that includes the additional URL resources.
      *
      * @param modulePaths a list of module paths where each entry can be a 
comma-separated list of multiple module paths
      */
     private void processClasspathModifiers(final Set<String> modulePaths) {
         try {
+            // compute the URLs from all the modules paths
             final URL[] urls = 
ClassLoaderUtils.getURLsForClasspath(modulePaths, null, true);
 
-            if (getLogger().isDebugEnabled()) {
-                getLogger().debug("Adding {} resources to the classpath for 
{}", new Object[] {urls.length, name});
-                for (URL url : urls) {
-                    getLogger().debug(url.getFile());
+            // convert to a set of URLs
+            final Set<URL> additionalUrls = new LinkedHashSet<>();
+            if (urls != null) {
+                for (final URL url : urls) {
+                    additionalUrls.add(url);
                 }
             }
 
-            final ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
+            // reload the underlying component with a new InstanceClassLoader 
that includes the new URLs
+            reload(additionalUrls);
 
-            if (!(classLoader instanceof InstanceClassLoader)) {
-                // Really shouldn't happen, but if we somehow got here and 
don't have an InstanceClassLoader then log a warning and move on
-                final String classLoaderName = classLoader == null ? "null" : 
classLoader.getClass().getName();
-                if (getLogger().isWarnEnabled()) {
-                    getLogger().warn(String.format("Unable to modify the 
classpath for %s, expected InstanceClassLoader, but found %s", name, 
classLoaderName));
-                }
-                return;
-            }
-
-            final InstanceClassLoader instanceClassLoader = 
(InstanceClassLoader) classLoader;
-            instanceClassLoader.setInstanceResources(urls);
-        } catch (MalformedURLException e) {
-            // Shouldn't get here since we are suppressing errors
-            getLogger().warn("Error processing classpath resources", e);
+        } catch (Exception e) {
+            getLogger().warn("Error processing classpath resources for " + id 
+ ": " + e.getMessage(), e);
         }
     }
 
@@ -506,6 +497,10 @@ public abstract class AbstractConfiguredComponent 
implements ConfigurableCompone
         return this.variableRegistry;
     }
 
+    protected ReloadComponent getReloadComponent() {
+        return this.reloadComponent;
+    }
+
     @Override
     public void verifyCanUpdateBundle(final BundleCoordinate 
incomingCoordinate) throws IllegalArgumentException {
         final BundleCoordinate existingCoordinate = getBundleCoordinate();

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ConfiguredComponent.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ConfiguredComponent.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ConfiguredComponent.java
index 1c0b7c1..2ccb858 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ConfiguredComponent.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ConfiguredComponent.java
@@ -30,8 +30,10 @@ import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.logging.ComponentLog;
 
+import java.net.URL;
 import java.util.Collection;
 import java.util.Map;
+import java.util.Set;
 
 public interface ConfiguredComponent extends ComponentAuthorizable {
 
@@ -53,6 +55,8 @@ public interface ConfiguredComponent extends 
ComponentAuthorizable {
 
     boolean isValid();
 
+    void reload(Set<URL> additionalUrls) throws Exception;
+
     BundleCoordinate getBundleCoordinate();
 
     ConfigurableComponent getComponent();

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
index 8c78958..aac5e52 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
@@ -47,8 +47,8 @@ public abstract class ProcessorNode extends 
AbstractConfiguredComponent implemen
     public ProcessorNode(final String id,
                          final ValidationContextFactory 
validationContextFactory, final ControllerServiceProvider serviceProvider,
                          final String componentType, final String 
componentCanonicalClass, final VariableRegistry variableRegistry,
-                         final boolean isExtensionMissing) {
-        super(id, validationContextFactory, serviceProvider, componentType, 
componentCanonicalClass, variableRegistry, isExtensionMissing);
+                         final ReloadComponent reloadComponent, final boolean 
isExtensionMissing) {
+        super(id, validationContextFactory, serviceProvider, componentType, 
componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
         this.scheduledState = new AtomicReference<>(ScheduledState.STOPPED);
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ReloadComponent.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ReloadComponent.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ReloadComponent.java
new file mode 100644
index 0000000..6886ef6
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ReloadComponent.java
@@ -0,0 +1,69 @@
+/*
+ * 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.controller;
+
+import org.apache.nifi.bundle.BundleCoordinate;
+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 java.net.URL;
+import java.util.Set;
+
+/**
+ * A service used to change the type of an underlying component.
+ */
+public interface ReloadComponent {
+
+    /**
+     * Changes the underlying Processor held by the node to an instance of the 
new type.
+     *
+     * @param existingNode the node being being updated
+     * @param newType the fully qualified class name of the new type
+     * @param bundleCoordinate the bundle coordinate of the new type
+     * @param additionalUrls additional URLs to be added to the instance class 
loader of the new component
+     * @throws ControllerServiceInstantiationException if unable to create an 
instance of the new type
+     */
+    void reload(ProcessorNode existingNode, String newType, BundleCoordinate 
bundleCoordinate, Set<URL> additionalUrls)
+            throws ProcessorInstantiationException;
+
+    /**
+     * Changes the underlying ControllerService held by the node to an 
instance of the new type.
+     *
+     * @param existingNode the node being being updated
+     * @param newType the fully qualified class name of the new type
+     * @param bundleCoordinate the bundle coordinate of the new type
+     * @param additionalUrls additional URLs to be added to the instance class 
loader of the new component
+     * @throws ControllerServiceInstantiationException if unable to create an 
instance of the new type
+     */
+    void reload(ControllerServiceNode existingNode, String newType, 
BundleCoordinate bundleCoordinate, Set<URL> additionalUrls)
+            throws ControllerServiceInstantiationException;
+
+    /**
+     * Changes the underlying ReportingTask held by the node to an instance of 
the new type.
+     *
+     * @param existingNode the ReportingTaskNode being updated
+     * @param newType the fully qualified class name of the new type
+     * @param bundleCoordinate the bundle coordinate of the new type
+     * @param additionalUrls additional URLs to be added to the instance class 
loader of the new component
+     * @throws ReportingTaskInstantiationException if unable to create an 
instance of the new type
+     */
+    void reload(ReportingTaskNode existingNode, String newType, 
BundleCoordinate bundleCoordinate, Set<URL> additionalUrls)
+            throws ReportingTaskInstantiationException;
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/reporting/ReportingTaskProvider.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/reporting/ReportingTaskProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/reporting/ReportingTaskProvider.java
index b48f198..c826775 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/reporting/ReportingTaskProvider.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/reporting/ReportingTaskProvider.java
@@ -112,14 +112,4 @@ public interface ReportingTaskProvider {
      */
     void disableReportingTask(ReportingTaskNode reportingTask);
 
-    /**
-     * Changes the underlying ReportingTask held by the node to an instance of 
the new type.
-     *
-     * @param reportingTask the ReportingTaskNode being updated
-     * @param newType the fully qualified class name of the new type
-     * @param bundleCoordinate the bundle coordinate of the new type
-     * @throws ReportingTaskInstantiationException if unable to create an 
instance of the new type
-     */
-    void changeReportingTaskType(final ReportingTaskNode reportingTask, final 
String newType, final BundleCoordinate bundleCoordinate) throws 
ReportingTaskInstantiationException;
-
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceProvider.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceProvider.java
index d1111e6..4169281 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceProvider.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/service/ControllerServiceProvider.java
@@ -16,6 +16,7 @@
  */
 package org.apache.nifi.controller.service;
 
+import java.net.URL;
 import java.util.Collection;
 import java.util.Set;
 
@@ -38,10 +39,11 @@ public interface ControllerServiceProvider extends 
ControllerServiceLookup {
      * @param type of service
      * @param id of service
      * @param bundleCoordinate the coordinate of the bundle for the service
+     * @param additionalUrls optional additional URL resources to add to the 
class loader of the component
      * @param firstTimeAdded for service
      * @return the service node
      */
-    ControllerServiceNode createControllerService(String type, String id, 
BundleCoordinate bundleCoordinate, boolean firstTimeAdded);
+    ControllerServiceNode createControllerService(String type, String id, 
BundleCoordinate bundleCoordinate, Set<URL> additionalUrls, boolean 
firstTimeAdded);
 
     /**
      * @param id of the service

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
index 3e92219..54d777f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
@@ -41,19 +41,19 @@
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-expression-language</artifactId>
+            <artifactId>nifi-nar-utils</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-utils</artifactId>
+            <artifactId>nifi-expression-language</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-schema-utils</artifactId>
+            <artifactId>nifi-utils</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-nar-utils</artifactId>
+            <artifactId>nifi-schema-utils</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
index f312096..151640e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowController.java
@@ -221,6 +221,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -247,7 +248,7 @@ import java.util.stream.Collectors;
 import static java.util.Objects.requireNonNull;
 
 public class FlowController implements EventAccess, ControllerServiceProvider, 
ReportingTaskProvider,
-    QueueProvider, Authorizable, ProvenanceAuthorizableFactory, 
NodeTypeProvider, IdentifierLookup {
+    QueueProvider, Authorizable, ProvenanceAuthorizableFactory, 
NodeTypeProvider, IdentifierLookup, ReloadComponent {
 
     // default repository implementations
     public static final String DEFAULT_FLOWFILE_REPO_IMPLEMENTATION = 
"org.apache.nifi.controller.repository.WriteAheadFlowFileRepository";
@@ -1049,7 +1050,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
      * instantiated for any reason
      */
     public ProcessorNode createProcessor(final String type, String id, final 
BundleCoordinate coordinate, final boolean firstTimeAdded) throws 
ProcessorInstantiationException {
-        return createProcessor(type, id, coordinate, firstTimeAdded, true);
+        return createProcessor(type, id, coordinate, Collections.emptySet(), 
firstTimeAdded, true);
     }
 
     /**
@@ -1069,14 +1070,14 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
      * @throws ProcessorInstantiationException if the processor cannot be
      * instantiated for any reason
      */
-    public ProcessorNode createProcessor(final String type, String id, final 
BundleCoordinate coordinate, final boolean firstTimeAdded, final boolean 
registerLogObserver)
-            throws ProcessorInstantiationException {
+    public ProcessorNode createProcessor(final String type, String id, final 
BundleCoordinate coordinate, final Set<URL> additionalUrls,
+                                         final boolean firstTimeAdded, final 
boolean registerLogObserver) throws ProcessorInstantiationException {
         id = id.intern();
 
         boolean creationSuccessful;
         LoggableComponent<Processor> processor;
         try {
-            processor = instantiateProcessor(type, id, coordinate);
+            processor = instantiateProcessor(type, id, coordinate, 
additionalUrls);
             creationSuccessful = true;
         } catch (final ProcessorInstantiationException pie) {
             LOG.error("Could not create Processor of type " + type + " for ID 
" + id + "; creating \"Ghost\" implementation", pie);
@@ -1090,12 +1091,12 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         final ValidationContextFactory validationContextFactory = new 
StandardValidationContextFactory(controllerServiceProvider, variableRegistry);
         final ProcessorNode procNode;
         if (creationSuccessful) {
-            procNode = new StandardProcessorNode(processor, id, 
validationContextFactory, processScheduler, controllerServiceProvider, 
nifiProperties, variableRegistry);
+            procNode = new StandardProcessorNode(processor, id, 
validationContextFactory, processScheduler, controllerServiceProvider, 
nifiProperties, variableRegistry, this);
         } else {
             final String simpleClassName = type.contains(".") ? 
StringUtils.substringAfterLast(type, ".") : type;
             final String componentType = "(Missing) " + simpleClassName;
             procNode = new StandardProcessorNode(
-                    processor, id, validationContextFactory, processScheduler, 
controllerServiceProvider, componentType, type, nifiProperties, 
variableRegistry, true);
+                    processor, id, validationContextFactory, processScheduler, 
controllerServiceProvider, componentType, type, nifiProperties, 
variableRegistry, this, true);
         }
 
         final LogRepository logRepository = 
LogRepositoryFactory.getRepository(id);
@@ -1153,7 +1154,9 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         return procNode;
     }
 
-    private LoggableComponent<Processor> instantiateProcessor(final String 
type, final String identifier, final BundleCoordinate bundleCoordinate) throws 
ProcessorInstantiationException {
+    private LoggableComponent<Processor> instantiateProcessor(final String 
type, final String identifier, final BundleCoordinate bundleCoordinate, final 
Set<URL> additionalUrls)
+            throws ProcessorInstantiationException {
+
         final Bundle processorBundle = 
ExtensionManager.getBundle(bundleCoordinate);
         if (processorBundle == null) {
             throw new ProcessorInstantiationException("Unable to find bundle 
for coordinate " + bundleCoordinate.getCoordinate());
@@ -1161,9 +1164,9 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
 
         final ClassLoader ctxClassLoader = 
Thread.currentThread().getContextClassLoader();
         try {
-            final ClassLoader detectedClassLoaderForType = 
ExtensionManager.createInstanceClassLoader(type, identifier, processorBundle);
-            final Class<?> rawClass = Class.forName(type, true, 
processorBundle.getClassLoader());
-            
Thread.currentThread().setContextClassLoader(detectedClassLoaderForType);
+            final ClassLoader detectedClassLoaderForInstance = 
ExtensionManager.createInstanceClassLoader(type, identifier, processorBundle, 
additionalUrls);
+            final Class<?> rawClass = Class.forName(type, true, 
detectedClassLoaderForInstance);
+            
Thread.currentThread().setContextClassLoader(detectedClassLoaderForInstance);
 
             final Class<? extends Processor> processorClass = 
rawClass.asSubclass(Processor.class);
             final Processor processor = processorClass.newInstance();
@@ -1184,7 +1187,9 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         }
     }
 
-    public void changeProcessorType(final ProcessorNode existingNode, final 
String newType, final BundleCoordinate bundleCoordinate) throws 
ProcessorInstantiationException {
+    @Override
+    public void reload(final ProcessorNode existingNode, final String newType, 
final BundleCoordinate bundleCoordinate, final Set<URL> additionalUrls)
+            throws ProcessorInstantiationException {
         if (existingNode == null) {
             throw new IllegalStateException("Existing ProcessorNode cannot be 
null");
         }
@@ -1197,13 +1202,15 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
 
         // create a new node with firstTimeAdded as true so lifecycle methods 
get fired
         // attempt the creation to make sure it works before firing the 
OnRemoved methods below
-        final ProcessorNode newNode = createProcessor(newType, id, 
bundleCoordinate, true, false);
+        final ProcessorNode newNode = createProcessor(newType, id, 
bundleCoordinate, additionalUrls, true, false);
 
         // call OnRemoved for the existing processor using the previous 
instance class loader
         try (final NarCloseable x = 
NarCloseable.withComponentNarLoader(existingInstanceClassLoader)) {
             final StandardProcessContext processContext = new 
StandardProcessContext(
                     existingNode, controllerServiceProvider, encryptor, 
getStateManagerProvider().getStateManager(id), variableRegistry);
             
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnRemoved.class, 
existingNode.getProcessor(), processContext);
+        } finally {
+            ExtensionManager.closeURLClassLoader(id, 
existingInstanceClassLoader);
         }
 
         // set the new processor in the existing node
@@ -1701,7 +1708,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
             //
             for (final ControllerServiceDTO controllerServiceDTO : 
dto.getControllerServices()) {
                 final BundleCoordinate bundleCoordinate = 
BundleUtils.getBundle(controllerServiceDTO.getType(), 
controllerServiceDTO.getBundle());
-                final ControllerServiceNode serviceNode = 
createControllerService(controllerServiceDTO.getType(), 
controllerServiceDTO.getId(), bundleCoordinate, true);
+                final ControllerServiceNode serviceNode = 
createControllerService(controllerServiceDTO.getType(), 
controllerServiceDTO.getId(), bundleCoordinate, Collections.emptySet(),true);
 
                 
serviceNode.setAnnotationData(controllerServiceDTO.getAnnotationData());
                 serviceNode.setComments(controllerServiceDTO.getComments());
@@ -2942,12 +2949,13 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
     }
 
     @Override
-    public ReportingTaskNode createReportingTask(final String type, final 
String id, final BundleCoordinate bundleCoordinate,final boolean 
firstTimeAdded) throws ReportingTaskInstantiationException {
-        return createReportingTask(type, id, bundleCoordinate, firstTimeAdded, 
true);
+    public ReportingTaskNode createReportingTask(final String type, final 
String id, final BundleCoordinate bundleCoordinate,final boolean firstTimeAdded)
+            throws ReportingTaskInstantiationException {
+        return createReportingTask(type, id, bundleCoordinate, 
Collections.emptySet(), firstTimeAdded, true);
     }
 
-    public ReportingTaskNode createReportingTask(final String type, final 
String id, final BundleCoordinate bundleCoordinate, final boolean 
firstTimeAdded, final boolean register)
-            throws ReportingTaskInstantiationException {
+    public ReportingTaskNode createReportingTask(final String type, final 
String id, final BundleCoordinate bundleCoordinate, final Set<URL> 
additionalUrls,
+                                                 final boolean firstTimeAdded, 
final boolean register) throws ReportingTaskInstantiationException {
         if (type == null || id == null || bundleCoordinate == null) {
             throw new NullPointerException();
         }
@@ -2955,7 +2963,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         LoggableComponent<ReportingTask> task = null;
         boolean creationSuccessful = true;
         try {
-            task = instantiateReportingTask(type, id, bundleCoordinate);
+            task = instantiateReportingTask(type, id, bundleCoordinate, 
additionalUrls);
         } catch (final Exception e) {
             LOG.error("Could not create Reporting Task of type " + type + " 
for ID " + id + "; creating \"Ghost\" implementation", e);
             final GhostReportingTask ghostTask = new GhostReportingTask();
@@ -2968,12 +2976,12 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         final ValidationContextFactory validationContextFactory = new 
StandardValidationContextFactory(controllerServiceProvider, variableRegistry);
         final ReportingTaskNode taskNode;
         if (creationSuccessful) {
-            taskNode = new StandardReportingTaskNode(task, id, this, 
processScheduler, validationContextFactory, variableRegistry);
+            taskNode = new StandardReportingTaskNode(task, id, this, 
processScheduler, validationContextFactory, variableRegistry, this);
         } else {
             final String simpleClassName = type.contains(".") ? 
StringUtils.substringAfterLast(type, ".") : type;
             final String componentType = "(Missing) " + simpleClassName;
 
-            taskNode = new StandardReportingTaskNode(task, id, this, 
processScheduler, validationContextFactory, componentType, type, 
variableRegistry, true);
+            taskNode = new StandardReportingTaskNode(task, id, this, 
processScheduler, validationContextFactory, componentType, type, 
variableRegistry, this, true);
         }
 
         
taskNode.setName(taskNode.getReportingTask().getClass().getSimpleName());
@@ -3008,7 +3016,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         return taskNode;
     }
 
-    private LoggableComponent<ReportingTask> instantiateReportingTask(final 
String type, final String id, final BundleCoordinate bundleCoordinate)
+    private LoggableComponent<ReportingTask> instantiateReportingTask(final 
String type, final String id, final BundleCoordinate bundleCoordinate, final 
Set<URL> additionalUrls)
             throws ReportingTaskInstantiationException {
 
         final ClassLoader ctxClassLoader = 
Thread.currentThread().getContextClassLoader();
@@ -3018,7 +3026,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
                 throw new IllegalStateException("Unable to find bundle for 
coordinate " + bundleCoordinate.getCoordinate());
             }
 
-            final ClassLoader detectedClassLoader = 
ExtensionManager.createInstanceClassLoader(type, id, reportingTaskBundle);
+            final ClassLoader detectedClassLoader = 
ExtensionManager.createInstanceClassLoader(type, id, reportingTaskBundle, 
additionalUrls);
             final Class<?> rawClass = Class.forName(type, false, 
detectedClassLoader);
             Thread.currentThread().setContextClassLoader(detectedClassLoader);
 
@@ -3039,7 +3047,8 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
     }
 
     @Override
-    public void changeReportingTaskType(final ReportingTaskNode existingNode, 
final String newType, final BundleCoordinate bundleCoordinate) throws 
ReportingTaskInstantiationException {
+    public void reload(final ReportingTaskNode existingNode, final String 
newType, final BundleCoordinate bundleCoordinate, final Set<URL> additionalUrls)
+            throws ReportingTaskInstantiationException {
         if (existingNode == null) {
             throw new IllegalStateException("Existing ReportingTaskNode cannot 
be null");
         }
@@ -3052,11 +3061,13 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
 
         // set firstTimeAdded to true so lifecycle annotations get fired, but 
don't register this node
         // attempt the creation to make sure it works before firing the 
OnRemoved methods below
-        final ReportingTaskNode newNode = createReportingTask(newType, id, 
bundleCoordinate, true, false);
+        final ReportingTaskNode newNode = createReportingTask(newType, id, 
bundleCoordinate, additionalUrls, true, false);
 
         // call OnRemoved for the existing reporting task using the previous 
instance class loader
         try (final NarCloseable x = 
NarCloseable.withComponentNarLoader(existingInstanceClassLoader)) {
             
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnRemoved.class, 
existingNode.getReportingTask(), existingNode.getConfigurationContext());
+        } finally {
+            ExtensionManager.closeURLClassLoader(id, 
existingInstanceClassLoader);
         }
 
         // set the new reporting task into the existing node
@@ -3117,7 +3128,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         }
 
         reportingTasks.remove(reportingTaskNode.getIdentifier());
-        
ExtensionManager.removeInstanceClassLoaderIfExists(reportingTaskNode.getIdentifier());
+        
ExtensionManager.removeInstanceClassLoader(reportingTaskNode.getIdentifier());
     }
 
     @Override
@@ -3126,8 +3137,8 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
     }
 
     @Override
-    public ControllerServiceNode createControllerService(final String type, 
final String id, final BundleCoordinate bundleCoordinate, final boolean 
firstTimeAdded) {
-        final ControllerServiceNode serviceNode = 
controllerServiceProvider.createControllerService(type, id, bundleCoordinate, 
firstTimeAdded);
+    public ControllerServiceNode createControllerService(final String type, 
final String id, final BundleCoordinate bundleCoordinate, final Set<URL> 
additionalUrls, final boolean firstTimeAdded) {
+        final ControllerServiceNode serviceNode = 
controllerServiceProvider.createControllerService(type, id, bundleCoordinate, 
additionalUrls, firstTimeAdded);
 
         // Register log observer to provide bulletins when reporting task logs 
anything at WARN level or above
         final LogRepository logRepository = 
LogRepositoryFactory.getRepository(id);
@@ -3145,7 +3156,8 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         return serviceNode;
     }
 
-    public void changeControllerServiceType(final ControllerServiceNode 
existingNode, final String newType, final BundleCoordinate bundleCoordinate)
+    @Override
+    public void reload(final ControllerServiceNode existingNode, final String 
newType, final BundleCoordinate bundleCoordinate, final Set<URL> additionalUrls)
             throws ControllerServiceInstantiationException {
         if (existingNode == null) {
             throw new IllegalStateException("Existing ControllerServiceNode 
cannot be null");
@@ -3159,12 +3171,14 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
 
         // create a new node with firstTimeAdded as true so lifecycle methods 
get called
         // attempt the creation to make sure it works before firing the 
OnRemoved methods below
-        final ControllerServiceNode newNode = 
controllerServiceProvider.createControllerService(newType, id, 
bundleCoordinate, true);
+        final ControllerServiceNode newNode = 
controllerServiceProvider.createControllerService(newType, id, 
bundleCoordinate, additionalUrls, true);
 
         // call OnRemoved for the existing service using the previous instance 
class loader
         try (final NarCloseable x = 
NarCloseable.withComponentNarLoader(existingInstanceClassLoader)) {
             final ConfigurationContext configurationContext = new 
StandardConfigurationContext(existingNode, controllerServiceProvider, null, 
variableRegistry);
             
ReflectionUtils.quietlyInvokeMethodsWithAnnotation(OnRemoved.class, 
existingNode.getControllerServiceImplementation(), configurationContext);
+        } finally {
+            ExtensionManager.closeURLClassLoader(id, 
existingInstanceClassLoader);
         }
 
         // take the invocation handler that was created for new proxy and is 
set to look at the new node,
@@ -3313,7 +3327,7 @@ public class FlowController implements EventAccess, 
ControllerServiceProvider, R
         rootControllerServices.remove(service.getIdentifier());
         getStateManagerProvider().onComponentRemoved(service.getIdentifier());
 
-        
ExtensionManager.removeInstanceClassLoaderIfExists(service.getIdentifier());
+        ExtensionManager.removeInstanceClassLoader(service.getIdentifier());
 
         LOG.info("{} removed from Flow Controller", service, this);
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
index afc94d8..281c695 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
@@ -40,6 +40,7 @@ import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Position;
+import org.apache.nifi.controller.exception.ProcessorInstantiationException;
 import org.apache.nifi.controller.scheduling.ScheduleState;
 import org.apache.nifi.controller.scheduling.SchedulingAgent;
 import org.apache.nifi.controller.service.ControllerServiceNode;
@@ -66,6 +67,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.util.Assert;
 
 import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -132,19 +134,19 @@ public class StandardProcessorNode extends ProcessorNode 
implements Connectable
     public StandardProcessorNode(final LoggableComponent<Processor> processor, 
final String uuid,
                                  final ValidationContextFactory 
validationContextFactory, final ProcessScheduler scheduler,
                                  final ControllerServiceProvider 
controllerServiceProvider, final NiFiProperties nifiProperties,
-                                 final VariableRegistry variableRegistry) {
+                                 final VariableRegistry variableRegistry, 
final ReloadComponent reloadComponent) {
 
         this(processor, uuid, validationContextFactory, scheduler, 
controllerServiceProvider,
-            processor.getComponent().getClass().getSimpleName(), 
processor.getComponent().getClass().getCanonicalName(), nifiProperties, 
variableRegistry, false);
+            processor.getComponent().getClass().getSimpleName(), 
processor.getComponent().getClass().getCanonicalName(), nifiProperties, 
variableRegistry, reloadComponent, false);
     }
 
     public StandardProcessorNode(final LoggableComponent<Processor> processor, 
final String uuid,
                                  final ValidationContextFactory 
validationContextFactory, final ProcessScheduler scheduler,
                                  final ControllerServiceProvider 
controllerServiceProvider,
                                  final String componentType, final String 
componentCanonicalClass, final NiFiProperties nifiProperties,
-                                 final VariableRegistry variableRegistry, 
final boolean isExtensionMissing) {
+                                 final VariableRegistry variableRegistry, 
final ReloadComponent reloadComponent, final boolean isExtensionMissing) {
 
-        super(uuid, validationContextFactory, controllerServiceProvider, 
componentType, componentCanonicalClass, variableRegistry, isExtensionMissing);
+        super(uuid, validationContextFactory, controllerServiceProvider, 
componentType, componentCanonicalClass, variableRegistry, reloadComponent, 
isExtensionMissing);
 
         final ProcessorDetails processorDetails = new 
ProcessorDetails(processor);
         this.processorRef = new AtomicReference<>(processorDetails);
@@ -867,6 +869,15 @@ public class StandardProcessorNode extends ProcessorNode 
implements Connectable
         processorRef.set(processorDetails);
     }
 
+    @Override
+    public synchronized void reload(final Set<URL> additionalUrls) throws 
ProcessorInstantiationException {
+        if (isRunning()) {
+            throw new IllegalStateException("Cannot reload Processor while the 
Processor is running");
+        }
+
+        getReloadComponent().reload(this, getCanonicalClassName(), 
getBundleCoordinate(), additionalUrls);
+    }
+
     /**
      * @return the Set of destination processors for all relationships 
excluding
      *         any destinations that are this processor itself (self-loops)

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/AbstractReportingTaskNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/AbstractReportingTaskNode.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/AbstractReportingTaskNode.java
index aeb1d07..1d5d7b9 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/AbstractReportingTaskNode.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/AbstractReportingTaskNode.java
@@ -21,6 +21,7 @@ import org.apache.nifi.bundle.BundleCoordinate;
 import org.apache.nifi.components.ConfigurableComponent;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.controller.AbstractConfiguredComponent;
+import org.apache.nifi.controller.ReloadComponent;
 import org.apache.nifi.controller.ConfigurationContext;
 import org.apache.nifi.controller.ControllerServiceLookup;
 import org.apache.nifi.controller.LoggableComponent;
@@ -37,6 +38,7 @@ import org.apache.nifi.reporting.ReportingTask;
 import org.apache.nifi.scheduling.SchedulingStrategy;
 import org.apache.nifi.util.FormatUtils;
 
+import java.net.URL;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -64,19 +66,21 @@ public abstract class AbstractReportingTaskNode extends 
AbstractConfiguredCompon
 
     public AbstractReportingTaskNode(final LoggableComponent<ReportingTask> 
reportingTask, final String id,
                                      final ControllerServiceProvider 
controllerServiceProvider, final ProcessScheduler processScheduler,
-                                     final ValidationContextFactory 
validationContextFactory, final VariableRegistry variableRegistry) {
+                                     final ValidationContextFactory 
validationContextFactory, final VariableRegistry variableRegistry,
+                                     final ReloadComponent reloadComponent) {
 
         this(reportingTask, id, controllerServiceProvider, processScheduler, 
validationContextFactory,
-            reportingTask.getComponent().getClass().getSimpleName(), 
reportingTask.getComponent().getClass().getCanonicalName(),variableRegistry, 
false);
+                reportingTask.getComponent().getClass().getSimpleName(), 
reportingTask.getComponent().getClass().getCanonicalName(),
+                variableRegistry, reloadComponent, false);
     }
 
 
     public AbstractReportingTaskNode(final LoggableComponent<ReportingTask> 
reportingTask, final String id, final ControllerServiceProvider 
controllerServiceProvider,
                                      final ProcessScheduler processScheduler, 
final ValidationContextFactory validationContextFactory,
                                      final String componentType, final String 
componentCanonicalClass, final VariableRegistry variableRegistry,
-                                     final boolean isExtensionMissing) {
+                                     final ReloadComponent reloadComponent, 
final boolean isExtensionMissing) {
 
-        super(id, validationContextFactory, controllerServiceProvider, 
componentType, componentCanonicalClass, variableRegistry, isExtensionMissing);
+        super(id, validationContextFactory, controllerServiceProvider, 
componentType, componentCanonicalClass, variableRegistry, reloadComponent, 
isExtensionMissing);
         this.reportingTaskRef = new AtomicReference<>(new 
ReportingTaskDetails(reportingTask));
         this.processScheduler = processScheduler;
         this.serviceLookup = controllerServiceProvider;
@@ -153,6 +157,15 @@ public abstract class AbstractReportingTaskNode extends 
AbstractConfiguredCompon
     }
 
     @Override
+    public void reload(final Set<URL> additionalUrls) throws 
ReportingTaskInstantiationException {
+        if (isRunning()) {
+            throw new IllegalStateException("Cannot reload Reporting Task 
while Reporting Task is running");
+        }
+
+        getReloadComponent().reload(this, getCanonicalClassName(), 
getBundleCoordinate(), additionalUrls);
+    }
+
+    @Override
     public boolean isRunning() {
         return processScheduler.isScheduled(this) || 
processScheduler.getActiveThreadCount(this) > 0;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
index edf1b67..3dbfce1 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingTaskNode.java
@@ -21,6 +21,7 @@ import org.apache.nifi.authorization.Resource;
 import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.controller.ReloadComponent;
 import org.apache.nifi.controller.FlowController;
 import org.apache.nifi.controller.LoggableComponent;
 import org.apache.nifi.controller.ProcessScheduler;
@@ -36,16 +37,17 @@ public class StandardReportingTaskNode extends 
AbstractReportingTaskNode impleme
 
     public StandardReportingTaskNode(final LoggableComponent<ReportingTask> 
reportingTask, final String id, final FlowController controller,
                                      final ProcessScheduler processScheduler, 
final ValidationContextFactory validationContextFactory,
-                                     final VariableRegistry variableRegistry) {
-        super(reportingTask, id, controller, processScheduler, 
validationContextFactory, variableRegistry);
+                                     final VariableRegistry variableRegistry, 
final ReloadComponent reloadComponent) {
+        super(reportingTask, id, controller, processScheduler, 
validationContextFactory, variableRegistry, reloadComponent);
         this.flowController = controller;
     }
 
     public StandardReportingTaskNode(final LoggableComponent<ReportingTask> 
reportingTask, final String id, final FlowController controller,
                                      final ProcessScheduler processScheduler, 
final ValidationContextFactory validationContextFactory,
                                      final String componentType, final String 
canonicalClassName, final VariableRegistry variableRegistry,
-                                     final boolean isExtensionMissing) {
-        super(reportingTask, id, controller, processScheduler, 
validationContextFactory, componentType, canonicalClassName,variableRegistry, 
isExtensionMissing);
+                                     final ReloadComponent reloadComponent, 
final boolean isExtensionMissing) {
+        super(reportingTask, id, controller, processScheduler, 
validationContextFactory, componentType, canonicalClassName,
+                variableRegistry, reloadComponent, isExtensionMissing);
         this.flowController = controller;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
index 520d3fb..3faffd7 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
@@ -43,6 +43,7 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -163,7 +164,8 @@ public class ControllerServiceLoader {
         // create a new id for the clone seeded from the original id so that 
it is consistent in a cluster
         final UUID id = 
UUID.nameUUIDFromBytes(controllerService.getIdentifier().getBytes(StandardCharsets.UTF_8));
 
-        final ControllerServiceNode clone = 
provider.createControllerService(controllerService.getCanonicalClassName(), 
id.toString(), controllerService.getBundleCoordinate(), false);
+        final ControllerServiceNode clone = 
provider.createControllerService(controllerService.getCanonicalClassName(), 
id.toString(),
+                controllerService.getBundleCoordinate(), 
Collections.emptySet(), false);
         clone.setName(controllerService.getName());
         clone.setComments(controllerService.getComments());
 
@@ -193,7 +195,7 @@ public class ControllerServiceLoader {
             }
         }
 
-        final ControllerServiceNode node = 
provider.createControllerService(dto.getType(), dto.getId(), coordinate, false);
+        final ControllerServiceNode node = 
provider.createControllerService(dto.getType(), dto.getId(), coordinate, 
Collections.emptySet(), false);
         node.setName(dto.getName());
         node.setComments(dto.getComments());
         return node;

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
index a543040..4ee65ec 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceNode.java
@@ -29,11 +29,13 @@ import org.apache.nifi.components.ConfigurableComponent;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.controller.AbstractConfiguredComponent;
+import org.apache.nifi.controller.ReloadComponent;
 import org.apache.nifi.controller.ConfigurationContext;
 import org.apache.nifi.controller.ConfiguredComponent;
 import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.controller.LoggableComponent;
 import org.apache.nifi.controller.ValidationContextFactory;
+import 
org.apache.nifi.controller.exception.ControllerServiceInstantiationException;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.logging.ComponentLog;
 import org.apache.nifi.nar.NarCloseable;
@@ -44,6 +46,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -79,18 +82,18 @@ public class StandardControllerServiceNode extends 
AbstractConfiguredComponent i
 
     public StandardControllerServiceNode(final 
LoggableComponent<ControllerService> implementation, final 
LoggableComponent<ControllerService> proxiedControllerService,
                                          final 
ControllerServiceInvocationHandler invocationHandler, final String id, final 
ValidationContextFactory validationContextFactory,
-                                         final ControllerServiceProvider 
serviceProvider, final VariableRegistry variableRegistry) {
+                                         final ControllerServiceProvider 
serviceProvider, final VariableRegistry variableRegistry, final ReloadComponent 
reloadComponent) {
 
         this(implementation, proxiedControllerService, invocationHandler, id, 
validationContextFactory, serviceProvider,
-            implementation.getComponent().getClass().getSimpleName(), 
implementation.getComponent().getClass().getCanonicalName(), variableRegistry, 
false);
+            implementation.getComponent().getClass().getSimpleName(), 
implementation.getComponent().getClass().getCanonicalName(), variableRegistry, 
reloadComponent, false);
     }
 
     public StandardControllerServiceNode(final 
LoggableComponent<ControllerService> implementation, final 
LoggableComponent<ControllerService> proxiedControllerService,
                                          final 
ControllerServiceInvocationHandler invocationHandler, final String id, final 
ValidationContextFactory validationContextFactory,
                                          final ControllerServiceProvider 
serviceProvider, final String componentType, final String 
componentCanonicalClass,
-                                         final VariableRegistry 
variableRegistry, final boolean isExtensionMissing) {
+                                         final VariableRegistry 
variableRegistry, final ReloadComponent reloadComponent, final boolean 
isExtensionMissing) {
 
-        super(id, validationContextFactory, serviceProvider, componentType, 
componentCanonicalClass, variableRegistry, isExtensionMissing);
+        super(id, validationContextFactory, serviceProvider, componentType, 
componentCanonicalClass, variableRegistry, reloadComponent, isExtensionMissing);
         this.serviceProvider = serviceProvider;
         this.active = new AtomicBoolean();
         setControllerServiceAndProxy(implementation, proxiedControllerService, 
invocationHandler);
@@ -172,6 +175,17 @@ public class StandardControllerServiceNode extends 
AbstractConfiguredComponent i
     }
 
     @Override
+    public void reload(final Set<URL> additionalUrls) throws 
ControllerServiceInstantiationException {
+        synchronized (this.active) {
+            if (isActive()) {
+                throw new IllegalStateException("Cannot reload Controller 
Service while service is active");
+            }
+
+            getReloadComponent().reload(this, getCanonicalClassName(), 
getBundleCoordinate(), additionalUrls);
+        }
+    }
+
+    @Override
     public ProcessGroup getProcessGroup() {
         readLock.lock();
         try {

http://git-wip-us.apache.org/repos/asf/nifi/blob/556f309d/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceProvider.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceProvider.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceProvider.java
index cadc8e7..ab70e75 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceProvider.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardControllerServiceProvider.java
@@ -53,6 +53,7 @@ import org.slf4j.LoggerFactory;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -91,7 +92,7 @@ public class StandardControllerServiceProvider implements 
ControllerServiceProvi
     }
 
     @Override
-    public ControllerServiceNode createControllerService(final String type, 
final String id, final BundleCoordinate bundleCoordinate, final boolean 
firstTimeAdded) {
+    public ControllerServiceNode createControllerService(final String type, 
final String id, final BundleCoordinate bundleCoordinate, final Set<URL> 
additionalUrls, final boolean firstTimeAdded) {
         if (type == null || id == null || bundleCoordinate == null) {
             throw new NullPointerException();
         }
@@ -106,7 +107,7 @@ public class StandardControllerServiceProvider implements 
ControllerServiceProvi
                     throw new ControllerServiceInstantiationException("Unable 
to find bundle for coordinate " + bundleCoordinate.getCoordinate());
                 }
 
-                cl = ExtensionManager.createInstanceClassLoader(type, id, 
csBundle);
+                cl = ExtensionManager.createInstanceClassLoader(type, id, 
csBundle, additionalUrls);
                 Thread.currentThread().setContextClassLoader(cl);
                 rawClass = Class.forName(type, false, cl);
             } catch (final Exception e) {
@@ -141,7 +142,7 @@ public class StandardControllerServiceProvider implements 
ControllerServiceProvi
             final LoggableComponent<ControllerService> 
proxiedLoggableComponent = new LoggableComponent<>(proxiedService, 
bundleCoordinate, serviceLogger);
 
             final ControllerServiceNode serviceNode = new 
StandardControllerServiceNode(originalLoggableComponent, 
proxiedLoggableComponent, invocationHandler,
-                    id, validationContextFactory, this, variableRegistry);
+                    id, validationContextFactory, this, variableRegistry, 
flowController);
             serviceNode.setName(rawClass.getSimpleName());
 
             invocationHandler.setServiceNode(serviceNode);
@@ -217,7 +218,7 @@ public class StandardControllerServiceProvider implements 
ControllerServiceProvi
         final LoggableComponent<ControllerService> 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

Reply via email to