You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ex...@apache.org on 2023/10/11 18:53:21 UTC

[nifi] branch main updated: NIFI-11772 Removed flow.xml.gz support

This is an automated email from the ASF dual-hosted git repository.

exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 3f13604c36 NIFI-11772 Removed flow.xml.gz support
3f13604c36 is described below

commit 3f13604c365ac9205b9a8dc2782bf13a08b76b26
Author: Bence Simon <bs...@apache.org>
AuthorDate: Wed Aug 30 13:55:40 2023 +0200

    NIFI-11772 Removed flow.xml.gz support
    
    - Created NIFI-12203 to evaluate issues with flow comparison surfaced in JoinClusterWithDifferentFlow
    
    This closes #7661
    
    Signed-off-by: David Handermann <ex...@apache.org>
---
 .../service/MiNiFiConfigurationChangeListener.java |   10 +-
 .../service/MiNiFiPropertiesGenerator.java         |    4 +-
 .../resources/MINIFI-216/nifi.properties.before    |    2 +-
 .../resources/MINIFI-245/nifi.properties.before    |    2 +-
 .../src/test/resources/MINIFI-277/nifi.properties  |    2 +-
 .../resources/NIFI-8753/nifi.properties.before     |    2 +-
 .../src/main/markdown/System_Admin_Guide.md        |    2 +-
 .../src/test/resources/conf/nifi.properties        |    2 +-
 .../apache/nifi/minifi/c2/C2NifiClientService.java |    4 +-
 .../apache/nifi/minifi/StandardMiNiFiServer.java   |    6 -
 .../src/test/resources/nifi.properties.dns-sans    |    2 +-
 .../src/test/resources/nifi.properties.ip-sans     |    2 +-
 .../resources/nifi.properties.keystore-password    |    2 +-
 .../src/test/resources/nifi.properties.no-https    |    2 +-
 .../resources/nifi.properties.no-keystore-types    |    2 +-
 .../test/resources/nifi.properties.no-keystores    |    2 +-
 .../test/resources/nifi.properties.only-keystore   |    2 +-
 .../test/resources/nifi.properties.only-truststore |    2 +-
 .../test/resources/nifi.properties.stores-exist    |    2 +-
 .../src/test/resources/nifi.properties.success     |    2 +-
 .../resources/nifi.properties.truststore-password  |    2 +-
 .../nifi/flow/encryptor/StandardFlowEncryptor.java |   55 -
 .../nifi/flow/encryptor/XmlFlowEncryptor.java      |   80 -
 .../encryptor/command/FlowEncryptorCommand.java    |   17 +-
 ...cryptorTest.java => JsonFlowEncryptorTest.java} |   89 +-
 .../command/FlowEncryptorCommandTest.java          |   13 +-
 .../src/test/resources/blank.nifi.properties       |    1 -
 .../src/test/resources/populated.nifi.properties   |    1 -
 .../java/org/apache/nifi/util/NiFiProperties.java  |   17 -
 .../NiFiProperties/conf/nifi.blank.properties      |    2 +-
 .../NiFiProperties/conf/nifi.missing.properties    |    2 +-
 .../resources/NiFiProperties/conf/nifi.properties  |    2 +-
 .../src/main/asciidoc/administration-guide.adoc    |   16 +-
 .../java/org/apache/nifi/web/api/dto/PortDTO.java  |   31 -
 .../authorization/FileAccessPolicyProvider.java    |  170 +-
 .../apache/nifi/authorization/FileAuthorizer.java  |    8 -
 .../nifi/authorization/FileUserGroupProvider.java  |   60 -
 .../FileAccessPolicyProviderTest.java              |  283 +--
 .../nifi/authorization/FileAuthorizerTest.java     |  316 +---
 .../authorization/FileUserGroupProviderTest.java   |  141 --
 .../src/test/resources/flow-no-ports.json.gz       |  Bin 0 -> 1176 bytes
 .../src/test/resources/flow-no-ports.xml.gz        |  Bin 730 -> 0 bytes
 .../src/test/resources/flow-with-dns.json.gz       |  Bin 0 -> 1176 bytes
 .../src/test/resources/flow-with-dns.xml.gz        |  Bin 784 -> 0 bytes
 .../src/test/resources/flow.json.gz                |  Bin 0 -> 1176 bytes
 .../src/test/resources/flow.xml.gz                 |  Bin 730 -> 0 bytes
 .../nifi/cluster/protocol/StandardDataFlow.java    |   10 +-
 .../coordination/flow/PopularVoteFlowElection.java |    4 +-
 .../flow/TestPopularVoteFlowElection.java          |   14 +-
 .../resources/conf/auto-generated-empty-flow.json  |    1 +
 .../resources/conf/auto-generated-empty-flow.xml   |   27 -
 .../resources/conf/controller-service-flow.json    |   64 +
 .../resources/conf/controller-service-flow.xml     |   37 -
 .../test/resources/conf/different-empty-flow.json  |    1 +
 .../test/resources/conf/different-empty-flow.xml   |   27 -
 .../src/test/resources/conf/empty-flow.json        |    1 +
 .../src/test/resources/conf/empty-flow.xml         |   27 -
 .../src/test/resources/conf/nifi.properties        |    2 +-
 .../src/test/resources/conf/non-empty-flow.json    |    1 +
 .../src/test/resources/conf/non-empty-flow.xml     |   26 -
 .../test/resources/conf/reporting-task-flow.json   |    1 +
 .../test/resources/conf/reporting-task-flow.xml    |   54 -
 .../StandardVersionedComponentSynchronizer.java    |    2 +-
 .../src/test/resources/conf/nifi.properties        |    2 +-
 .../org/apache/nifi/cluster/protocol/DataFlow.java |    5 -
 .../java/org/apache/nifi/remote/PublicPort.java    |   10 -
 .../java/org/apache/nifi/services/FlowService.java |    2 +-
 .../nifi/controller/FlowSerializationStrategy.java |   31 -
 .../nifi/controller/StandardFlowService.java       |   21 +-
 .../nifi/controller/StandardFlowSnippet.java       |   13 -
 .../nifi/controller/XmlFlowSynchronizer.java       | 1981 --------------------
 .../inheritance/BundleCompatibilityCheck.java      |    8 -
 .../inheritance/ConnectionMissingCheck.java        |   56 +-
 .../inheritance/FlowFingerprintCheck.java          |   99 -
 .../serialization/FlowFromDOMFactory.java          |  783 --------
 .../serialization/RunningComponentSetFilter.java   |    4 +-
 .../serialization/StandardFlowSerializer.java      |  716 -------
 .../serialization/StandardFlowSynchronizer.java    |   64 -
 .../serialization/VersionedFlowSynchronizer.java   |   90 +-
 .../service/ControllerServiceLoader.java           |  188 --
 .../nifi/fingerprint/FingerprintException.java     |   40 -
 .../nifi/fingerprint/FingerprintFactory.java       | 1050 -----------
 .../FlowConfigurationArchiveManager.java           |    6 +-
 .../persistence/StandardFlowConfigurationDAO.java  |   71 +-
 .../spring/StandardFlowServiceFactoryBean.java     |    4 +-
 .../main/java/org/apache/nifi/util/FlowParser.java |  194 +-
 .../nifi/util/LoggingXmlParserErrorHandler.java    |   43 -
 .../src/main/resources/FlowConfiguration.xsd       |  607 ------
 .../nifi/controller/StandardFlowServiceTest.java   |   38 +-
 .../apache/nifi/controller/TestFlowController.java |   97 +-
 .../serialization/StandardFlowSerializerTest.java  |  169 --
 .../nifi/fingerprint/FingerprintFactoryTest.java   |  405 ----
 .../TestFlowConfigurationArchiveManager.java       |    2 +-
 .../resources/conf/{0bytes.xml => 0bytes.json}     |    0
 .../src/test/resources/conf/all-flow-corrupt.json  |  420 +++++
 .../src/test/resources/conf/all-flow-corrupt.xml   |  201 --
 .../test/resources/conf/all-flow-inheritable.json  |  417 ++++
 .../test/resources/conf/all-flow-inheritable.xml   |  196 --
 .../resources/conf/all-flow-uninheritable.json     |  417 ++++
 .../test/resources/conf/all-flow-uninheritable.xml |  202 --
 .../src/test/resources/conf/all-flow.json          |  417 ++++
 .../src/test/resources/conf/all-flow.xml           |  198 --
 .../src/test/resources/conf/nifi.properties        |    3 +-
 .../src/test/resources/conf/only-termination.json  |    1 +
 .../src/test/resources/conf/only-termination.xml   |   37 -
 .../conf/parameter-context-flow-error.json         |  102 +
 .../conf/parameter-context-flow-error.xml          |   70 -
 .../resources/conf/parameter-context-flow.json     |    1 +
 .../test/resources/conf/parameter-context-flow.xml |   75 -
 .../conf/parameter-provider-with-cs-flow.json      |  139 ++
 .../conf/parameter-provider-with-cs-flow.xml       |   71 -
 .../conf/processor-with-cs-flow-0.7.0.json         |  100 +
 .../conf/processor-with-cs-flow-0.7.0.xml          |   60 -
 .../src/test/resources/conf/remote-flow.xml        |  145 --
 .../conf/reporting-task-with-cs-flow-0.7.0.json    |  142 ++
 .../conf/reporting-task-with-cs-flow-0.7.0.xml     |   75 -
 .../resources/conf/scale-positions-flow-0.7.0.json |    1 +
 .../resources/conf/scale-positions-flow-0.7.0.xml  | 1533 ---------------
 .../src/test/resources/conf/standard-flow.json     |    1 +
 .../src/test/resources/conf/standard-flow.xml      |  196 --
 .../src/test/resources/conf/taskConfig.xml         |   17 -
 ...{termination-only.xml => termination-only.json} |    0
 .../resources/flowcontrollertest.nifi.properties   |    2 +-
 .../src/test/resources/nifi-with-remote.properties |    2 +-
 .../test/resources/nifi/fingerprint/flow1a.json    |  399 ++++
 .../src/test/resources/nifi/fingerprint/flow1a.xml |  215 ---
 .../test/resources/nifi/fingerprint/flow1b.json    |  412 ++++
 .../src/test/resources/nifi/fingerprint/flow1b.xml |  217 ---
 .../src/test/resources/nifi/fingerprint/flow2.json |  358 ++++
 .../src/test/resources/nifi/fingerprint/flow2.xml  |  175 --
 .../nifi/fingerprint/flow3-with-bundle-1.json      |   79 +
 .../nifi/fingerprint/flow3-with-bundle-1.xml       |   55 -
 .../nifi/fingerprint/flow3-with-bundle-2.json      |   79 +
 .../nifi/fingerprint/flow3-with-bundle-2.xml       |   55 -
 .../fingerprint/flow3-with-missing-bundle.json     |   79 +
 .../nifi/fingerprint/flow3-with-missing-bundle.xml |   55 -
 .../nifi/fingerprint/flow3-with-no-bundle.json     |   79 +
 .../nifi/fingerprint/flow3-with-no-bundle.xml      |   50 -
 .../fingerprint/flow4-with-different-bundle.json   |   79 +
 .../fingerprint/flow4-with-different-bundle.xml    |   55 -
 .../src/test/resources/nifi/fingerprint/flow4.json |   79 +
 .../src/test/resources/nifi/fingerprint/flow4.xml  |   55 -
 .../standardflowserializertest.nifi.properties     |    2 +-
 .../standardflowsynchronizerspec.nifi.properties   |    2 +-
 .../standardprocessschedulertest.nifi.properties   |    2 +-
 .../conf/nifi.nar_with_native_lib.properties       |    2 +-
 .../conf/nifi.nar_without_native_lib.properties    |    2 +-
 .../src/test/resources/conf/nifi.properties        |    2 +-
 .../resources/NarUnpacker/conf/nifi.properties     |    2 +-
 .../src/test/resources/nifi.properties             |    2 +-
 .../apache/nifi/headless/HeadlessNiFiServer.java   |    8 +-
 .../src/test/resources/nifi.properties             |    2 +-
 .../nifi/properties/NiFiPropertiesLoader.java      |   12 +-
 .../properties/conf/duplicates.nifi.properties     |    2 +-
 .../resources/properties/conf/flow.nifi.properties |    5 +-
 .../properties/conf/protected.nifi.properties      |    3 +-
 .../nifi-framework/nifi-resources/pom.xml          |    3 +-
 .../src/main/resources/conf/nifi.properties        |    1 -
 .../NiFiProperties/conf/encrypted.nifi.properties  |    2 +-
 .../resources/NiFiProperties/conf/nifi.properties  |    2 +-
 .../org/apache/nifi/remote/StandardPublicPort.java |   55 +-
 .../src/test/resources/nifi.properties             |    2 +-
 .../java/org/apache/nifi/audit/PortAuditor.java    |   55 +-
 .../org/apache/nifi/web/api/dto/DtoFactory.java    |   10 +-
 .../apache/nifi/web/dao/impl/AbstractPortDAO.java  |   13 +-
 .../attributematchers/PublicPortMatcher.java       |   42 -
 .../src/main/resources/nifi-web-api-context.xml    |    2 -
 .../nifi/web/controller/ComponentMockUtil.java     |   12 +-
 .../ControllerSearchServiceIntegrationTest.java    |   18 -
 .../ControllerSearchServiceRegressionTest.java     |   10 +-
 .../attributematchers/PublicPortMatcherTest.java   |   65 -
 .../nifi-anonymous-allowed.properties              |    2 +-
 .../resources/access-control/nifi-flow.properties  |    2 +-
 .../nifi-mapped-identities.properties              |    2 +-
 .../test/resources/access-control/nifi.properties  |    2 +-
 .../additionalDetails.html                         |    4 +-
 .../additionalDetails.html                         |    4 +-
 .../additionalDetails.html                         |    4 +-
 .../additionalDetails.html                         |    4 +-
 .../src/test/resources/nifi.properties             |    2 +-
 nifi-stateless/nifi-stateless-assembly/README.md   |    2 +-
 nifi-system-tests/nifi-system-test-suite/pom.xml   |    8 +-
 .../nifi/tests/system/InstanceConfiguration.java   |   22 +-
 .../SpawnedStandaloneNiFiInstanceFactory.java      |    8 +-
 .../system/clustering/FlowSynchronizationIT.java   |    3 +-
 .../clustering/JoinClusterAdjustStateIT.java       |    4 +-
 .../clustering/JoinClusterWithDifferentFlow.java   |  154 +-
 .../JoinClusterWithMissingConnectionNoData.java    |    4 +-
 .../JoinClusterWithMissingConnectionWithData.java  |    4 +-
 .../system/restart/FlowFileRestorationIT.java      |    2 -
 .../resources/conf/clustered/node1/nifi.properties |    2 +-
 .../resources/conf/clustered/node2/nifi.properties |    2 +-
 .../test/resources/conf/default/nifi.properties    |    2 +-
 .../resources/flows/mismatched-flows/flow1.json.gz |  Bin 0 -> 4273 bytes
 .../resources/flows/mismatched-flows/flow1.xml.gz  |  Bin 3554 -> 0 bytes
 .../resources/flows/mismatched-flows/flow2.json.gz |  Bin 0 -> 4252 bytes
 .../resources/flows/mismatched-flows/flow2.xml.gz  |  Bin 3530 -> 0 bytes
 .../missing-connection/with-connection.json.gz     |  Bin 0 -> 1424 bytes
 .../missing-connection/with-connection.xml.gz      |  Bin 1031 -> 0 bytes
 .../missing-connection/without-connection.json.gz  |  Bin 0 -> 1177 bytes
 .../missing-connection/without-connection.xml.gz   |  Bin 770 -> 0 bytes
 .../nifi/properties/ConfigEncryptionTool.groovy    |  121 +-
 .../properties/ConfigEncryptionToolTest.groovy     |    8 +-
 .../src/test/resources/nifi_default.properties     |    2 +-
 ...h_sensitive_properties_protected_aes.properties |    2 +-
 ...nsitive_properties_protected_aes_128.properties |    2 +-
 ...ve_properties_protected_aes_password.properties |    2 +-
 ...roperties_protected_aes_password_128.properties |    2 +-
 ...ith_sensitive_properties_unprotected.properties |    2 +-
 ...otected_and_empty_protection_schemes.properties |    2 +-
 .../src/test/resources/localhost/nifi.properties   |    2 +-
 211 files changed, 4325 insertions(+), 12679 deletions(-)

diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java
index f043f6d5a1..b5d30ffe09 100644
--- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java
+++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java
@@ -58,11 +58,6 @@ public class MiNiFiConfigurationChangeListener implements ConfigurationChangeLis
         this.flowEnrichService = flowEnrichService;
     }
 
-    @Override
-    public String getDescriptor() {
-        return "MiNiFiConfigurationChangeListener";
-    }
-
     @Override
     public void handleChange(InputStream flowConfigInputStream) throws ConfigurationChangeException {
         logger.info("Received notification of a change");
@@ -107,6 +102,11 @@ public class MiNiFiConfigurationChangeListener implements ConfigurationChangeLis
         }
     }
 
+    @Override
+    public String getDescriptor() {
+        return "MiNiFiConfigurationChangeListener";
+    }
+
     private void setActiveFlowReference(ByteBuffer flowConfig) {
         logger.debug("Setting active flow reference {} with content:\n{}", flowConfig, new String(flowConfig.array(), UTF_8));
         runner.getConfigFileReference().set(flowConfig);
diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java
index 53e39e1839..16a393d0c9 100644
--- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java
+++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java
@@ -137,11 +137,11 @@ public class MiNiFiPropertiesGenerator {
         Triple.of(NiFiProperties.SECURITY_OCSP_RESPONDER_URL, EMPTY, EMPTY),
         Triple.of(NiFiProperties.SECURITY_OCSP_RESPONDER_CERTIFICATE, EMPTY, EMPTY),
         Triple.of(NiFiProperties.CLUSTER_IS_NODE, "false", EMPTY),
-        Triple.of(NiFiProperties.FLOW_CONFIGURATION_FILE, "./conf/flow.xml.gz", EMPTY)
+        Triple.of(NiFiProperties.FLOW_CONFIGURATION_FILE, "./conf/flow.json.gz", EMPTY)
     );
 
     static final Map<String, String> MINIFI_TO_NIFI_PROPERTY_MAPPING = Map.of(
-        MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), NiFiProperties.FLOW_CONFIGURATION_JSON_FILE,
+        MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), NiFiProperties.FLOW_CONFIGURATION_FILE,
         MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE.getKey(), NiFiProperties.SECURITY_KEYSTORE,
         MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_TYPE.getKey(), NiFiProperties.SECURITY_KEYSTORE_TYPE,
         MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_PASSWD.getKey(), NiFiProperties.SECURITY_KEYSTORE_PASSWD,
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
index 4f0e0b25e0..8df7e966ca 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-216/nifi.properties.before
@@ -15,7 +15,7 @@
 
 # Core Properties #
 
-nifi.flow.configuration.file=./conf/flow.xml.gz
+nifi.flow.configuration.file=./conf/flow.json.gz
 nifi.flow.configuration.archive.enabled=false
 nifi.flow.configuration.archive.dir=./conf/archive/
 nifi.flowcontroller.autoResumeState=true
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
index 4f0e0b25e0..8df7e966ca 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-245/nifi.properties.before
@@ -15,7 +15,7 @@
 
 # Core Properties #
 
-nifi.flow.configuration.file=./conf/flow.xml.gz
+nifi.flow.configuration.file=./conf/flow.json.gz
 nifi.flow.configuration.archive.enabled=false
 nifi.flow.configuration.archive.dir=./conf/archive/
 nifi.flowcontroller.autoResumeState=true
diff --git a/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties b/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
index 4f0e0b25e0..8df7e966ca 100644
--- a/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
+++ b/minifi/minifi-bootstrap/src/test/resources/MINIFI-277/nifi.properties
@@ -15,7 +15,7 @@
 
 # Core Properties #
 
-nifi.flow.configuration.file=./conf/flow.xml.gz
+nifi.flow.configuration.file=./conf/flow.json.gz
 nifi.flow.configuration.archive.enabled=false
 nifi.flow.configuration.archive.dir=./conf/archive/
 nifi.flowcontroller.autoResumeState=true
diff --git a/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before b/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
index 4f0e0b25e0..8df7e966ca 100644
--- a/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
+++ b/minifi/minifi-bootstrap/src/test/resources/NIFI-8753/nifi.properties.before
@@ -15,7 +15,7 @@
 
 # Core Properties #
 
-nifi.flow.configuration.file=./conf/flow.xml.gz
+nifi.flow.configuration.file=./conf/flow.json.gz
 nifi.flow.configuration.archive.enabled=false
 nifi.flow.configuration.archive.dir=./conf/archive/
 nifi.flowcontroller.autoResumeState=true
diff --git a/minifi/minifi-docs/src/main/markdown/System_Admin_Guide.md b/minifi/minifi-docs/src/main/markdown/System_Admin_Guide.md
index 69d5a77500..f227fec440 100644
--- a/minifi/minifi-docs/src/main/markdown/System_Admin_Guide.md
+++ b/minifi/minifi-docs/src/main/markdown/System_Admin_Guide.md
@@ -434,7 +434,7 @@ The "Core Properties" section applies to the core framework as a whole.
 *Property*                                 | *Description*
 ------------------------------------------ | -----------
 `flow controller graceful shutdown period` | Indicates the shutdown period. The default value is `10 sec`.
-`flow service write delay interval`        | When many changes are made to the *flow.xml*, this property specifies how long to wait before writing out the changes, so as to batch the changes into a single write. The default value is `500 ms`.
+`flow service write delay interval`        | When many changes are made to the *flow.json*, this property specifies how long to wait before writing out the changes, so as to batch the changes into a single write. The default value is `500 ms`.
 `administrative yield duration`            | If a component allows an unexpected exception to escape, it is considered a bug. As a result, the framework will pause (or administratively yield) the component for this amount of time. This is done so that the component does not use up massive amounts of system resources, since it is known to have problems in the existing state. The default value is `30 sec`.
 `bored yield duration`                     | When a component has no work to do (i.e., is "bored"), this is the amount of time it will wait before checking to see if it has new data to work on. This way, it does not use up CPU resources by checking for new work too often. When setting this property, be aware that it could add extra latency for components that do not constantly have work to do, as once they go into this "bored" state, they will wait this amount of time before checking for [...]
 `max concurrent threads`                   | The maximum number of threads any processor can have running at one time.
diff --git a/minifi/minifi-integration-tests/src/test/resources/conf/nifi.properties b/minifi/minifi-integration-tests/src/test/resources/conf/nifi.properties
index b2530ed55e..85f8471bd0 100644
--- a/minifi/minifi-integration-tests/src/test/resources/conf/nifi.properties
+++ b/minifi/minifi-integration-tests/src/test/resources/conf/nifi.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/C2NifiClientService.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/C2NifiClientService.java
index 74109a6887..0ef45a92c2 100644
--- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/C2NifiClientService.java
+++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-framework-core/src/main/java/org/apache/nifi/minifi/c2/C2NifiClientService.java
@@ -45,7 +45,7 @@ import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.C2_SECURITY_KE
 import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.C2_SECURITY_TRUSTSTORE_LOCATION;
 import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.C2_SECURITY_TRUSTSTORE_PASSWORD;
 import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.C2_SECURITY_TRUSTSTORE_TYPE;
-import static org.apache.nifi.util.NiFiProperties.FLOW_CONFIGURATION_JSON_FILE;
+import static org.apache.nifi.util.NiFiProperties.FLOW_CONFIGURATION_FILE;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
@@ -216,7 +216,7 @@ public class C2NifiClientService {
 
         FlowEnrichService flowEnrichService = new FlowEnrichService(niFiProperties);
         UpdateConfigurationStrategy updateConfigurationStrategy =
-            new DefaultUpdateConfigurationStrategy(flowController, flowService, flowEnrichService, niFiProperties.getProperty(FLOW_CONFIGURATION_JSON_FILE));
+            new DefaultUpdateConfigurationStrategy(flowController, flowService, flowEnrichService, niFiProperties.getProperty(FLOW_CONFIGURATION_FILE));
 
         return new C2OperationHandlerProvider(List.of(
             new UpdateConfigurationOperationHandler(client, flowIdHolder, updateConfigurationStrategy, emptyOperandPropertiesProvider),
diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-server/src/main/java/org/apache/nifi/minifi/StandardMiNiFiServer.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-server/src/main/java/org/apache/nifi/minifi/StandardMiNiFiServer.java
index 4263ac809f..1b648a5a0b 100644
--- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-server/src/main/java/org/apache/nifi/minifi/StandardMiNiFiServer.java
+++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-server/src/main/java/org/apache/nifi/minifi/StandardMiNiFiServer.java
@@ -24,7 +24,6 @@ import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.util.Optional;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.controller.FlowSerializationStrategy;
 import org.apache.nifi.headless.HeadlessNiFiServer;
 import org.apache.nifi.minifi.bootstrap.BootstrapListener;
 import org.apache.nifi.minifi.c2.C2NifiClientService;
@@ -87,11 +86,6 @@ public class StandardMiNiFiServer extends HeadlessNiFiServer implements MiNiFiSe
         }
     }
 
-    @Override
-    protected FlowSerializationStrategy getFlowSerializationStrategy() {
-        return FlowSerializationStrategy.WRITE_JSON_ONLY;
-    }
-
     private void initC2() {
         if (Boolean.parseBoolean(getNiFiProperties().getProperty(MiNiFiProperties.C2_ENABLE.getKey(), MiNiFiProperties.C2_ENABLE.getDefaultValue()))) {
             NiFiProperties niFiProperties = getNiFiProperties();
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.dns-sans b/nifi-bootstrap/src/test/resources/nifi.properties.dns-sans
index 1528c1b871..74d25bbc7c 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.dns-sans
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.dns-sans
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.ip-sans b/nifi-bootstrap/src/test/resources/nifi.properties.ip-sans
index 35df24cfcb..1ff3f757a4 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.ip-sans
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.ip-sans
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.keystore-password b/nifi-bootstrap/src/test/resources/nifi.properties.keystore-password
index cd99e6de5f..7ade1760b5 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.keystore-password
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.keystore-password
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.no-https b/nifi-bootstrap/src/test/resources/nifi.properties.no-https
index ddc7080fa7..84408708b9 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.no-https
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.no-https
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.no-keystore-types b/nifi-bootstrap/src/test/resources/nifi.properties.no-keystore-types
index 37b9915f4f..e1c1c0b1e2 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.no-keystore-types
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.no-keystore-types
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.no-keystores b/nifi-bootstrap/src/test/resources/nifi.properties.no-keystores
index a4325f4a75..3eef8bc3bd 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.no-keystores
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.no-keystores
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.only-keystore b/nifi-bootstrap/src/test/resources/nifi.properties.only-keystore
index de83da7720..37d7ed2c61 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.only-keystore
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.only-keystore
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.only-truststore b/nifi-bootstrap/src/test/resources/nifi.properties.only-truststore
index 4b58c0cc93..3f5d57a04f 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.only-truststore
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.only-truststore
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.stores-exist b/nifi-bootstrap/src/test/resources/nifi.properties.stores-exist
index 6cc723eacc..6d974df1d0 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.stores-exist
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.stores-exist
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.success b/nifi-bootstrap/src/test/resources/nifi.properties.success
index 1272b12a75..67a2cb69c9 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.success
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.success
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-bootstrap/src/test/resources/nifi.properties.truststore-password b/nifi-bootstrap/src/test/resources/nifi.properties.truststore-password
index 5ac0d2072a..52c6eb73a7 100644
--- a/nifi-bootstrap/src/test/resources/nifi.properties.truststore-password
+++ b/nifi-bootstrap/src/test/resources/nifi.properties.truststore-password
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 
 # Removing most properties for testing...
 
diff --git a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptor.java b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptor.java
deleted file mode 100644
index 2cbbfd2f09..0000000000
--- a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptor.java
+++ /dev/null
@@ -1,55 +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.flow.encryptor;
-
-import org.apache.nifi.encrypt.PropertyEncryptor;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UncheckedIOException;
-
-/**
- * Standard Flow Encryptor handles reading Input Steam and writing Output Stream
- */
-public class StandardFlowEncryptor implements FlowEncryptor {
-    private static final int XML_DECLARATION = '<';
-
-    /**
-     * Process Flow Configuration Stream replacing existing encrypted properties with new encrypted properties
-     *
-     * @param inputStream Flow Configuration Input Stream
-     * @param outputStream Flow Configuration Output Stream encrypted using new password
-     * @param inputEncryptor Property Encryptor for Input Configuration
-     * @param outputEncryptor Property Encryptor for Output Configuration
-     */
-    @Override
-    public void processFlow(final InputStream inputStream, final OutputStream outputStream,
-                            final PropertyEncryptor inputEncryptor, final PropertyEncryptor outputEncryptor) {
-        final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
-        bufferedInputStream.mark(1);
-        try {
-            final int firstByte = bufferedInputStream.read();
-            bufferedInputStream.reset();
-            final FlowEncryptor flowEncryptor = (firstByte == XML_DECLARATION) ? new XmlFlowEncryptor() : new JsonFlowEncryptor();
-            flowEncryptor.processFlow(bufferedInputStream, outputStream, inputEncryptor, outputEncryptor);
-        } catch (final IOException e) {
-            throw new UncheckedIOException(e);
-        }
-    }
-}
diff --git a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/XmlFlowEncryptor.java b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/XmlFlowEncryptor.java
deleted file mode 100644
index db5b22bf24..0000000000
--- a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/XmlFlowEncryptor.java
+++ /dev/null
@@ -1,80 +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.flow.encryptor;
-
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
-import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
-
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Characters;
-import javax.xml.stream.events.XMLEvent;
-import javax.xml.transform.stream.StreamSource;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UncheckedIOException;
-import java.nio.charset.StandardCharsets;
-import java.util.regex.Matcher;
-
-public class XmlFlowEncryptor extends AbstractFlowEncryptor {
-    private static final XMLEventReaderProvider eventReaderProvider = new StandardXMLEventReaderProvider();
-
-    @Override
-    public void processFlow(final InputStream inputStream, final OutputStream outputStream,
-                            final PropertyEncryptor inputEncryptor, final PropertyEncryptor outputEncryptor) {
-        final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
-        final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-
-        try {
-            final XMLEventReader reader = eventReaderProvider.getEventReader(new StreamSource(inputStream));
-            final XMLEventWriter writer = xmlOutputFactory.createXMLEventWriter(outputStream, StandardCharsets.UTF_8.name());
-            while (reader.hasNext()) {
-                final XMLEvent event = reader.nextEvent();
-                if (event.getEventType() == XMLEvent.CHARACTERS) {
-                    final Characters characters = event.asCharacters();
-                    final String value = characters.getData();
-                    final Matcher matcher = ENCRYPTED_PATTERN.matcher(value);
-                    if (matcher.matches()) {
-                        final String processedValue = getOutputEncrypted(matcher.group(FIRST_GROUP), inputEncryptor, outputEncryptor);
-                        writer.add(eventFactory.createCharacters(processedValue));
-                    } else {
-                        writer.add(characters);
-                    }
-                } else if (event.getEventType() == XMLEvent.START_DOCUMENT) {
-                    writer.add(event);
-                    writer.add(eventFactory.createSpace(System.lineSeparator()));
-                } else {
-                    writer.add(event);
-                }
-            }
-            writer.flush();
-            writer.close();
-            reader.close();
-            outputStream.close();
-            inputStream.close();
-        } catch (final XMLStreamException e) {
-            throw new RuntimeException("Flow XML Processing Failed", e);
-        } catch (final IOException e) {
-            throw new UncheckedIOException("Failed Processing Flow Configuration", e);
-        }
-    }
-}
diff --git a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java
index 353b065b5d..b5f8cd03cb 100644
--- a/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java
+++ b/nifi-commons/nifi-flow-encryptor/src/main/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommand.java
@@ -16,12 +16,6 @@
  */
 package org.apache.nifi.flow.encryptor.command;
 
-import org.apache.nifi.encrypt.PropertyEncryptionMethod;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
-import org.apache.nifi.flow.encryptor.FlowEncryptor;
-import org.apache.nifi.flow.encryptor.StandardFlowEncryptor;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -40,6 +34,11 @@ import java.util.Properties;
 import java.util.stream.Collectors;
 import java.util.zip.GZIPInputStream;
 import java.util.zip.GZIPOutputStream;
+import org.apache.nifi.encrypt.PropertyEncryptionMethod;
+import org.apache.nifi.encrypt.PropertyEncryptor;
+import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
+import org.apache.nifi.flow.encryptor.FlowEncryptor;
+import org.apache.nifi.flow.encryptor.JsonFlowEncryptor;
 
 /**
  * Flow Encryptor Command capable of updating Sensitive Properties Key or Algorithm as well as Flow Configuration
@@ -53,9 +52,7 @@ class FlowEncryptorCommand implements Runnable {
 
     protected static final String CONFIGURATION_FILE = "nifi.flow.configuration.file";
 
-    protected static final String CONFIGURATION_JSON_FILE = "nifi.flow.configuration.json.file";
-
-    private static final List<String> CONFIGURATION_FILES = Arrays.asList(CONFIGURATION_FILE, CONFIGURATION_JSON_FILE);
+    private static final List<String> CONFIGURATION_FILES = Arrays.asList(CONFIGURATION_FILE);
 
     private static final String FLOW_PREFIX = "nifi.flow.";
 
@@ -131,7 +128,7 @@ class FlowEncryptorCommand implements Runnable {
                 final String inputPropertiesKey = getKey(properties);
                 final PropertyEncryptor inputEncryptor = getPropertyEncryptor(inputPropertiesKey, inputAlgorithm);
 
-                final FlowEncryptor flowEncryptor = new StandardFlowEncryptor();
+                final FlowEncryptor flowEncryptor = new JsonFlowEncryptor();
                 flowEncryptor.processFlow(flowInputStream, flowOutputStream, inputEncryptor, outputEncryptor);
             }
 
diff --git a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptorTest.java b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/JsonFlowEncryptorTest.java
similarity index 62%
rename from nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptorTest.java
rename to nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/JsonFlowEncryptorTest.java
index ef9b61ffd4..37a444dd95 100644
--- a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/StandardFlowEncryptorTest.java
+++ b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/JsonFlowEncryptorTest.java
@@ -16,11 +16,8 @@
  */
 package org.apache.nifi.flow.encryptor;
 
-import org.apache.nifi.encrypt.PropertyEncryptionMethod;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -31,11 +28,13 @@ import java.util.Objects;
 import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.apache.nifi.encrypt.PropertyEncryptionMethod;
+import org.apache.nifi.encrypt.PropertyEncryptor;
+import org.apache.nifi.encrypt.PropertyEncryptorBuilder;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class StandardFlowEncryptorTest {
+public class JsonFlowEncryptorTest {
     private static final String INPUT_KEY = UUID.randomUUID().toString();
 
     private static final String OUTPUT_KEY = UUID.randomUUID().toString();
@@ -50,22 +49,23 @@ public class StandardFlowEncryptorTest {
 
     private PropertyEncryptor outputEncryptor;
 
-    private StandardFlowEncryptor flowEncryptor;
+    private FlowEncryptor flowEncryptor;
 
 
     @BeforeEach
     public void setEncryptors() {
         inputEncryptor = getPropertyEncryptor(INPUT_KEY, PropertyEncryptionMethod.NIFI_PBKDF2_AES_GCM_256.name());
         outputEncryptor = getPropertyEncryptor(OUTPUT_KEY, PropertyEncryptionMethod.NIFI_ARGON2_AES_GCM_256.name());
-        flowEncryptor = new StandardFlowEncryptor();
+        flowEncryptor = new JsonFlowEncryptor();
     }
 
     @Test
     public void testProcessEncrypted() {
-        final String property = StandardFlowEncryptorTest.class.getSimpleName();
+        final String property = JsonFlowEncryptorTest.class.getSimpleName();
         final String encryptedProperty = String.format(ENCRYPTED_FORMAT, inputEncryptor.encrypt(property));
-        final String encryptedRow = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>%n" +
-                "<test>%s</test>", encryptedProperty);
+        final String encryptedRow = String.format(
+                "{\"properties\":{\"username\":\"sample_username\",\"test\":\"%s\",\"position\":1.123456789123456789}}",
+                encryptedProperty);
 
         final InputStream inputStream = new ByteArrayInputStream(encryptedRow.getBytes(StandardCharsets.UTF_8));
         final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@@ -83,8 +83,7 @@ public class StandardFlowEncryptorTest {
 
     @Test
     public void testProcessNoEncrypted() {
-        final String property = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>%n" +
-                "<test>%s</test>", StandardFlowEncryptorTest.class.getSimpleName());
+        final String property = String.format("{\"properties\":{\"username\":\"sample_username\",\"test\":\"%s\",\"position\":1.123456789123456789}}", JsonFlowEncryptorTest.class.getSimpleName());
 
         final InputStream inputStream = new ByteArrayInputStream(property.getBytes(StandardCharsets.UTF_8));
         final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
@@ -92,12 +91,12 @@ public class StandardFlowEncryptorTest {
         flowEncryptor.processFlow(inputStream, outputStream, inputEncryptor, outputEncryptor);
 
         final String outputProperty = outputStream.toString();
-        assertEquals(removeXmlDeclaration(property).trim(), removeXmlDeclaration(outputProperty).trim());
+        assertEquals(property, outputProperty);
     }
 
     @Test
     public void testProcessJson() throws IOException {
-        final String password = StandardFlowEncryptorTest.class.getSimpleName();
+        final String password = JsonFlowEncryptorTest.class.getSimpleName();
         final String encryptedPassword = String.format(ENCRYPTED_FORMAT, inputEncryptor.encrypt(password));
 
         final String sampleFlowJson = getSampleFlowJson(encryptedPassword);
@@ -113,21 +112,6 @@ public class StandardFlowEncryptorTest {
         }
     }
 
-    @Test
-    public void testProcessXml() throws IOException {
-        final String password = StandardFlowEncryptorTest.class.getSimpleName();
-        final String encryptedPassword = String.format(ENCRYPTED_FORMAT, inputEncryptor.encrypt(password));
-        final String sampleFlowXml = getSampleFlowXml(encryptedPassword);
-        try (final InputStream inputStream = new ByteArrayInputStream(sampleFlowXml.getBytes(StandardCharsets.UTF_8))) {
-            try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
-                flowEncryptor.processFlow(inputStream, outputStream, inputEncryptor, outputEncryptor);
-                final String outputXml = outputStream.toString();
-
-                compareFlow(removeXmlDeclaration(sampleFlowXml).trim(), removeXmlDeclaration(outputXml).trim());
-            }
-        }
-    }
-
     private PropertyEncryptor getPropertyEncryptor(final String propertiesKey, final String propertiesAlgorithm) {
         return new PropertyEncryptorBuilder(propertiesKey).setAlgorithm(propertiesAlgorithm).build();
     }
@@ -145,43 +129,4 @@ public class StandardFlowEncryptorTest {
         Objects.requireNonNull(password);
         return String.format("{\"properties\":{\"username\":\"sample_username\",\"password\":\"%s\",\"position\":1.123456789123456789}}", password);
     }
-
-    private String getSampleFlowXml(final String password) {
-        Objects.requireNonNull(password);
-        final String flowXml = String.format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>%n" +
-                "<processor>%n" +
-                "\t<property>%n" +
-                "\t\t<name>Username</name>%n" +
-                "\t\t<value>SAMPLE_USERNAME</value>%n" +
-                "\t</property>%n" +
-                "\t<property>%n" +
-                "\t\t<name>Password</name>%n" +
-                "\t\t<value>%s</value>%n" +
-                "\t</property>%n" +
-                "</processor>", password);
-
-        return getProcessedFlowXml(flowXml);
-    }
-
-    private String getProcessedFlowXml(final String flowXml) {
-        final PropertyEncryptor encryptor = new PropertyEncryptor() {
-            @Override
-            public String encrypt(String property) {
-                return property;
-            }
-
-            @Override
-            public String decrypt(String encryptedProperty) {
-                return encryptedProperty;
-            }
-        };
-        final InputStream inputStream = new ByteArrayInputStream(flowXml.getBytes(StandardCharsets.UTF_8));
-        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        flowEncryptor.processFlow(inputStream, outputStream, encryptor, encryptor);
-        return outputStream.toString();
-    }
-
-    private String removeXmlDeclaration(final String xmlFlow) {
-        return xmlFlow.replaceAll("<\\?xml.+\\?>", "");
-    }
 }
diff --git a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java
index 50837bd05e..1f37379bdd 100644
--- a/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java
+++ b/nifi-commons/nifi-flow-encryptor/src/test/java/org/apache/nifi/flow/encryptor/command/FlowEncryptorCommandTest.java
@@ -44,12 +44,8 @@ public class FlowEncryptorCommandTest {
 
     private static final String FLOW_CONTENTS_JSON = "{\"property\":\"value\"}";
 
-    private static final String FLOW_CONTENTS_XML = "<property><value>PROPERTY</value></property>";
-
     private static final String JSON_GZ = ".json.gz";
 
-    private static final String XML_GZ = ".xml.gz";
-
     private static final String PROPERTIES_EXTENSION = ".properties";
 
     private static final String BLANK_PROPERTIES = "/blank.nifi.properties";
@@ -123,19 +119,16 @@ public class FlowEncryptorCommandTest {
     }
 
     protected static Path getBlankNiFiProperties() throws IOException, URISyntaxException {
-        final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
         final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
-        return getNiFiProperties(flowConfiguration, flowConfigurationJson, BLANK_PROPERTIES);
+        return getNiFiProperties(flowConfigurationJson, BLANK_PROPERTIES);
     }
 
     protected static Path getPopulatedNiFiProperties() throws IOException, URISyntaxException {
-        final Path flowConfiguration = getFlowConfiguration(FLOW_CONTENTS_XML, XML_GZ);
         final Path flowConfigurationJson = getFlowConfiguration(FLOW_CONTENTS_JSON, JSON_GZ);
-        return getNiFiProperties(flowConfiguration, flowConfigurationJson, POPULATED_PROPERTIES);
+        return getNiFiProperties(flowConfigurationJson, POPULATED_PROPERTIES);
     }
 
     private static Path getNiFiProperties(
-            final Path flowConfigurationPath,
             final Path flowConfigurationJsonPath,
             String propertiesResource
     ) throws IOException, URISyntaxException {
@@ -143,8 +136,6 @@ public class FlowEncryptorCommandTest {
         final List<String> sourceProperties = Files.readAllLines(sourcePropertiesPath);
         final List<String> flowProperties = sourceProperties.stream().map(line -> {
             if (line.startsWith(FlowEncryptorCommand.CONFIGURATION_FILE)) {
-                return line + flowConfigurationPath;
-            } else if (line.startsWith(FlowEncryptorCommand.CONFIGURATION_JSON_FILE)) {
                 return flowConfigurationJsonPath == null ? line : line + flowConfigurationJsonPath;
             } else {
                 return line;
diff --git a/nifi-commons/nifi-flow-encryptor/src/test/resources/blank.nifi.properties b/nifi-commons/nifi-flow-encryptor/src/test/resources/blank.nifi.properties
index b6e24e7eac..8c16c51f95 100644
--- a/nifi-commons/nifi-flow-encryptor/src/test/resources/blank.nifi.properties
+++ b/nifi-commons/nifi-flow-encryptor/src/test/resources/blank.nifi.properties
@@ -15,4 +15,3 @@
 nifi.sensitive.props.key=
 nifi.sensitive.props.algorithm=
 nifi.flow.configuration.file=
-nifi.flow.configuration.json.file=
diff --git a/nifi-commons/nifi-flow-encryptor/src/test/resources/populated.nifi.properties b/nifi-commons/nifi-flow-encryptor/src/test/resources/populated.nifi.properties
index 520019e21a..36e2707c71 100644
--- a/nifi-commons/nifi-flow-encryptor/src/test/resources/populated.nifi.properties
+++ b/nifi-commons/nifi-flow-encryptor/src/test/resources/populated.nifi.properties
@@ -15,4 +15,3 @@
 nifi.sensitive.props.key=D5E41AC1-EEF8-4A54-930D-593F749AE95C
 nifi.sensitive.props.algorithm=NIFI_ARGON2_AES_GCM_256
 nifi.flow.configuration.file=
-nifi.flow.configuration.json.file=
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index 643c050edf..78432ce444 100644
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -54,7 +54,6 @@ public class NiFiProperties extends ApplicationProperties {
     // core properties
     public static final String PROPERTIES_FILE_PATH = "nifi.properties.file.path";
     public static final String FLOW_CONFIGURATION_FILE = "nifi.flow.configuration.file";
-    public static final String FLOW_CONFIGURATION_JSON_FILE = "nifi.flow.configuration.json.file";
     public static final String FLOW_CONFIGURATION_ARCHIVE_ENABLED = "nifi.flow.configuration.archive.enabled";
     public static final String FLOW_CONFIGURATION_ARCHIVE_DIR = "nifi.flow.configuration.archive.dir";
     public static final String FLOW_CONFIGURATION_ARCHIVE_MAX_TIME = "nifi.flow.configuration.archive.max.time";
@@ -452,7 +451,6 @@ public class NiFiProperties extends ApplicationProperties {
         super(props);
     }
 
-    // getters for core properties //
     public File getFlowConfigurationFile() {
         try {
             return new File(getProperty(FLOW_CONFIGURATION_FILE));
@@ -461,21 +459,6 @@ public class NiFiProperties extends ApplicationProperties {
         }
     }
 
-    public File getFlowConfigurationJsonFile() {
-        final String jsonFilename = getProperty(FLOW_CONFIGURATION_JSON_FILE);
-        if (jsonFilename != null) {
-            return new File(jsonFilename);
-        }
-
-        final File xmlFile = getFlowConfigurationFile();
-        final String xmlFilename = xmlFile.getName();
-        if (xmlFilename.contains(".xml")) {
-            return new File(xmlFile.getParentFile(), xmlFilename.replace(".xml", ".json"));
-        }
-
-        return new File(xmlFile.getParentFile(), xmlFilename.replace(".gz", "") + ".json.gz");
-    }
-
     public File getFlowConfigurationFileDir() {
         try {
             return getFlowConfigurationFile().getParentFile();
diff --git a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.blank.properties b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.blank.properties
index 99931d1ae7..64dd766aa8 100644
--- a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.blank.properties
+++ b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.blank.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.missing.properties b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.missing.properties
index f94fbdbf05..31f0ef53a3 100644
--- a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.missing.properties
+++ b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.missing.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.properties b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.properties
index ec3616b435..853395b79e 100644
--- a/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.properties
+++ b/nifi-commons/nifi-properties/src/test/resources/NiFiProperties/conf/nifi.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 8fc594e9f9..2cc8d07726 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -3316,11 +3316,7 @@ The first section of the _nifi.properties_ file is for the Core Properties. Thes
 
 |===
 |*Property*|*Description*
-|`nifi.flow.configuration.file`*|The location of the XML-based flow configuration file. The default value is `./conf/flow.xml.gz`. This is a legacy property. Older versions of NiFi used an
-XML-formatted file to store the flow configuration. However, newer versions use a JSON representation. In order to maintain backward compatibility of flows and still load flows developed using
-older versions of NiFi, upon startup, NiFi will use the `nifi.flow.configuration.json.file` first. If the file exists, it will be used. However, if it does not exist, NiFi will fall back to this
-property to determine the XML version of the file and use it.
-|`nifi.flow.configuration.json.file`*|The location of the flow configuration file (i.e., the file that contains what is currently displayed on the NiFi graph). The default value is `./conf/flow.json.gz`.
+|`nifi.flow.configuration.file`*|The location of the JSON-based flow configuration file. The default value is `./conf/flow.json.gz`.
 |`nifi.flow.configuration.archive.enabled`*|Specifies whether NiFi creates a backup copy of the flow automatically when the flow is updated. The default value is `true`.
 |`nifi.flow.configuration.archive.dir`*|The location of the archive directory where backup copies of the _flow.json_ are saved. The default value is `./conf/archive`. NiFi removes old archive files to limit disk usage based on archived file lifespan, total size, and number of files, as specified with `nifi.flow.configuration.archive.max.time`, `max.storage` and `max.count` properties respectively. If none of these limitation for archiving is specified, NiFi uses default conditions, that  [...]
 This cleanup mechanism takes into account only automatically created archived _flow.json_ files. If there are other files or directories in this archive directory, NiFi will ignore them. Automatically created archives have filename with ISO 8601 format timestamp prefix followed by `<original-filename>`. That is `<year><month><day>T<hour><minute><second>+<timezone offset>_<original filename>`. For example, `20160706T160719+0900_flow.json.gz`. NiFi checks filenames when it cleans archive d [...]
@@ -4398,7 +4394,7 @@ If you are encrypting sensitive component properties in your dataflow via the se
 
 If the below properties point to directories inside the NiFi base installation path, you must copy the target directories to the new NiFi. Stop your existing NiFi installation before you do this.
 
-|`nifi.flow.configuration.json.file=`
+|`nifi.flow.configuration.file=`
 
 If you have retained the default value (`./conf/flow.json.gz`), copy _flow.json.gz_ from the existing to the new NiFi base install conf directory.
 
@@ -4466,7 +4462,7 @@ When a value is set for `nifi.sensitive.props.key` in _nifi.properties_, the spe
 2. Encrypts all the sensitive values with a specified new key.
 3. Updates the _nifi.properties_ and _flow.json.gz_ files or creates new versions of them.
 
-As an example, assume version 1.9.2 is the existing NiFi instance and the sensitive properties key is set to `password`. The goal is to move the 1.9.2 _flow.xml.gz_ to a 1.10.0 instance with a new sensitive properties key: `new_password`. Running the following Encrypt-Config command would read in the _flow.xml.gz_ and _nifi.properties_ files from 1.9.2 using the original sensitive properties key and write out new versions in 1.10.0 with the sensitive properties encrypted with the new password:
+As an example, assume version 1.9.2 is the existing NiFi instance and the sensitive properties key is set to `password`. The goal is to move the 1.9.2 _flow.json.gz_ to a 1.10.0 instance with a new sensitive properties key: `new_password`. Running the following Encrypt-Config command would read in the _flow.json.gz_ and _nifi.properties_ files from 1.9.2 using the original sensitive properties key and write out new versions in 1.10.0 with the sensitive properties encrypted with the new p [...]
 
 ```
 $ ./nifi-toolkit-1.10.0/bin/encrypt-config.sh -f /path/to/nifi/nifi-1.9.2/conf/flow.json.gz -g /path/to/nifi/nifi-1.10.0/conf/flow.json.gz -s new_password -n /path/to/nifi/nifi-1.9.2/conf/nifi
@@ -4495,7 +4491,6 @@ $ ./bin/nifi.sh set-sensitive-properties-algorithm <algorithm>
 The command reads the following flow configuration file properties from _nifi.properties_:
 
 - `nifi.flow.configuration.file`
-- `nifi.flow.configuration.json.file`
 
 The command checks for the existence of each file and updates the sensitive property values found.
 
@@ -4511,12 +4506,11 @@ The following command can be used to read an existing flow configuration and set
 $ ./bin/nifi.sh set-sensitive-properties-key <sensitivePropertiesKey>
 ```
 
-The command reads the following flow configuration file properties from _nifi.properties_:
+The command reads the following flow configuration file property from _nifi.properties_:
 
 - `nifi.flow.configuration.file`
-- `nifi.flow.configuration.json.file`
 
-The command checks for the existence of each file and updates the sensitive property values found.
+The command checks for the existence of the file file and updates the sensitive property values found.
 
 The minimum required length for a new sensitive properties key is 12 characters.
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
index e9313186e4..eedcec6190 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
@@ -20,7 +20,6 @@ import io.swagger.annotations.ApiModelProperty;
 
 import javax.xml.bind.annotation.XmlType;
 import java.util.Collection;
-import java.util.Set;
 
 /**
  * The details for a port within this NiFi flow.
@@ -34,8 +33,6 @@ public class PortDTO extends ComponentDTO {
     private String type;
     private Boolean transmitting;
     private Integer concurrentlySchedulableTaskCount;
-    private Set<String> userAccessControl;
-    private Set<String> groupAccessControl;
     private Boolean allowRemoteAccess;
     private String portFunction;
 
@@ -129,34 +126,6 @@ public class PortDTO extends ComponentDTO {
         this.transmitting = transmitting;
     }
 
-    /**
-     * @return groups that are allowed to access this port
-     */
-    @ApiModelProperty(
-            value = "The user groups that are allowed to access the port."
-    )
-    public Set<String> getGroupAccessControl() {
-        return groupAccessControl;
-    }
-
-    public void setGroupAccessControl(Set<String> groupAccessControl) {
-        this.groupAccessControl = groupAccessControl;
-    }
-
-    /**
-     * @return users that are allowed to access this port
-     */
-    @ApiModelProperty(
-            value = "The users that are allowed to access the port."
-    )
-    public Set<String> getUserAccessControl() {
-        return userAccessControl;
-    }
-
-    public void setUserAccessControl(Set<String> userAccessControl) {
-        this.userAccessControl = userAccessControl;
-    }
-
     /**
      * Gets the validation errors from this port. These validation errors represent the problems with the port that must be resolved before it can be started.
      *
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
index 5be8335a79..0d2ada3beb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
@@ -25,12 +25,10 @@ import org.apache.nifi.authorization.exception.UninheritableAuthorizationsExcept
 import org.apache.nifi.authorization.file.generated.Authorizations;
 import org.apache.nifi.authorization.file.generated.Policies;
 import org.apache.nifi.authorization.file.generated.Policy;
-import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.authorization.util.IdentityMapping;
 import org.apache.nifi.authorization.util.IdentityMappingUtil;
 import org.apache.nifi.components.PropertyValue;
-import org.apache.nifi.user.generated.Users;
 import org.apache.nifi.util.FlowInfo;
 import org.apache.nifi.util.FlowParser;
 import org.apache.nifi.util.NiFiProperties;
@@ -131,7 +129,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
     private File restoreAuthorizationsFile;
     private String rootGroupId;
     private String initialAdminIdentity;
-    private String legacyAuthorizedUsersFile;
     private Set<String> nodeIdentities;
     private String nodeGroupIdentifier;
     private List<PortDTO> ports = new ArrayList<>();
@@ -213,10 +210,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
             final PropertyValue initialAdminIdentityProp = configurationContext.getProperty(PROP_INITIAL_ADMIN_IDENTITY);
             initialAdminIdentity = initialAdminIdentityProp.isSet() ? IdentityMappingUtil.mapIdentity(initialAdminIdentityProp.getValue(), identityMappings) : null;
 
-            // get the value of the legacy authorized users file
-            final PropertyValue legacyAuthorizedUsersProp = configurationContext.getProperty(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE);
-            legacyAuthorizedUsersFile = legacyAuthorizedUsersProp.isSet() ? legacyAuthorizedUsersProp.getValue() : null;
-
             // extract any node identities
             nodeIdentities = new HashSet<>();
             for (Map.Entry<String,String> entry : configurationContext.getProperties().entrySet()) {
@@ -594,20 +587,14 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
         final AuthorizationsHolder authorizationsHolder = new AuthorizationsHolder(authorizations);
         final boolean emptyAuthorizations = authorizationsHolder.getAllPolicies().isEmpty();
         final boolean hasInitialAdminIdentity = (initialAdminIdentity != null && !StringUtils.isBlank(initialAdminIdentity));
-        final boolean hasLegacyAuthorizedUsers = (legacyAuthorizedUsersFile != null && !StringUtils.isBlank(legacyAuthorizedUsersFile));
 
         // if we are starting fresh then we might need to populate an initial admin or convert legacy users
         if (emptyAuthorizations) {
             parseFlow();
 
-            if (hasInitialAdminIdentity && hasLegacyAuthorizedUsers) {
-                throw new AuthorizerCreationException("Cannot provide an Initial Admin Identity and a Legacy Authorized Users File");
-            } else if (hasInitialAdminIdentity) {
+            if (hasInitialAdminIdentity) {
                 logger.info("Populating authorizations for Initial Admin: " + initialAdminIdentity);
                 populateInitialAdmin(authorizations);
-            } else if (hasLegacyAuthorizedUsers) {
-                logger.info("Converting " + legacyAuthorizedUsersFile + " to new authorizations model");
-                convertLegacyAuthorizedUsers(authorizations);
             }
 
             populateNodes(authorizations);
@@ -652,15 +639,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
      */
     private void parseFlow() throws SAXException {
         final FlowParser flowParser = new FlowParser();
-
-        final File flowConfigurationFile;
-        final File jsonFile = properties.getFlowConfigurationJsonFile();
-        if (jsonFile.exists()) {
-            flowConfigurationFile = jsonFile;
-        } else {
-            flowConfigurationFile = properties.getFlowConfigurationFile();
-        }
-
+        final File flowConfigurationFile = properties.getFlowConfigurationFile();
         final FlowInfo flowInfo = flowParser.parse(flowConfigurationFile);
 
         if (flowInfo != null) {
@@ -741,151 +720,6 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
         }
     }
 
-    /**
-     * Unmarshalls an existing authorized-users.xml and converts the object model to the new model.
-     *
-     * @param authorizations the current Authorizations instance that policies will be added to
-     * @throws AuthorizerCreationException if the legacy authorized users file that was provided does not exist
-     * @throws JAXBException if the legacy authorized users file that was provided could not be unmarshalled
-     */
-    private void convertLegacyAuthorizedUsers(final Authorizations authorizations) throws AuthorizerCreationException, JAXBException {
-        final File authorizedUsersFile = new File(legacyAuthorizedUsersFile);
-        if (!authorizedUsersFile.exists()) {
-            throw new AuthorizerCreationException("Legacy Authorized Users File '" + legacyAuthorizedUsersFile + "' does not exists");
-        }
-
-        final Unmarshaller unmarshaller = JAXB_USERS_CONTEXT.createUnmarshaller();
-        unmarshaller.setSchema(usersSchema);
-
-        final XMLStreamReader xsr;
-        try {
-            final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
-            xsr = provider.getStreamReader(new StreamSource(authorizedUsersFile));
-        } catch (final ProcessingException e) {
-            logger.error("Encountered an error reading authorized users file: ", e);
-            throw new JAXBException("Error reading authorized users file", e);
-        }
-        final JAXBElement<Users> element = unmarshaller.unmarshal(
-                xsr, org.apache.nifi.user.generated.Users.class);
-
-        final org.apache.nifi.user.generated.Users users = element.getValue();
-        if (users.getUser().isEmpty()) {
-            logger.info("Legacy Authorized Users File contained no users, nothing to convert");
-            return;
-        }
-
-        // get all the user DNs into a list
-        List<String> userIdentities = new ArrayList<>();
-        for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
-            userIdentities.add(IdentityMappingUtil.mapIdentity(legacyUser.getDn(), identityMappings));
-        }
-
-        // sort the list and pull out the first identity
-        Collections.sort(userIdentities);
-        final String seedIdentity = userIdentities.get(0);
-
-        // create mapping from Role to access policies
-        final Map<Role,Set<RoleAccessPolicy>> roleAccessPolicies = RoleAccessPolicy.getMappings(rootGroupId);
-
-        final List<Policy> allPolicies = new ArrayList<>();
-
-        for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
-            // create the identifier of the new user based on the DN
-            final String legacyUserDn = IdentityMappingUtil.mapIdentity(legacyUser.getDn(), identityMappings);
-            final User user = userGroupProvider.getUserByIdentity(legacyUserDn);
-            if (user == null) {
-                throw new AuthorizerCreationException("Unable to locate legacy user " + legacyUserDn + " to seed policies.");
-            }
-
-            // create policies based on the given role
-            for (org.apache.nifi.user.generated.Role jaxbRole : legacyUser.getRole()) {
-                Role role = Role.valueOf(jaxbRole.getName());
-                Set<RoleAccessPolicy> policies = roleAccessPolicies.get(role);
-
-                for (RoleAccessPolicy roleAccessPolicy : policies) {
-
-                    // get the matching policy, or create a new one
-                    Policy policy = getOrCreatePolicy(
-                            allPolicies,
-                            seedIdentity,
-                            roleAccessPolicy.getResource(),
-                            roleAccessPolicy.getAction());
-
-                    // add the user to the policy if it doesn't exist
-                    addUserToPolicy(user.getIdentifier(), policy);
-                }
-            }
-
-        }
-
-        // convert any access controls on ports to the appropriate policies
-        for (PortDTO portDTO : ports) {
-            final Resource resource;
-            if (portDTO.getType() != null && portDTO.getType().equals("inputPort")) {
-                resource = ResourceFactory.getDataTransferResource(ResourceFactory.getComponentResource(ResourceType.InputPort, portDTO.getId(), portDTO.getName()));
-            } else {
-                resource = ResourceFactory.getDataTransferResource(ResourceFactory.getComponentResource(ResourceType.OutputPort, portDTO.getId(), portDTO.getName()));
-            }
-
-            if (portDTO.getUserAccessControl() != null) {
-                for (String userAccessControl : portDTO.getUserAccessControl()) {
-                    // need to perform the identity mapping on the access control so it matches the identities in the User objects
-                    final String mappedUserAccessControl = IdentityMappingUtil.mapIdentity(userAccessControl, identityMappings);
-                    final User foundUser = userGroupProvider.getUserByIdentity(mappedUserAccessControl);
-
-                    // couldn't find the user matching the access control so log a warning and skip
-                    if (foundUser == null) {
-                        logger.warn("Found port with user access control for {} but no user exists with this identity, skipping...",
-                                new Object[] {mappedUserAccessControl});
-                        continue;
-                    }
-
-                    // we found the user so create the appropriate policy and add the user to it
-                    Policy policy = getOrCreatePolicy(
-                            allPolicies,
-                            seedIdentity,
-                            resource.getIdentifier(),
-                            WRITE_CODE);
-
-                    addUserToPolicy(foundUser.getIdentifier(), policy);
-                }
-            }
-
-            if (portDTO.getGroupAccessControl() != null) {
-                for (String groupAccessControl : portDTO.getGroupAccessControl()) {
-                    final String legacyGroupName = IdentityMappingUtil.mapIdentity(groupAccessControl, groupMappings);
-
-                    // find a group where the name is the groupAccessControl
-                    Group foundGroup = null;
-                    for (Group group : userGroupProvider.getGroups()) {
-                        if (group.getName().equals(legacyGroupName)) {
-                            foundGroup = group;
-                            break;
-                        }
-                    }
-
-                    // couldn't find the group matching the access control so log a warning and skip
-                    if (foundGroup == null) {
-                        logger.warn("Found port with group access control for {} but no group exists with this name, skipping...",
-                                new Object[] {legacyGroupName});
-                        continue;
-                    }
-
-                    // we found the group so create the appropriate policy and add all the users to it
-                    Policy policy = getOrCreatePolicy(
-                            allPolicies,
-                            seedIdentity,
-                            resource.getIdentifier(),
-                            WRITE_CODE);
-
-                    addGroupToPolicy(IdentifierUtil.getIdentifier(legacyGroupName), policy);
-                }
-            }
-        }
-
-        authorizations.getPolicies().getPolicy().addAll(allPolicies);
-    }
-
     /**
      * Creates and adds an access policy for the given resource, identity, and actions to the specified authorizations.
      *
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
index 3700cf0c23..052f7d5f22 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
@@ -39,8 +39,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
     private static final String FILE_USER_GROUP_PROVIDER_ID = "file-user-group-provider";
     private static final String FILE_ACCESS_POLICY_PROVIDER_ID = "file-access-policy-provider";
 
-    static final String PROP_LEGACY_AUTHORIZED_USERS_FILE = "Legacy Authorized Users File";
-
     private FileUserGroupProvider userGroupProvider = new FileUserGroupProvider();
     private FileAccessPolicyProvider accessPolicyProvider = new FileAccessPolicyProvider();
 
@@ -93,9 +91,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         if (configurationProperties.containsKey(FileUserGroupProvider.PROP_TENANTS_FILE)) {
             userGroupProperties.put(FileUserGroupProvider.PROP_TENANTS_FILE, configurationProperties.get(FileUserGroupProvider.PROP_TENANTS_FILE));
         }
-        if (configurationProperties.containsKey(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)) {
-            userGroupProperties.put(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE, configurationProperties.get(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE));
-        }
 
         // relay the relevant config
         final Map<String, String> accessPolicyProperties = new HashMap<>();
@@ -106,9 +101,6 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
         if (configurationProperties.containsKey(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)) {
             accessPolicyProperties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY, configurationProperties.get(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY));
         }
-        if (configurationProperties.containsKey(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)) {
-            accessPolicyProperties.put(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE, configurationProperties.get(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE));
-        }
 
         // ensure all node identities are seeded into the user provider
         configurationProperties.forEach((property, value) -> {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
index 855e80a331..5e39ff4657 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
@@ -116,7 +116,6 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
     private NiFiProperties properties;
     private File tenantsFile;
     private File restoreTenantsFile;
-    private String legacyAuthorizedUsersFile;
     private Set<String> initialUserIdentities;
     private List<IdentityMapping> identityMappings;
     private List<IdentityMapping> groupMappings;
@@ -178,10 +177,6 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
             identityMappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
             groupMappings = Collections.unmodifiableList(IdentityMappingUtil.getGroupMappings(properties));
 
-            // get the value of the legacy authorized users file
-            final PropertyValue legacyAuthorizedUsersProp = configurationContext.getProperty(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE);
-            legacyAuthorizedUsersFile = legacyAuthorizedUsersProp.isSet() ? legacyAuthorizedUsersProp.getValue() : null;
-
             // extract any node identities
             initialUserIdentities = new HashSet<>();
             for (Map.Entry<String,String> entry : configurationContext.getProperties().entrySet()) {
@@ -692,14 +687,8 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
 
         final UserGroupHolder userGroupHolder = new UserGroupHolder(tenants);
         final boolean emptyTenants = userGroupHolder.getAllUsers().isEmpty() && userGroupHolder.getAllGroups().isEmpty();
-        final boolean hasLegacyAuthorizedUsers = (legacyAuthorizedUsersFile != null && !StringUtils.isBlank(legacyAuthorizedUsersFile));
 
         if (emptyTenants) {
-            if (hasLegacyAuthorizedUsers) {
-                logger.info("Loading users from legacy model " + legacyAuthorizedUsersFile + " into new users file.");
-                convertLegacyAuthorizedUsers(tenants);
-            }
-
             populateInitialUsers(tenants);
 
             // save any changes that were made and repopulate the holder
@@ -740,55 +729,6 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
         }
     }
 
-    /**
-     * Unmarshalls an existing authorized-users.xml and converts the object model to the new model.
-     *
-     * @param tenants the current Tenants instance users and groups will be added to
-     * @throws AuthorizerCreationException if the legacy authorized users file that was provided does not exist
-     * @throws JAXBException if the legacy authorized users file that was provided could not be unmarshalled
-     */
-    private void convertLegacyAuthorizedUsers(final Tenants tenants) throws AuthorizerCreationException, JAXBException {
-        final File authorizedUsersFile = new File(legacyAuthorizedUsersFile);
-        if (!authorizedUsersFile.exists()) {
-            throw new AuthorizerCreationException("Legacy Authorized Users File '" + legacyAuthorizedUsersFile + "' does not exists");
-        }
-
-        final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
-        final XMLStreamReader xsr;
-        try {
-            xsr = provider.getStreamReader(new StreamSource(authorizedUsersFile));
-        } catch (final ProcessingException e) {
-            throw new AuthorizerCreationException("Error converting the legacy authorizers file", e);
-        }
-
-        final Unmarshaller unmarshaller = JAXB_USERS_CONTEXT.createUnmarshaller();
-        unmarshaller.setSchema(usersSchema);
-
-        final JAXBElement<org.apache.nifi.user.generated.Users> element = unmarshaller.unmarshal(
-                xsr, org.apache.nifi.user.generated.Users.class);
-
-        final org.apache.nifi.user.generated.Users users = element.getValue();
-        if (users.getUser().isEmpty()) {
-            logger.info("Legacy Authorized Users File contained no users, nothing to convert");
-            return;
-        }
-
-        for (org.apache.nifi.user.generated.User legacyUser : users.getUser()) {
-            // create the identifier of the new user based on the DN
-            final String legacyUserDn = IdentityMappingUtil.mapIdentity(legacyUser.getDn(), identityMappings);
-            org.apache.nifi.authorization.file.tenants.generated.User user = getOrCreateUser(tenants, legacyUserDn);
-
-            // if there was a group name find or create the group and add the user to it
-            if (StringUtils.isNotBlank(legacyUser.getGroup())) {
-                final String legacyGroupName = IdentityMappingUtil.mapIdentity(legacyUser.getGroup(), groupMappings);
-                org.apache.nifi.authorization.file.tenants.generated.Group group = getOrCreateGroup(tenants, legacyGroupName);
-                org.apache.nifi.authorization.file.tenants.generated.Group.User groupUser = new org.apache.nifi.authorization.file.tenants.generated.Group.User();
-                groupUser.setIdentifier(user.getIdentifier());
-                group.getUser().add(groupUser);
-            }
-        }
-    }
-
     /**
      * Finds the User with the given identity, or creates a new one and adds it to the Tenants.
      *
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
index 2c60e59d27..c4f487a18d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAccessPolicyProviderTest.java
@@ -16,12 +16,11 @@
  */
 package org.apache.nifi.authorization;
 
-import org.apache.nifi.parameter.ParameterLookup;
 import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
 import org.apache.nifi.authorization.exception.AuthorizerCreationException;
-import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.parameter.ParameterLookup;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.util.file.FileUtils;
 import org.junit.jupiter.api.AfterEach;
@@ -36,7 +35,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -146,7 +144,6 @@ public class FileAccessPolicyProviderTest {
     private File restoreAuthorizations;
     private File restoreTenants;
     private File flow;
-    private File flowJson;
     private File flowNoPorts;
     private File flowWithDns;
 
@@ -170,21 +167,18 @@ public class FileAccessPolicyProviderTest {
         restoreTenants = new File("target/restore/users.xml");
         FileUtils.ensureDirectoryExistAndCanAccess(restoreTenants.getParentFile());
 
-        flow = new File("src/test/resources/flow.xml.gz");
+        flow = new File("src/test/resources/flow.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flow.getParentFile());
 
-        flowJson = new File("src/test/resources/flow.json.gz");
-
-        flowNoPorts = new File("src/test/resources/flow-no-ports.xml.gz");
+        flowNoPorts = new File("src/test/resources/flow-no-ports.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flowNoPorts.getParentFile());
 
-        flowWithDns = new File("src/test/resources/flow-with-dns.xml.gz");
+        flowWithDns = new File("src/test/resources/flow-with-dns.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flowWithDns.getParentFile());
 
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
         when(properties.getFlowConfigurationFile()).thenReturn(flow);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
 
         userGroupProvider = new FileUserGroupProvider();
         userGroupProvider.setNiFiProperties(properties);
@@ -196,7 +190,6 @@ public class FileAccessPolicyProviderTest {
             ParameterLookup.EMPTY));
         when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_TENANTS_FILE))).thenReturn(new StandardPropertyValue(primaryTenants.getPath(), null, ParameterLookup.EMPTY));
         when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY))).thenReturn(new StandardPropertyValue(null, null, ParameterLookup.EMPTY));
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE))).thenReturn(new StandardPropertyValue(null, null, ParameterLookup.EMPTY));
         when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_USER_GROUP_PROVIDER))).thenReturn(new StandardPropertyValue("user-group-provider", null,
             ParameterLookup.EMPTY));
         when(configurationContext.getProperties()).then((invocation) -> {
@@ -212,11 +205,6 @@ public class FileAccessPolicyProviderTest {
                 properties.put(FileUserGroupProvider.PROP_TENANTS_FILE, tenantFile.getValue());
             }
 
-            final PropertyValue legacyAuthFile = configurationContext.getProperty(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE);
-            if (legacyAuthFile != null) {
-                properties.put(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE, legacyAuthFile.getValue());
-            }
-
             final PropertyValue initialAdmin = configurationContext.getProperty(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY);
             if (initialAdmin != null) {
                 properties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY, initialAdmin.getValue());
@@ -280,262 +268,6 @@ public class FileAccessPolicyProviderTest {
         deleteFile(restoreTenants);
     }
 
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithOverlappingRoles() throws Exception {
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-multirole.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        userGroupProvider.onConfigured(configurationContext);
-        accessPolicyProvider.onConfigured(configurationContext);
-
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.Flow.getValue(), RequestAction.READ));
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.READ));
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.WRITE));
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.System.getValue(), RequestAction.READ));
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.READ));
-        assertNotNull(accessPolicyProvider.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.WRITE));
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedAndFlowHasNoPorts() throws Exception {
-        properties = mock(NiFiProperties.class);
-        when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(flowNoPorts);
-
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        userGroupProvider.onConfigured(configurationContext);
-        accessPolicyProvider.onConfigured(configurationContext);
-
-        boolean foundDataTransferPolicy = false;
-        for (AccessPolicy policy : accessPolicyProvider.getAccessPolicies()) {
-            if (policy.getResource().contains(ResourceType.DataTransfer.name())) {
-                foundDataTransferPolicy = true;
-                break;
-            }
-        }
-
-        assertFalse(foundDataTransferPolicy);
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        userGroupProvider.onConfigured(configurationContext);
-        accessPolicyProvider.onConfigured(configurationContext);
-
-        final User user1 = userGroupProvider.getUserByIdentity("user1");
-        final User user2 = userGroupProvider.getUserByIdentity("user2");
-        final User user3 = userGroupProvider.getUserByIdentity("user3");
-        final User user4 = userGroupProvider.getUserByIdentity("user4");
-        final User user5 = userGroupProvider.getUserByIdentity("user5");
-        final User user6 = userGroupProvider.getUserByIdentity("user6");
-
-        // verify one group got created
-        final Set<Group> groups = userGroupProvider.getGroups();
-        final Group group1 = groups.iterator().next();
-
-        // verify more than one policy got created
-        final Set<AccessPolicy> policies = accessPolicyProvider.getAccessPolicies();
-        assertTrue(policies.size() > 0);
-
-        // verify user1's policies
-        final Map<String,Set<RequestAction>> user1Policies = getResourceActions(policies, user1);
-        assertEquals(4, user1Policies.size());
-
-        assertTrue(user1Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user1Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user1Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user1Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(1, user1Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user1Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        // verify user2's policies
-        final Map<String,Set<RequestAction>> user2Policies = getResourceActions(policies, user2);
-        assertEquals(3, user2Policies.size());
-
-        assertTrue(user2Policies.containsKey(ResourceType.Provenance.getValue()));
-        assertEquals(1, user2Policies.get(ResourceType.Provenance.getValue()).size());
-        assertTrue(user2Policies.get(ResourceType.Provenance.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user2Policies.containsKey(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID));
-        assertEquals(1, user2Policies.get(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID).size());
-        assertTrue(user2Policies.get(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        assertTrue(user2Policies.containsKey(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID));
-        assertEquals(1, user2Policies.get(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID).size());
-        assertTrue(user2Policies.get(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        // verify user3's policies
-        final Map<String,Set<RequestAction>> user3Policies = getResourceActions(policies, user3);
-        assertEquals(6, user3Policies.size());
-
-        assertTrue(user3Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user3Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user3Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user3Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(2, user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.WRITE));
-
-        // verify user4's policies
-        final Map<String,Set<RequestAction>> user4Policies = getResourceActions(policies, user4);
-        assertEquals(6, user4Policies.size());
-
-        assertTrue(user4Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user4Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user4Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(1, user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        assertTrue(user4Policies.containsKey(ResourceType.Tenant.getValue()));
-        assertEquals(2, user4Policies.get(ResourceType.Tenant.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Tenant.getValue()).contains(RequestAction.WRITE));
-
-        assertTrue(user4Policies.containsKey(ResourceType.Policy.getValue()));
-        assertEquals(2, user4Policies.get(ResourceType.Policy.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Policy.getValue()).contains(RequestAction.WRITE));
-
-        // verify user5's policies
-        final Map<String,Set<RequestAction>> user5Policies = getResourceActions(policies, user5);
-        assertEquals(2, user5Policies.size());
-
-        assertTrue(user5Policies.containsKey(ResourceType.Proxy.getValue()));
-        assertEquals(1, user5Policies.get(ResourceType.Proxy.getValue()).size());
-        assertTrue(user5Policies.get(ResourceType.Proxy.getValue()).contains(RequestAction.WRITE));
-
-        // verify user6's policies
-        final Map<String,Set<RequestAction>> user6Policies = getResourceActions(policies, user6);
-        assertEquals(3, user6Policies.size());
-
-        assertTrue(user6Policies.containsKey(ResourceType.SiteToSite.getValue()));
-        assertEquals(1, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
-        assertTrue(user6Policies.get(ResourceType.SiteToSite.getValue()).contains(RequestAction.READ));
-
-        final Resource inputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.InputPort, "2f7d1606-b090-4be7-a592-a5b70fb55531", "TCP Input"));
-        final AccessPolicy inputPortPolicy = accessPolicyProvider.getAccessPolicy(inputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(inputPortPolicy);
-        assertEquals(1, inputPortPolicy.getUsers().size());
-        assertTrue(inputPortPolicy.getUsers().contains(user6.getIdentifier()));
-        assertEquals(1, inputPortPolicy.getGroups().size());
-        assertTrue(inputPortPolicy.getGroups().contains(group1.getIdentifier()));
-
-        final Resource outputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.OutputPort, "2f7d1606-b090-4be7-a592-a5b70fb55532", "TCP Output"));
-        final AccessPolicy outputPortPolicy = accessPolicyProvider.getAccessPolicy(outputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(outputPortPolicy);
-        assertEquals(1, outputPortPolicy.getUsers().size());
-        assertTrue(outputPortPolicy.getUsers().contains(user4.getIdentifier()));
-    }
-
-    private Map<String,Set<RequestAction>> getResourceActions(final Set<AccessPolicy> policies, final User user) {
-        Map<String,Set<RequestAction>> resourceActionMap = new HashMap<>();
-
-        for (AccessPolicy accessPolicy : policies) {
-            if (accessPolicy.getUsers().contains(user.getIdentifier())) {
-                Set<RequestAction> actions = resourceActionMap.get(accessPolicy.getResource());
-                if (actions == null) {
-                    actions = new HashSet<>();
-                    resourceActionMap.put(accessPolicy.getResource(), actions);
-                }
-                actions.add(accessPolicy.getAction());
-            }
-        }
-
-        return resourceActionMap;
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithIdentityMappings() throws Exception {
-        final Properties props = new Properties();
-        props.setProperty("nifi.security.identity.mapping.pattern.dn1", "^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$");
-        props.setProperty("nifi.security.identity.mapping.value.dn1", "$1");
-
-        properties = getNiFiProperties(props);
-        when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(flowWithDns);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
-
-        userGroupProvider.setNiFiProperties(properties);
-        accessPolicyProvider.setNiFiProperties(properties);
-
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-with-dns.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        userGroupProvider.onConfigured(configurationContext);
-        accessPolicyProvider.onConfigured(configurationContext);
-
-        final User user4 = userGroupProvider.getUserByIdentity("user4");
-        final User user6 = userGroupProvider.getUserByIdentity("user6");
-
-        // verify one group got created
-        final Set<Group> groups = userGroupProvider.getGroups();
-        final Group group1 = groups.iterator().next();
-
-        final Resource inputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.InputPort, "2f7d1606-b090-4be7-a592-a5b70fb55531", "TCP Input"));
-        final AccessPolicy inputPortPolicy = accessPolicyProvider.getAccessPolicy(inputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(inputPortPolicy);
-        assertEquals(1, inputPortPolicy.getUsers().size());
-        assertTrue(inputPortPolicy.getUsers().contains(user6.getIdentifier()));
-        assertEquals(1, inputPortPolicy.getGroups().size());
-        assertTrue(inputPortPolicy.getGroups().contains(group1.getIdentifier()));
-
-        final Resource outputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.OutputPort, "2f7d1606-b090-4be7-a592-a5b70fb55532", "TCP Output"));
-        final AccessPolicy outputPortPolicy = accessPolicyProvider.getAccessPolicy(outputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(outputPortPolicy);
-        assertEquals(1, outputPortPolicy.getUsers().size());
-        assertTrue(outputPortPolicy.getUsers().contains(user4.getIdentifier()));
-    }
-
-    @Test
-    public void testOnConfiguredWhenBadLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/does-not-exist.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        assertThrows(AuthorizerCreationException.class,
-                () -> accessPolicyProvider.onConfigured(configurationContext));
-    }
-
-    @Test
-    public void testOnConfiguredWhenInitialAdminAndLegacyUsersProvided() throws Exception {
-        final String adminIdentity = "admin-user";
-        when(configurationContext.getProperty(eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)))
-                .thenReturn(new StandardPropertyValue(adminIdentity, null, ParameterLookup.EMPTY));
-
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        assertThrows(AuthorizerCreationException.class,
-                () -> accessPolicyProvider.onConfigured(configurationContext));
-    }
-
     @Test
     public void testOnConfiguredWhenInitialAdminNotProvided() throws Exception {
         writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
@@ -586,8 +318,7 @@ public class FileAccessPolicyProviderTest {
         // setup NiFi properties to return a file that does not exist
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.xml.gz"));
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
+        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.json.gz"));
 
         userGroupProvider.setNiFiProperties(properties);
         accessPolicyProvider.setNiFiProperties(properties);
@@ -627,8 +358,7 @@ public class FileAccessPolicyProviderTest {
         // setup NiFi properties to return a file that does not exist
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(null);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
+        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.json.gz"));
 
         userGroupProvider.setNiFiProperties(properties);
         accessPolicyProvider.setNiFiProperties(properties);
@@ -672,7 +402,6 @@ public class FileAccessPolicyProviderTest {
         properties = getNiFiProperties(props);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
         when(properties.getFlowConfigurationFile()).thenReturn(flow);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
 
         userGroupProvider.setNiFiProperties(properties);
         accessPolicyProvider.setNiFiProperties(properties);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
index 85aa1410d3..b567325554 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
@@ -17,19 +17,19 @@
 package org.apache.nifi.authorization;
 
 import org.apache.commons.lang3.SystemUtils;
-import org.apache.nifi.parameter.ParameterLookup;
 import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
 import org.apache.nifi.authorization.AuthorizationResult.Result;
 import org.apache.nifi.authorization.exception.AuthorizerCreationException;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.parameter.ParameterLookup;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.util.file.FileUtils;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assumptions;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
@@ -40,7 +40,6 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -157,7 +156,6 @@ public class FileAuthorizerTest {
     private File restoreAuthorizations;
     private File restoreTenants;
     private File flow;
-    private File flowJson;
     private File flowNoPorts;
     private File flowWithDns;
 
@@ -186,21 +184,18 @@ public class FileAuthorizerTest {
         restoreTenants = new File("target/restore/users.xml");
         FileUtils.ensureDirectoryExistAndCanAccess(restoreTenants.getParentFile());
 
-        flow = new File("src/test/resources/flow.xml.gz");
+        flow = new File("src/test/resources/flow.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flow.getParentFile());
 
-        flowJson = new File("src/test/resources/flow.json.gz");
-
-        flowNoPorts = new File("src/test/resources/flow-no-ports.xml.gz");
+        flowNoPorts = new File("src/test/resources/flow-no-ports.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flowNoPorts.getParentFile());
 
-        flowWithDns = new File("src/test/resources/flow-with-dns.xml.gz");
+        flowWithDns = new File("src/test/resources/flow-with-dns.json.gz");
         FileUtils.ensureDirectoryExistAndCanAccess(flowWithDns.getParentFile());
 
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
         when(properties.getFlowConfigurationFile()).thenReturn(flow);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
 
         configurationContext = mock(AuthorizerConfigurationContext.class);
         when(configurationContext.getProperty(Mockito.eq(FileAccessPolicyProvider.PROP_AUTHORIZATIONS_FILE))).thenReturn(new StandardPropertyValue(primaryAuthorizations.getPath(), null,
@@ -219,11 +214,6 @@ public class FileAuthorizerTest {
                 properties.put(FileUserGroupProvider.PROP_TENANTS_FILE, tenantFile.getValue());
             }
 
-            final PropertyValue legacyAuthFile = configurationContext.getProperty(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE);
-            if (legacyAuthFile != null) {
-                properties.put(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE, legacyAuthFile.getValue());
-            }
-
             final PropertyValue initialAdmin = configurationContext.getProperty(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY);
             if (initialAdmin != null) {
                 properties.put(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY, initialAdmin.getValue());
@@ -256,294 +246,6 @@ public class FileAuthorizerTest {
         deleteFile(restoreTenants);
     }
 
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithOverlappingRoles() throws Exception {
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-multirole.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        authorizer.onConfigured(configurationContext);
-
-        final Set<User> users = authorizer.getUsers();
-        assertEquals(1, users.size());
-
-        UsersAndAccessPolicies usersAndAccessPolicies = authorizer.getUsersAndAccessPolicies();
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Flow.getValue(), RequestAction.READ));
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.READ));
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.WRITE));
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.System.getValue(), RequestAction.READ));
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.READ));
-        assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.WRITE));
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedAndFlowHasNoPorts() throws Exception {
-        properties = mock(NiFiProperties.class);
-        when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(flowNoPorts);
-
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        authorizer.onConfigured(configurationContext);
-
-        boolean foundDataTransferPolicy = false;
-        for (AccessPolicy policy : authorizer.getAccessPolicies()) {
-            if (policy.getResource().contains(ResourceType.DataTransfer.name())) {
-                foundDataTransferPolicy = true;
-                break;
-            }
-        }
-
-        assertFalse(foundDataTransferPolicy);
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        authorizer.onConfigured(configurationContext);
-
-        // verify all users got created correctly
-        final Set<User> users = authorizer.getUsers();
-        assertEquals(6, users.size());
-
-        final User user1 = authorizer.getUserByIdentity("user1");
-        assertNotNull(user1);
-
-        final User user2 = authorizer.getUserByIdentity("user2");
-        assertNotNull(user2);
-
-        final User user3 = authorizer.getUserByIdentity("user3");
-        assertNotNull(user3);
-
-        final User user4 = authorizer.getUserByIdentity("user4");
-        assertNotNull(user4);
-
-        final User user5 = authorizer.getUserByIdentity("user5");
-        assertNotNull(user5);
-
-        final User user6 = authorizer.getUserByIdentity("user6");
-        assertNotNull(user6);
-
-        // verify one group got created
-        final Set<Group> groups = authorizer.getGroups();
-        assertEquals(1, groups.size());
-        final Group group1 = groups.iterator().next();
-        assertEquals("group1", group1.getName());
-
-        // verify more than one policy got created
-        final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
-        assertTrue(policies.size() > 0);
-
-        // verify user1's policies
-        final Map<String,Set<RequestAction>> user1Policies = getResourceActions(policies, user1);
-        assertEquals(4, user1Policies.size());
-
-        assertTrue(user1Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user1Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user1Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user1Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(1, user1Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user1Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        // verify user2's policies
-        final Map<String,Set<RequestAction>> user2Policies = getResourceActions(policies, user2);
-        assertEquals(3, user2Policies.size());
-
-        assertTrue(user2Policies.containsKey(ResourceType.Provenance.getValue()));
-        assertEquals(1, user2Policies.get(ResourceType.Provenance.getValue()).size());
-        assertTrue(user2Policies.get(ResourceType.Provenance.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user2Policies.containsKey(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID));
-        assertEquals(1, user2Policies.get(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID).size());
-        assertTrue(user2Policies.get(ResourceType.ProvenanceData.getValue() + "/process-groups/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        assertTrue(user2Policies.containsKey(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID));
-        assertEquals(1, user2Policies.get(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID).size());
-        assertTrue(user2Policies.get(ResourceType.Data.getValue() + "/process-groups/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        // verify user3's policies
-        final Map<String,Set<RequestAction>> user3Policies = getResourceActions(policies, user3);
-        assertEquals(6, user3Policies.size());
-
-        assertTrue(user3Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user3Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user3Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user3Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(2, user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user3Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.WRITE));
-
-        // verify user4's policies
-        final Map<String,Set<RequestAction>> user4Policies = getResourceActions(policies, user4);
-        assertEquals(6, user4Policies.size());
-
-        assertTrue(user4Policies.containsKey(ResourceType.Flow.getValue()));
-        assertEquals(1, user4Policies.get(ResourceType.Flow.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Flow.getValue()).contains(RequestAction.READ));
-
-        assertTrue(user4Policies.containsKey(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID));
-        assertEquals(1, user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
-        assertTrue(user4Policies.get(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).contains(RequestAction.READ));
-
-        assertTrue(user4Policies.containsKey(ResourceType.Tenant.getValue()));
-        assertEquals(2, user4Policies.get(ResourceType.Tenant.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Tenant.getValue()).contains(RequestAction.WRITE));
-
-        assertTrue(user4Policies.containsKey(ResourceType.Policy.getValue()));
-        assertEquals(2, user4Policies.get(ResourceType.Policy.getValue()).size());
-        assertTrue(user4Policies.get(ResourceType.Policy.getValue()).contains(RequestAction.WRITE));
-
-        // verify user5's policies
-        final Map<String,Set<RequestAction>> user5Policies = getResourceActions(policies, user5);
-        assertEquals(2, user5Policies.size());
-
-        assertTrue(user5Policies.containsKey(ResourceType.Proxy.getValue()));
-        assertEquals(1, user5Policies.get(ResourceType.Proxy.getValue()).size());
-        assertTrue(user5Policies.get(ResourceType.Proxy.getValue()).contains(RequestAction.WRITE));
-
-        // verify user6's policies
-        final Map<String,Set<RequestAction>> user6Policies = getResourceActions(policies, user6);
-        assertEquals(3, user6Policies.size());
-
-        assertTrue(user6Policies.containsKey(ResourceType.SiteToSite.getValue()));
-        assertEquals(1, user6Policies.get(ResourceType.SiteToSite.getValue()).size());
-        assertTrue(user6Policies.get(ResourceType.SiteToSite.getValue()).contains(RequestAction.READ));
-
-        final Resource inputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.InputPort, "2f7d1606-b090-4be7-a592-a5b70fb55531", "TCP Input"));
-        final AccessPolicy inputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(inputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(inputPortPolicy);
-        assertEquals(1, inputPortPolicy.getUsers().size());
-        assertTrue(inputPortPolicy.getUsers().contains(user6.getIdentifier()));
-        assertEquals(1, inputPortPolicy.getGroups().size());
-        assertTrue(inputPortPolicy.getGroups().contains(group1.getIdentifier()));
-
-        final Resource outputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.OutputPort, "2f7d1606-b090-4be7-a592-a5b70fb55532", "TCP Output"));
-        final AccessPolicy outputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(outputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(outputPortPolicy);
-        assertEquals(1, outputPortPolicy.getUsers().size());
-        assertTrue(outputPortPolicy.getUsers().contains(user4.getIdentifier()));
-    }
-
-    private Map<String,Set<RequestAction>> getResourceActions(final Set<AccessPolicy> policies, final User user) {
-        Map<String,Set<RequestAction>> resourceActionMap = new HashMap<>();
-
-        for (AccessPolicy accessPolicy : policies) {
-            if (accessPolicy.getUsers().contains(user.getIdentifier())) {
-                Set<RequestAction> actions = resourceActionMap.get(accessPolicy.getResource());
-                if (actions == null) {
-                    actions = new HashSet<>();
-                    resourceActionMap.put(accessPolicy.getResource(), actions);
-                }
-                actions.add(accessPolicy.getAction());
-            }
-        }
-
-        return resourceActionMap;
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithIdentityMappings() throws Exception {
-        final Properties props = new Properties();
-        props.setProperty("nifi.security.identity.mapping.pattern.dn1", "^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$");
-        props.setProperty("nifi.security.identity.mapping.value.dn1", "$1");
-
-        props.setProperty("nifi.security.group.mapping.pattern.anygroup", "^(.*)$");
-        props.setProperty("nifi.security.group.mapping.value.anygroup", "$1");
-        props.setProperty("nifi.security.group.mapping.transform.anygroup", "UPPER");
-
-        properties = getNiFiProperties(props);
-        when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(flowWithDns);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
-        authorizer.setNiFiProperties(properties);
-
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-with-dns.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        authorizer.onConfigured(configurationContext);
-
-        final User user1 = authorizer.getUserByIdentity("user1");
-        assertNotNull(user1);
-
-        final User user2 = authorizer.getUserByIdentity("user2");
-        assertNotNull(user2);
-
-        final User user3 = authorizer.getUserByIdentity("user3");
-        assertNotNull(user3);
-
-        final User user4 = authorizer.getUserByIdentity("user4");
-        assertNotNull(user4);
-
-        final User user5 = authorizer.getUserByIdentity("user5");
-        assertNotNull(user5);
-
-        final User user6 = authorizer.getUserByIdentity("user6");
-        assertNotNull(user6);
-
-        // verify one group got created
-        final Set<Group> groups = authorizer.getGroups();
-        assertEquals(1, groups.size());
-        final Group group1 = groups.iterator().next();
-        assertEquals("GROUP1", group1.getName());
-
-        final Resource inputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.InputPort, "2f7d1606-b090-4be7-a592-a5b70fb55531", "TCP Input"));
-        final AccessPolicy inputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(inputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(inputPortPolicy);
-        assertEquals(1, inputPortPolicy.getUsers().size());
-        assertTrue(inputPortPolicy.getUsers().contains(user6.getIdentifier()));
-        assertEquals(1, inputPortPolicy.getGroups().size());
-        assertTrue(inputPortPolicy.getGroups().contains(group1.getIdentifier()));
-
-        final Resource outputPortResource = ResourceFactory.getDataTransferResource(
-                ResourceFactory.getComponentResource(ResourceType.OutputPort, "2f7d1606-b090-4be7-a592-a5b70fb55532", "TCP Output"));
-        final AccessPolicy outputPortPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(outputPortResource.getIdentifier(), RequestAction.WRITE);
-        assertNotNull(outputPortPolicy);
-        assertEquals(1, outputPortPolicy.getUsers().size());
-        assertTrue(outputPortPolicy.getUsers().contains(user4.getIdentifier()));
-    }
-
-    @Test
-    public void testOnConfiguredWhenBadLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/does-not-exist.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        assertThrows(AuthorizerCreationException.class,
-                () -> authorizer.onConfigured(configurationContext));
-    }
-
-    @Test
-    public void testOnConfiguredWhenInitialAdminAndLegacyUsersProvided() throws Exception {
-        final String adminIdentity = "admin-user";
-        when(configurationContext.getProperty(Mockito.eq(FileAccessPolicyProvider.PROP_INITIAL_ADMIN_IDENTITY)))
-                .thenReturn(new StandardPropertyValue(adminIdentity, null, ParameterLookup.EMPTY));
-
-        when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        assertThrows(AuthorizerCreationException.class,
-                () -> authorizer.onConfigured(configurationContext));
-    }
-
     @Test
     public void testOnConfiguredWhenInitialAdminNotProvided() throws Exception {
         writeFile(primaryAuthorizations, EMPTY_AUTHORIZATIONS_CONCISE);
@@ -595,8 +297,7 @@ public class FileAuthorizerTest {
         // setup NiFi properties to return a file that does not exist
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.xml.gz"));
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
+        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.json.gz"));
         authorizer.setNiFiProperties(properties);
 
         final String adminIdentity = "admin-user";
@@ -634,8 +335,7 @@ public class FileAuthorizerTest {
         // setup NiFi properties to return a file that does not exist
         properties = mock(NiFiProperties.class);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
-        when(properties.getFlowConfigurationFile()).thenReturn(null);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
+        when(properties.getFlowConfigurationFile()).thenReturn(new File("src/test/resources/does-not-exist.json.gz"));
         authorizer.setNiFiProperties(properties);
 
         final String adminIdentity = "admin-user";
@@ -677,7 +377,6 @@ public class FileAuthorizerTest {
         properties = getNiFiProperties(props);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
         when(properties.getFlowConfigurationFile()).thenReturn(flow);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
         authorizer.setNiFiProperties(properties);
 
         final String adminIdentity = "CN=localhost, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US";
@@ -772,7 +471,6 @@ public class FileAuthorizerTest {
         properties = getNiFiProperties(props);
         when(properties.getRestoreDirectory()).thenReturn(restoreAuthorizations.getParentFile());
         when(properties.getFlowConfigurationFile()).thenReturn(flow);
-        when(properties.getFlowConfigurationJsonFile()).thenReturn(flowJson);
         authorizer.setNiFiProperties(properties);
 
         final String adminIdentity = "CN=user1, OU=Apache NiFi, O=Apache, L=Santa Monica, ST=CA, C=US";
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
index 6bcae42c8e..3dac3ff76d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileUserGroupProviderTest.java
@@ -111,7 +111,6 @@ public class FileUserGroupProviderTest {
         when(properties.getRestoreDirectory()).thenReturn(restoreTenants.getParentFile());
 
         configurationContext = mock(AuthorizerConfigurationContext.class);
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE))).thenReturn(new StandardPropertyValue(null, null, ParameterLookup.EMPTY));
         when(configurationContext.getProperty(eq(FileUserGroupProvider.PROP_TENANTS_FILE))).thenReturn(new StandardPropertyValue(primaryTenants.getPath(), null, ParameterLookup.EMPTY));
         when(configurationContext.getProperties()).then((invocation) -> {
             final Map<String, String> properties = new HashMap<>();
@@ -121,11 +120,6 @@ public class FileUserGroupProviderTest {
                 properties.put(FileUserGroupProvider.PROP_TENANTS_FILE, tenantFile.getValue());
             }
 
-            final PropertyValue legacyAuthFile = configurationContext.getProperty(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE);
-            if (legacyAuthFile != null) {
-                properties.put(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE, legacyAuthFile.getValue());
-            }
-
             int i = 1;
             while (true) {
                 final String key = FileUserGroupProvider.PROP_INITIAL_USER_IDENTITY_PREFIX + i++;
@@ -151,141 +145,6 @@ public class FileUserGroupProviderTest {
         deleteFile(restoreTenants);
     }
 
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        userGroupProvider.onConfigured(configurationContext);
-
-        // verify all users got created correctly
-        final Set<User> users = userGroupProvider.getUsers();
-        assertEquals(6, users.size());
-
-        final User user1 = userGroupProvider.getUserByIdentity("user1");
-        assertNotNull(user1);
-
-        final User user2 = userGroupProvider.getUserByIdentity("user2");
-        assertNotNull(user2);
-
-        final User user3 = userGroupProvider.getUserByIdentity("user3");
-        assertNotNull(user3);
-
-        final User user4 = userGroupProvider.getUserByIdentity("user4");
-        assertNotNull(user4);
-
-        final User user5 = userGroupProvider.getUserByIdentity("user5");
-        assertNotNull(user5);
-
-        final User user6 = userGroupProvider.getUserByIdentity("user6");
-        assertNotNull(user6);
-
-        // verify one group got created
-        final Set<Group> groups = userGroupProvider.getGroups();
-        assertEquals(1, groups.size());
-        final Group group1 = groups.iterator().next();
-        assertEquals("group1", group1.getName());
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithIdentityMappings() throws Exception {
-        final Properties props = new Properties();
-        props.setProperty("nifi.security.identity.mapping.pattern.dn1", "^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$");
-        props.setProperty("nifi.security.identity.mapping.value.dn1", "$1");
-
-        properties = getNiFiProperties(props);
-        when(properties.getRestoreDirectory()).thenReturn(restoreTenants.getParentFile());
-        userGroupProvider.setNiFiProperties(properties);
-
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-with-dns.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        userGroupProvider.onConfigured(configurationContext);
-
-        final User user1 = userGroupProvider.getUserByIdentity("user1");
-        assertNotNull(user1);
-
-        final User user2 = userGroupProvider.getUserByIdentity("user2");
-        assertNotNull(user2);
-
-        final User user3 = userGroupProvider.getUserByIdentity("user3");
-        assertNotNull(user3);
-
-        final User user4 = userGroupProvider.getUserByIdentity("user4");
-        assertNotNull(user4);
-
-        final User user5 = userGroupProvider.getUserByIdentity("user5");
-        assertNotNull(user5);
-
-        final User user6 = userGroupProvider.getUserByIdentity("user6");
-        assertNotNull(user6);
-
-        // verify one group got created
-        final Set<Group> groups = userGroupProvider.getGroups();
-        assertEquals(1, groups.size());
-        final Group group1 = groups.iterator().next();
-        assertEquals("group1", group1.getName());
-    }
-
-    @Test
-    public void testOnConfiguredWhenLegacyUsersFileProvidedWithIdentityMappingsAndTransforms() throws Exception {
-        final Properties props = new Properties();
-        props.setProperty("nifi.security.identity.mapping.pattern.dn1", "^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$");
-        props.setProperty("nifi.security.identity.mapping.value.dn1", "$1");
-        props.setProperty("nifi.security.identity.mapping.transform.dn1", "UPPER");
-
-        props.setProperty("nifi.security.group.mapping.pattern.anygroup", "^(.*)$");
-        props.setProperty("nifi.security.group.mapping.value.anygroup", "$1");
-        props.setProperty("nifi.security.group.mapping.transform.anygroup", "UPPER");
-
-        properties = getNiFiProperties(props);
-        when(properties.getRestoreDirectory()).thenReturn(restoreTenants.getParentFile());
-        userGroupProvider.setNiFiProperties(properties);
-
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/authorized-users-with-dns.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-        userGroupProvider.onConfigured(configurationContext);
-
-        final User user1 = userGroupProvider.getUserByIdentity("USER1");
-        assertNotNull(user1);
-
-        final User user2 = userGroupProvider.getUserByIdentity("USER2");
-        assertNotNull(user2);
-
-        final User user3 = userGroupProvider.getUserByIdentity("USER3");
-        assertNotNull(user3);
-
-        final User user4 = userGroupProvider.getUserByIdentity("USER4");
-        assertNotNull(user4);
-
-        final User user5 = userGroupProvider.getUserByIdentity("USER5");
-        assertNotNull(user5);
-
-        final User user6 = userGroupProvider.getUserByIdentity("USER6");
-        assertNotNull(user6);
-
-        // verify one group got created
-        final Set<Group> groups = userGroupProvider.getGroups();
-        assertEquals(1, groups.size());
-        final Group group1 = groups.iterator().next();
-        assertEquals("GROUP1", group1.getName());
-    }
-
-    @Test
-    public void testOnConfiguredWhenBadLegacyUsersFileProvided() throws Exception {
-        when(configurationContext.getProperty(eq(FileAuthorizer.PROP_LEGACY_AUTHORIZED_USERS_FILE)))
-                .thenReturn(new StandardPropertyValue("src/test/resources/does-not-exist.xml", null, ParameterLookup.EMPTY));
-
-        writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
-
-        assertThrows(AuthorizerCreationException.class,
-                () -> userGroupProvider.onConfigured(configurationContext));
-    }
-
     @Test
     public void testOnConfiguredWhenInitialUsersNotProvided() throws Exception {
         writeFile(primaryTenants, EMPTY_TENANTS_CONCISE);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.json.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.json.gz
new file mode 100644
index 0000000000..02f95c2f28
Binary files /dev/null and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.json.gz differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.xml.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.xml.gz
deleted file mode 100644
index 95cca27554..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-no-ports.xml.gz and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.json.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.json.gz
new file mode 100644
index 0000000000..02f95c2f28
Binary files /dev/null and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.json.gz differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.xml.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.xml.gz
deleted file mode 100644
index e4b4ed6440..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-dns.xml.gz and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.json.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.json.gz
new file mode 100644
index 0000000000..02f95c2f28
Binary files /dev/null and b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.json.gz differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.xml.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.xml.gz
deleted file mode 100644
index 95cca27554..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow.xml.gz and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
index 30cce26b5c..fecaf1857c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
@@ -60,7 +60,7 @@ public class StandardDataFlow implements Serializable, DataFlow {
      * Constructs an instance.
      *
      * @param flow a valid flow as bytes, which cannot be null
-     * @param snippetBytes an XML representation of snippets.  May be null.
+     * @param snippetBytes a JSON representation of snippets. May be null.
      * @param authorizerFingerprint the bytes of the Authorizer's fingerprint. May be null when using an external Authorizer.
      * @param missingComponentIds the ids of components that were created as missing ghost components
      *
@@ -161,12 +161,4 @@ public class StandardDataFlow implements Serializable, DataFlow {
             throw new FlowSerializationException("Could not parse flow as a VersionedDataflow", e);
         }
     }
-
-    public boolean isXml() {
-        if (flow == null || flow.length == 0) {
-            return true;
-        }
-
-        return flow[0] == '<';
-    }
 }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
index 5e88021d09..201b4c367d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/flow/PopularVoteFlowElection.java
@@ -20,7 +20,7 @@ package org.apache.nifi.cluster.coordination.flow;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.nifi.cluster.protocol.DataFlow;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
-import org.apache.nifi.controller.serialization.StandardFlowSynchronizer;
+import org.apache.nifi.controller.serialization.VersionedFlowSynchronizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -239,7 +239,7 @@ public class PopularVoteFlowElection implements FlowElection {
         }
 
         public boolean isFlowEmpty() {
-            return StandardFlowSynchronizer.isFlowEmpty(dataFlow);
+            return VersionedFlowSynchronizer.isFlowEmpty(dataFlow);
         }
 
         public Set<NodeIdentifier> getNodes() {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
index 6270a14211..4c4b612587 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/flow/TestPopularVoteFlowElection.java
@@ -40,7 +40,7 @@ public class TestPopularVoteFlowElection {
     @Test
     public void testOnlyEmptyFlows() throws IOException {
         final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 3);
-        final byte[] flow = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.xml"));
+        final byte[] flow = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.json"));
 
         assertFalse(election.isElectionComplete());
         assertNull(election.getElectedDataFlow());
@@ -62,8 +62,8 @@ public class TestPopularVoteFlowElection {
     @Test
     public void testDifferentEmptyFlows() throws IOException {
         final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 3);
-        final byte[] flow1 = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.xml"));
-        final byte[] flow2 = Files.readAllBytes(Paths.get("src/test/resources/conf/different-empty-flow.xml"));
+        final byte[] flow1 = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.json"));
+        final byte[] flow2 = Files.readAllBytes(Paths.get("src/test/resources/conf/different-empty-flow.json"));
 
         assertFalse(election.isElectionComplete());
         assertNull(election.getElectedDataFlow());
@@ -87,8 +87,8 @@ public class TestPopularVoteFlowElection {
     @Test
     public void testEmptyFlowIgnoredIfNonEmptyFlowExists() throws IOException {
         final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 8);
-        final byte[] emptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.xml"));
-        final byte[] nonEmptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/non-empty-flow.xml"));
+        final byte[] emptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/empty-flow.json"));
+        final byte[] nonEmptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/non-empty-flow.json"));
 
         for (int i = 0; i < 8; i++) {
             assertFalse(election.isElectionComplete());
@@ -114,8 +114,8 @@ public class TestPopularVoteFlowElection {
     @Test
     public void testAutoGeneratedVsPopulatedFlowElection() throws IOException {
         final PopularVoteFlowElection election = new PopularVoteFlowElection(1, TimeUnit.MINUTES, 4);
-        final byte[] emptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/auto-generated-empty-flow.xml"));
-        final byte[] nonEmptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/reporting-task-flow.xml"));
+        final byte[] emptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/auto-generated-empty-flow.json"));
+        final byte[] nonEmptyFlow = Files.readAllBytes(Paths.get("src/test/resources/conf/reporting-task-flow.json"));
 
         for (int i = 0; i < 4; i++) {
             assertFalse(election.isElectionComplete());
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.json
new file mode 100644
index 0000000000..cd3d6db07a
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.json
@@ -0,0 +1 @@
+{"encodingVersion":{"majorVersion":2,"minorVersion":0},"maxTimerDrivenThreadCount":10,"registries":[],"parameterContexts":[],"parameterProviders":[],"controllerServices":[],"reportingTasks":[],"templates":[],"rootGroup":{"identifier":"0bc6db14-095b-392d-a063-0df1646ddf72","instanceIdentifier":"ee207cce-015d-1000-30bf-36cd2fd1ea5c","name":"NiFi Flow","comments":"","position":{"x":0.0,"y":0.0},"processGroups":[],"remoteProcessGroups":[],"processors":[],"inputPorts":[],"outputPorts":[],"con [...]
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.xml
deleted file mode 100644
index 720fc0b4d9..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/auto-generated-empty-flow.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  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.
--->
-<flowController encoding-version="1.1">
-    <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-    <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-    <rootGroup>
-        <id>ee207cce-015d-1000-30bf-36cd2fd1ea5c</id>
-        <name>NiFi Flow</name>
-        <position x="0.0" y="0.0"/>
-        <comment/>
-    </rootGroup>
-    <controllerServices/>
-    <reportingTasks/>
-</flowController>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.json
new file mode 100644
index 0000000000..b6fcf18abc
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.json
@@ -0,0 +1,64 @@
+{
+  "encodingVersion": {
+    "majorVersion": 2,
+    "minorVersion": 0
+  },
+  "maxTimerDrivenThreadCount": 10,
+  "registries": [],
+  "parameterContexts": [],
+  "parameterProviders": [],
+  "controllerServices": [],
+  "reportingTasks": [],
+  "templates": [],
+  "rootGroup": {
+    "identifier": "3ddb274d-5d53-3a68-8db3-1e95b702852d",
+    "instanceIdentifier": "778f676e-6542-4c18-9d06-24b6fd3a1b29",
+    "name": "NiFi Flow",
+    "position": {
+      "x": 0,
+      "y": 0
+    },
+    "processGroups": [],
+    "remoteProcessGroups": [],
+    "processors": [],
+    "inputPorts": [],
+    "outputPorts": [],
+    "connections": [],
+    "labels": [],
+    "funnels": [],
+    "controllerServices": [
+      {
+        "identifier": "e5c9d095-39ab-311a-80a7-260efcdd0498",
+        "instanceIdentifier": "edf22ee5-376a-46dc-a38a-919351124457",
+        "name": "ControllerService",
+        "comments": "",
+        "type": "org.apache.nifi.controller.service.mock.ServiceD",
+        "bundle": {
+          "group": "default",
+          "artifact": "unknown",
+          "version": "unversioned"
+        },
+        "properties": {
+          "Foo1": "enc{265708cd5e497f7581a37f48445f634879020a73382e2e761cc55587b8a2e55170774348}"
+        },
+        "propertyDescriptors": {},
+        "controllerServiceApis": [],
+        "scheduledState": "DISABLED",
+        "bulletinLevel": "WARN",
+        "componentType": "CONTROLLER_SERVICE",
+        "groupIdentifier": "3ddb274d-5d53-3a68-8db3-1e95b702852d"
+      }
+    ],
+    "variables": {},
+    "defaultFlowFileExpiration": "0 sec",
+    "defaultBackPressureObjectThreshold": 10000,
+    "defaultBackPressureDataSizeThreshold": "1 GB",
+    "scheduledState": "ENABLED",
+    "executionEngine": "INHERITED",
+    "maxConcurrentTasks": 1,
+    "statelessFlowTimeout": "1 min",
+    "componentType": "PROCESS_GROUP",
+    "flowFileConcurrency": "UNBOUNDED",
+    "flowFileOutboundPolicy": "STREAM_WHEN_AVAILABLE"
+  }
+}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.xml
deleted file mode 100644
index 4278311558..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/controller-service-flow.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  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.
--->
-<flowController>
-    <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-    <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-    <rootGroup>
-        <id>778f676e-6542-4c18-9d06-24b6fd3a1b29</id>
-        <name>NiFi Flow</name>
-        <position x="0.0" y="0.0"/>
-    </rootGroup>
-    <controllerServices>
-        <controllerService>
-            <id>edf22ee5-376a-46dc-a38a-919351124457</id>
-            <name>ControllerService</name>
-            <comment/>
-            <class>org.apache.nifi.controller.service.mock.ServiceD</class>
-            <enabled>false</enabled>
-            <property>
-                <name>Foo1</name>
-                <value>Bar1</value>
-            </property>
-        </controllerService>
-    </controllerServices>
-</flowController>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.json
new file mode 100644
index 0000000000..32c5a55521
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.json
@@ -0,0 +1 @@
+{"encodingVersion":{"majorVersion":2,"minorVersion":0},"maxTimerDrivenThreadCount":10,"registries":[],"parameterContexts":[],"parameterProviders":[],"controllerServices":[],"reportingTasks":[],"templates":[],"rootGroup":{"identifier":"38c6cbd2-8bf1-3507-8d07-0980dd1fb595","instanceIdentifier":"11111111-1111-1111-1111-111111111111","name":"Empty NiFi Flow","comments":"","position":{"x":0.0,"y":0.0},"processGroups":[],"remoteProcessGroups":[],"processors":[],"inputPorts":[],"outputPorts":[ [...]
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml
deleted file mode 100644
index 8c9641ae25..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/different-empty-flow.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  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.
--->
-<flowController encoding-version="1.0">
-  <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-  <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-  <rootGroup>
-    <id>11111111-1111-1111-1111-111111111111</id>
-    <name>Empty NiFi Flow</name>
-    <position x="0.0" y="0.0"/>
-    <comment/>
-  </rootGroup>
-  <controllerServices/>
-  <reportingTasks/>
-</flowController>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.json
new file mode 100644
index 0000000000..76c2f69b01
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.json
@@ -0,0 +1 @@
+{"encodingVersion":{"majorVersion":2,"minorVersion":0},"maxTimerDrivenThreadCount":10,"registries":[],"parameterContexts":[],"parameterProviders":[],"controllerServices":[],"reportingTasks":[],"templates":[],"rootGroup":{"identifier":"9f89c84a-559f-3736-b6a4-7ff8daed0d33","instanceIdentifier":"00000000-0000-0000-0000-000000000000","name":"Empty NiFi Flow","comments":"","position":{"x":0.0,"y":0.0},"processGroups":[],"remoteProcessGroups":[],"processors":[],"inputPorts":[],"outputPorts":[ [...]
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.xml
deleted file mode 100644
index c0cb6de05d..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/empty-flow.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  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.
--->
-<flowController encoding-version="1.0">
-  <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-  <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-  <rootGroup>
-    <id>00000000-0000-0000-0000-000000000000</id>
-    <name>Empty NiFi Flow</name>
-    <position x="0.0" y="0.0"/>
-    <comment/>
-  </rootGroup>
-  <controllerServices/>
-  <reportingTasks/>
-</flowController>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/nifi.properties
index d3170ef316..dc5764fee0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/nifi.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/nifi.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.json
new file mode 100644
index 0000000000..ac9f0e063f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.json
@@ -0,0 +1 @@
+{"encodingVersion":{"majorVersion":2,"minorVersion":0},"maxTimerDrivenThreadCount":10,"registries":[],"parameterContexts":[],"parameterProviders":[],"controllerServices":[],"reportingTasks":[],"templates":[],"rootGroup":{"identifier":"9f89c84a-559f-3736-b6a4-7ff8daed0d33","instanceIdentifier":"00000000-0000-0000-0000-000000000000","name":"Integration Test Flow","comments":"","position":{"x":0.0,"y":0.0},"processGroups":[],"remoteProcessGroups":[],"processors":[],"inputPorts":[],"outputPo [...]
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.xml
deleted file mode 100644
index ed5451d625..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/non-empty-flow.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<!--
-  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.
--->
-<flowController>
-  <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-  <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-  <rootGroup>
-    <id>00000000-0000-0000-0000-000000000000</id>
-    <name>Integration Test Flow</name>
-    <position x="0.0" y="0.0"/>
-    <comment/>
-    <parameterContextId>1234</parameterContextId>
-  </rootGroup>
-</flowController>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.json
new file mode 100644
index 0000000000..e25ce454f6
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.json
@@ -0,0 +1 @@
+{"encodingVersion":{"majorVersion":2,"minorVersion":0},"maxTimerDrivenThreadCount":10,"registries":[],"parameterContexts":[],"parameterProviders":[],"controllerServices":[],"reportingTasks":[{"identifier":"3b80ba0f-a6c0-48db-b721-4dbc04cef28e","instanceIdentifier":"3b80ba0f-a6c0-48db-b721-4dbc04cef28e","name":"AmbariReportingTask","comments":"","type":"org.apache.nifi.reporting.ambari.AmbariReportingTask","bundle":{"group":"org.apache.nifi","artifact":"nifi-standard-nar","version":"1.1.0 [...]
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.xml
deleted file mode 100644
index 751517c33d..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/resources/conf/reporting-task-flow.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  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.
--->
-<flowController>
-    <maxTimerDrivenThreadCount>10</maxTimerDrivenThreadCount>
-    <maxEventDrivenThreadCount>5</maxEventDrivenThreadCount>
-    <rootGroup>
-        <id>7c84501d-d10c-407c-b9f3-1d80e38fe36a</id>
-        <name>NiFi Flow</name>
-        <position x="0.0" y="0.0"/>
-        <comment/>
-    </rootGroup>
-    <controllerServices/>
-    <reportingTasks>
-        <reportingTask>
-            <id>3b80ba0f-a6c0-48db-b721-4dbc04cef28e</id>
-            <name>AmbariReportingTask</name>
-            <comment/>
-            <class>org.apache.nifi.reporting.ambari.AmbariReportingTask</class>
-            <bundle>
-                <group>org.apache.nifi</group>
-                <artifact>nifi-standard-nar</artifact>
-                <version>1.1.0</version>
-            </bundle>
-            <schedulingPeriod>{{nifi_ambari_reporting_frequency}}</schedulingPeriod>
-            <scheduledState>RUNNING</scheduledState>
-            <schedulingStrategy>TIMER_DRIVEN</schedulingStrategy>
-            <property>
-                <name>Metrics Collector URL</name>
-                <value>${ambari.metrics.collector.url}</value>
-            </property>
-            <property>
-                <name>Application ID</name>
-                <value>${ambari.application.id}</value>
-            </property>
-            <property>
-                <name>Hostname</name>
-                <value>${hostname(true)}</value>
-            </property>
-        </reportingTask>
-    </reportingTasks>
-</flowController>
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
index 63385c879f..eb6f97037e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java
@@ -1472,7 +1472,7 @@ public class StandardVersionedComponentSynchronizer implements VersionedComponen
                 return decryptor.decrypt(value.substring(ENC_PREFIX.length(), value.length() - ENC_SUFFIX.length()));
             } catch (EncryptionException e) {
                 final String moreDescriptiveMessage = "There was a problem decrypting a sensitive flow configuration value. " +
-                        "Check that the nifi.sensitive.props.key value in nifi.properties matches the value used to encrypt the flow.xml.gz file";
+                        "Check that the nifi.sensitive.props.key value in nifi.properties matches the value used to encrypt the flow.json.gz file";
                 throw new EncryptionException(moreDescriptiveMessage, e);
             }
         } else {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/resources/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/resources/conf/nifi.properties
index c2bf7dfcad..c3971d803b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/resources/conf/nifi.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/resources/conf/nifi.properties
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Core Properties #
-nifi.flow.configuration.file=./target/flow.xml.gz
+nifi.flow.configuration.file=./target/flow.json.gz
 nifi.flow.configuration.archive.dir=./target/archive/
 nifi.flowcontroller.autoResumeState=true
 nifi.flowcontroller.graceful.shutdown.period=10 sec
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java
index 854cc7999d..238d48cba9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/cluster/protocol/DataFlow.java
@@ -50,9 +50,4 @@ public interface DataFlow {
      * @return the component ids of components that were created as a missing ghost component
      */
     Set<String> getMissingComponents();
-
-    /**
-     * @return <code>true</code> if the contents are empty or are made up of XML, <code>false</code> if the contents are JSON
-     */
-    boolean isXml();
 }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/remote/PublicPort.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/remote/PublicPort.java
index fdd5653313..83012a05b0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/remote/PublicPort.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/remote/PublicPort.java
@@ -23,8 +23,6 @@ import org.apache.nifi.remote.exception.NotAuthorizedException;
 import org.apache.nifi.remote.exception.RequestExpiredException;
 import org.apache.nifi.remote.protocol.ServerProtocol;
 
-import java.util.Set;
-
 /**
  * Represents an input or output port that can receive or transfer data via Site-to-Site protocol.
  */
@@ -32,14 +30,6 @@ public interface PublicPort extends Port {
 
     boolean isTransmitting();
 
-    void setGroupAccessControl(Set<String> groups);
-
-    Set<String> getGroupAccessControl();
-
-    void setUserAccessControl(Set<String> users);
-
-    Set<String> getUserAccessControl();
-
     /**
      * Verifies that the specified user is authorized to interact with this port
      * and returns a {@link PortAuthorizationResult} indicating why the user is
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/services/FlowService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/services/FlowService.java
index 8d69550d0f..02cd20e86e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/services/FlowService.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/services/FlowService.java
@@ -86,7 +86,7 @@ public interface FlowService extends LifeCycle {
     void copyCurrentFlow(OutputStream os) throws IOException;
 
     /**
-     * Copies the contents of the current flow.xml.gz to the given file, overwriting the file if it exists
+     * Copies the contents of the current flow.json.gz to the given file, overwriting the file if it exists
      * @param file the file to write the current flow to
      * @throws IOException if unable to read the current flow or unable to write to the given file
      */
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowSerializationStrategy.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowSerializationStrategy.java
deleted file mode 100644
index d5e0f162e0..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/FlowSerializationStrategy.java
+++ /dev/null
@@ -1,31 +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.controller;
-
-public enum FlowSerializationStrategy {
-    WRITE_XML_ONLY,
-    WRITE_JSON_ONLY,
-    WRITE_XML_AND_JSON;
-
-    public boolean writesJson() {
-        return this == WRITE_JSON_ONLY || this == WRITE_XML_AND_JSON;
-    }
-
-    public boolean writesXml() {
-        return this == WRITE_XML_ONLY || this == WRITE_XML_AND_JSON;
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
index 26f835a08c..b1c9f06035 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
@@ -52,7 +52,7 @@ import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.controller.flow.FlowManager;
 import org.apache.nifi.controller.serialization.FlowSerializationException;
 import org.apache.nifi.controller.serialization.FlowSynchronizationException;
-import org.apache.nifi.controller.serialization.StandardFlowSynchronizer;
+import org.apache.nifi.controller.serialization.VersionedFlowSynchronizer;
 import org.apache.nifi.controller.status.ProcessGroupStatus;
 import org.apache.nifi.engine.FlowEngine;
 import org.apache.nifi.events.BulletinFactory;
@@ -111,7 +111,7 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
     private final boolean autoResumeState;
     private final Authorizer authorizer;
 
-    // Lock is used to protect the flow.xml file.
+    // Lock is used to protect the flow.json.gz file.
     private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
     private final Lock readLock = rwLock.readLock();
     private final Lock writeLock = rwLock.writeLock();
@@ -150,11 +150,9 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
             final FlowController controller,
             final NiFiProperties nifiProperties,
             final RevisionManager revisionManager,
-            final Authorizer authorizer,
-            final FlowSerializationStrategy serializationStrategy) throws IOException {
+            final Authorizer authorizer) throws IOException {
 
-        return new StandardFlowService(controller, nifiProperties, null, false, null, revisionManager, authorizer,
-                serializationStrategy);
+        return new StandardFlowService(controller, nifiProperties, null, false, null, revisionManager, authorizer);
     }
 
     public static StandardFlowService createClusteredInstance(
@@ -165,8 +163,7 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
             final RevisionManager revisionManager,
             final Authorizer authorizer) throws IOException {
 
-        return new StandardFlowService(controller, nifiProperties, senderListener, true, coordinator, revisionManager, authorizer,
-                FlowSerializationStrategy.WRITE_XML_AND_JSON);
+        return new StandardFlowService(controller, nifiProperties, senderListener, true, coordinator, revisionManager, authorizer);
     }
 
     private StandardFlowService(
@@ -176,17 +173,15 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
             final boolean configuredForClustering,
             final ClusterCoordinator clusterCoordinator,
             final RevisionManager revisionManager,
-            final Authorizer authorizer,
-            final FlowSerializationStrategy serializationStrategy) throws IOException {
+            final Authorizer authorizer) throws IOException {
 
         this.nifiProperties = nifiProperties;
         this.controller = controller;
 
-
         gracefulShutdownSeconds = (int) FormatUtils.getTimeDuration(nifiProperties.getProperty(NiFiProperties.FLOW_CONTROLLER_GRACEFUL_SHUTDOWN_PERIOD), TimeUnit.SECONDS);
         autoResumeState = nifiProperties.getAutoResumeState();
 
-        dao = new StandardFlowConfigurationDAO(nifiProperties, controller.getExtensionManager(), serializationStrategy);
+        dao = new StandardFlowConfigurationDAO(nifiProperties, controller.getExtensionManager());
         this.clusterCoordinator = clusterCoordinator;
         if (clusterCoordinator != null) {
             clusterCoordinator.setFlowService(this);
@@ -465,7 +460,7 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
              * the response will be null and we should load the local dataflow
              * and heartbeat until a manager is located.
              */
-            final boolean localFlowEmpty = StandardFlowSynchronizer.isFlowEmpty(proposedFlow);
+            final boolean localFlowEmpty = VersionedFlowSynchronizer.isFlowEmpty(proposedFlow);
             final ConnectionResponse response = connect(true, localFlowEmpty, proposedFlow);
 
             // obtain write lock while we are updating the controller. We need to ensure that we don't
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSnippet.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSnippet.java
index a1b6b5c74c..244a1e1ba5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSnippet.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowSnippet.java
@@ -46,7 +46,6 @@ import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.processor.StandardProcessContext;
 import org.apache.nifi.registry.flow.StandardVersionControlInformation;
 import org.apache.nifi.registry.flow.VersionControlInformation;
-import org.apache.nifi.remote.PublicPort;
 import org.apache.nifi.remote.StandardRemoteProcessGroupPortDescriptor;
 import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
 import org.apache.nifi.scheduling.ExecutionNode;
@@ -309,12 +308,6 @@ public class StandardFlowSnippet implements FlowSnippet {
             if (group.isRootGroup() || Boolean.TRUE.equals(portDTO.getAllowRemoteAccess())) {
                 final String portName = generatePublicInputPortName(flowManager, portDTO.getName());
                 inputPort = flowManager.createPublicInputPort(portDTO.getId(), portName);
-                if (portDTO.getGroupAccessControl() != null) {
-                    ((PublicPort) inputPort).setGroupAccessControl(portDTO.getGroupAccessControl());
-                }
-                if (portDTO.getUserAccessControl() != null) {
-                    ((PublicPort) inputPort).setUserAccessControl(portDTO.getUserAccessControl());
-                }
             } else {
                 inputPort = flowManager.createLocalInputPort(portDTO.getId(), portDTO.getName());
             }
@@ -337,12 +330,6 @@ public class StandardFlowSnippet implements FlowSnippet {
             if (group.isRootGroup() || Boolean.TRUE.equals(portDTO.getAllowRemoteAccess())) {
                 final String portName = generatePublicOutputPortName(flowManager, portDTO.getName());
                 outputPort = flowManager.createPublicOutputPort(portDTO.getId(), portName);
-                if (portDTO.getGroupAccessControl() != null) {
-                    ((PublicPort) outputPort).setGroupAccessControl(portDTO.getGroupAccessControl());
-                }
-                if (portDTO.getUserAccessControl() != null) {
-                    ((PublicPort) outputPort).setUserAccessControl(portDTO.getUserAccessControl());
-                }
             } else {
                 outputPort = flowManager.createLocalOutputPort(portDTO.getId(), portDTO.getName());
             }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/XmlFlowSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/XmlFlowSynchronizer.java
deleted file mode 100644
index c29b9b5695..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/XmlFlowSynchronizer.java
+++ /dev/null
@@ -1,1981 +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.controller;
-
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.AuthorizerCapabilityDetection;
-import org.apache.nifi.authorization.ManagedAuthorizer;
-import org.apache.nifi.bundle.BundleCoordinate;
-import org.apache.nifi.cluster.protocol.DataFlow;
-import org.apache.nifi.cluster.protocol.StandardDataFlow;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.connectable.Connectable;
-import org.apache.nifi.connectable.ConnectableType;
-import org.apache.nifi.connectable.Connection;
-import org.apache.nifi.connectable.Funnel;
-import org.apache.nifi.connectable.Port;
-import org.apache.nifi.connectable.Position;
-import org.apache.nifi.connectable.Size;
-import org.apache.nifi.controller.flow.FlowManager;
-import org.apache.nifi.controller.flowanalysis.FlowAnalysisRuleInstantiationException;
-import org.apache.nifi.controller.inheritance.AuthorizerCheck;
-import org.apache.nifi.controller.inheritance.BundleCompatibilityCheck;
-import org.apache.nifi.controller.inheritance.ConnectionMissingCheck;
-import org.apache.nifi.controller.inheritance.FlowFingerprintCheck;
-import org.apache.nifi.controller.inheritance.FlowInheritability;
-import org.apache.nifi.controller.inheritance.FlowInheritabilityCheck;
-import org.apache.nifi.controller.inheritance.MissingComponentsCheck;
-import org.apache.nifi.controller.label.Label;
-import org.apache.nifi.controller.queue.LoadBalanceCompression;
-import org.apache.nifi.controller.queue.LoadBalanceStrategy;
-import org.apache.nifi.controller.reporting.ReportingTaskInstantiationException;
-import org.apache.nifi.controller.serialization.FlowEncodingVersion;
-import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
-import org.apache.nifi.controller.serialization.FlowSerializationException;
-import org.apache.nifi.controller.serialization.FlowSynchronizationException;
-import org.apache.nifi.controller.serialization.FlowSynchronizer;
-import org.apache.nifi.controller.serialization.StandardFlowSerializer;
-import org.apache.nifi.controller.service.ControllerServiceLoader;
-import org.apache.nifi.controller.service.ControllerServiceNode;
-import org.apache.nifi.controller.service.ControllerServiceProvider;
-import org.apache.nifi.controller.service.ControllerServiceState;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.events.BulletinFactory;
-import org.apache.nifi.flowanalysis.FlowAnalysisRuleState;
-import org.apache.nifi.flowanalysis.EnforcementPolicy;
-import org.apache.nifi.flowfile.FlowFilePrioritizer;
-import org.apache.nifi.groups.BundleUpdateStrategy;
-import org.apache.nifi.groups.FlowFileConcurrency;
-import org.apache.nifi.groups.FlowFileOutboundPolicy;
-import org.apache.nifi.groups.ProcessGroup;
-import org.apache.nifi.groups.RemoteProcessGroup;
-import org.apache.nifi.groups.RemoteProcessGroupPortDescriptor;
-import org.apache.nifi.logging.LogLevel;
-import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.parameter.Parameter;
-import org.apache.nifi.parameter.ParameterContext;
-import org.apache.nifi.parameter.ParameterContextManager;
-import org.apache.nifi.parameter.ParameterDescriptor;
-import org.apache.nifi.parameter.ParameterProviderConfiguration;
-import org.apache.nifi.parameter.StandardParameterProviderConfiguration;
-import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.registry.flow.FlowRegistryClientNode;
-import org.apache.nifi.registry.flow.StandardVersionControlInformation;
-import org.apache.nifi.registry.flow.VersionedFlowState;
-import org.apache.nifi.remote.PublicPort;
-import org.apache.nifi.remote.RemoteGroupPort;
-import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
-import org.apache.nifi.reporting.Severity;
-import org.apache.nifi.scheduling.ExecutionNode;
-import org.apache.nifi.scheduling.SchedulingStrategy;
-import org.apache.nifi.services.FlowService;
-import org.apache.nifi.util.BundleUtils;
-import org.apache.nifi.util.DomUtils;
-import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.util.file.FileUtils;
-import org.apache.nifi.web.api.dto.BundleDTO;
-import org.apache.nifi.web.api.dto.ComponentReferenceDTO;
-import org.apache.nifi.web.api.dto.ConnectableDTO;
-import org.apache.nifi.web.api.dto.ConnectionDTO;
-import org.apache.nifi.web.api.dto.ControllerServiceDTO;
-import org.apache.nifi.web.api.dto.FlowAnalysisRuleDTO;
-import org.apache.nifi.web.api.dto.FlowRegistryClientDTO;
-import org.apache.nifi.web.api.dto.FlowSnippetDTO;
-import org.apache.nifi.web.api.dto.FunnelDTO;
-import org.apache.nifi.web.api.dto.LabelDTO;
-import org.apache.nifi.web.api.dto.ParameterContextDTO;
-import org.apache.nifi.web.api.dto.ParameterDTO;
-import org.apache.nifi.web.api.dto.ParameterProviderConfigurationDTO;
-import org.apache.nifi.web.api.dto.ParameterProviderDTO;
-import org.apache.nifi.web.api.dto.PortDTO;
-import org.apache.nifi.web.api.dto.PositionDTO;
-import org.apache.nifi.web.api.dto.ProcessGroupDTO;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
-import org.apache.nifi.web.api.dto.ProcessorDTO;
-import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
-import org.apache.nifi.web.api.dto.ReportingTaskDTO;
-import org.apache.nifi.web.api.dto.VersionControlInformationDTO;
-import org.apache.nifi.web.api.entity.ComponentReferenceEntity;
-import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
-import org.apache.nifi.web.api.entity.ParameterEntity;
-import org.apache.nifi.web.api.entity.ParameterProviderConfigurationEntity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.GZIPInputStream;
-
-/**
- * XML implementation of Flow Synchronizer for reading configuration using XML Document Object Model
- */
-public class XmlFlowSynchronizer implements FlowSynchronizer {
-
-    private static final Logger logger = LoggerFactory.getLogger(XmlFlowSynchronizer.class);
-    private final boolean autoResumeState;
-    private final NiFiProperties nifiProperties;
-    private final ExtensionManager extensionManager;
-
-    public XmlFlowSynchronizer(final NiFiProperties nifiProperties, final ExtensionManager extensionManager) {
-        this.autoResumeState = nifiProperties.getAutoResumeState();
-        this.nifiProperties = nifiProperties;
-        this.extensionManager = extensionManager;
-    }
-
-    @Override
-    public void sync(final FlowController controller, final DataFlow proposedFlow, final FlowService flowService, final BundleUpdateStrategy bundleUpdateStrategy)
-            throws FlowSerializationException, UninheritableFlowException, FlowSynchronizationException {
-
-        final FlowManager flowManager = controller.getFlowManager();
-        final ProcessGroup root = flowManager.getRootGroup();
-
-        // handle corner cases involving no proposed flow
-        if (proposedFlow == null) {
-            if (root.isEmpty()) {
-                return;  // no sync to perform
-            } else {
-                throw new UninheritableFlowException("Proposed configuration is empty, but the controller contains a data flow.");
-            }
-        }
-
-        // determine if the controller already had flow sync'd to it
-        final boolean flowAlreadySynchronized = controller.isFlowSynchronized();
-        logger.debug("Synching FlowController with proposed flow: Controller is Already Synchronized = {}", flowAlreadySynchronized);
-
-        // serialize controller state to bytes
-        final DataFlow existingDataFlow = getExistingDataFlow(controller);
-        boolean existingFlowEmpty = isFlowEmpty(existingDataFlow.getFlowDocument());
-
-        logger.trace("Parsing proposed flow bytes as DOM document");
-        final Document configuration = proposedFlow.getFlowDocument();
-
-        // check that the proposed flow is inheritable by the controller
-        boolean backupAndPurge = false;
-        if (existingFlowEmpty) {
-            logger.debug("Checking bundle compatibility");
-
-            final BundleCompatibilityCheck bundleCompatibilityCheck = new BundleCompatibilityCheck();
-            final FlowInheritability bundleInheritability = bundleCompatibilityCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
-            if (!bundleInheritability.isInheritable()) {
-                throw new UninheritableFlowException("Proposed flow could not be inherited because it references one or more Bundles that are not available in this NiFi instance: "
-                    + bundleInheritability.getExplanation());
-            }
-
-            logger.debug("Bundle Compatibility check passed");
-        } else {
-            logger.debug("Checking flow inheritability");
-            final FlowInheritabilityCheck fingerprintCheck = new FlowFingerprintCheck();
-            final FlowInheritability inheritability = fingerprintCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
-
-            if (inheritability.isInheritable()) {
-                logger.debug("Proposed flow is inheritable");
-            } else {
-                if (controller.isInitialized()) {
-                    // Flow has already been initialized so cannot inherit the cluster flow as liberally.
-                    // Since the cluster's flow is not immediately inheritable, we must throw an UninheritableFlowException.
-                    throw new UninheritableFlowException("Proposed configuration is not inheritable by the flow controller because of flow differences: " + inheritability.getExplanation());
-                }
-
-                logger.debug("Proposed flow is not directly inheritable. However, the Controller has not been synchronized yet, " +
-                    "so will check if the existing flow can be backed up and replaced by the proposed flow.");
-
-                final FlowInheritabilityCheck connectionMissingCheck = new ConnectionMissingCheck(null);
-                final FlowInheritability connectionMissingInheritability = connectionMissingCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
-                if (connectionMissingInheritability.isInheritable()) {
-                    backupAndPurge = true;
-                    existingFlowEmpty = true; // Consider the existing flow as being empty
-                    logger.debug("Proposed flow contains all connections that currently have data queued. Will backup existing flow and replace, provided all other checks pass");
-                } else {
-                    throw new UninheritableFlowException("Proposed flow is not inheritable by the flow controller and cannot completely replace the current flow due to: "
-                        + connectionMissingInheritability.getExplanation());
-                }
-            }
-        }
-
-        logger.debug("Checking missing component inheritability");
-        final FlowInheritabilityCheck missingComponentsCheck = new MissingComponentsCheck();
-        final FlowInheritability componentInheritability = missingComponentsCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
-        if (!componentInheritability.isInheritable()) {
-            throw new UninheritableFlowException("Proposed Flow is not inheritable by the flow controller because of differences in missing components: " + componentInheritability.getExplanation());
-        }
-        logger.debug("Missing Component Inheritability check passed");
-
-        logger.debug("Checking authorizer inheritability");
-        final FlowInheritabilityCheck authorizerCheck = new AuthorizerCheck();
-        final FlowInheritability authorizerInheritability = authorizerCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
-        final Authorizer authorizer = controller.getAuthorizer();
-
-        if (existingFlowEmpty) {
-            logger.debug("Existing flow is empty so will not check Authorizer inheritability. Authorizers will be forcibly inherited if necessary.");
-        } else {
-            if (!controller.isInitialized() && authorizer instanceof ManagedAuthorizer) {
-                logger.debug("Authorizations are not inheritable, but Authorizer is a Managed Authorizer and the Controller has not yet been initialized, so it can be forcibly inherited.");
-            } else {
-                if (!authorizerInheritability.isInheritable() && authorizerInheritability.getExplanation() != null) {
-                    throw new UninheritableFlowException("Proposed Authorizer is not inheritable by the Flow Controller because NiFi has already started the dataflow " +
-                        "and Authorizer has differences: " + authorizerInheritability.getExplanation());
-                }
-
-                logger.debug("Authorizer inheritability check passed");
-            }
-        }
-
-        // attempt to sync controller with proposed flow
-        try {
-            if (backupAndPurge) {
-                logger.warn("Proposed flow cannot be directly inherited. However, all data that is queued in this instance is queued in a connection that exists in the Proposed flow. As a " +
-                    "result, the existing flow will be backed up and replaced with the proposed flow.");
-                final File backupFile = getFlowBackupFile();
-
-                try {
-                    flowService.copyCurrentFlow(backupFile);
-                } catch (final IOException ioe) {
-                    throw new UninheritableFlowException("Could not inherit flow because failed to make a backup of existing flow to " + backupFile.getAbsolutePath(), ioe);
-                }
-
-                logger.info("Successfully created backup of existing flow to {}. Will now purge local flow and inherit proposed flow", backupFile.getAbsolutePath());
-                controller.purge();
-            }
-
-            if (!controller.isFlowSynchronized() && !existingFlowEmpty) {
-                updateThreadCounts(existingDataFlow.getFlowDocument().getDocumentElement(), controller);
-            }
-
-            if (configuration != null) {
-                updateFlow(controller, configuration, existingDataFlow, existingFlowEmpty);
-            }
-
-            inheritSnippets(controller, proposedFlow);
-
-            // if auths are inheritable and we have a policy based authorizer, then inherit
-            if (authorizer instanceof ManagedAuthorizer) {
-                final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
-                final String proposedAuthFingerprint = proposedFlow.getAuthorizerFingerprint() == null ? "" : new String(proposedFlow.getAuthorizerFingerprint(), StandardCharsets.UTF_8);
-
-                if (authorizerInheritability.isInheritable()) {
-                    logger.debug("Authorizations are inheritable. Will inherit from proposed fingerprint {}", proposedAuthFingerprint);
-                    managedAuthorizer.inheritFingerprint(proposedAuthFingerprint);
-                } else if (!Objects.equals(managedAuthorizer.getFingerprint(), proposedAuthFingerprint)) {
-                    // At this point, the flow is not inheritable, but we've made it this far. This can only happen if the existing flow is empty, so we can
-                    // just forcibly inherit the authorizations.
-                    logger.debug("Authorizations are not inheritable. Will force inheritance of proposed fingerprint {}", proposedAuthFingerprint);
-                    managedAuthorizer.forciblyInheritFingerprint(proposedAuthFingerprint);
-                }
-            }
-
-            logger.debug("Finished syncing flows");
-        } catch (final Exception ex) {
-            throw new FlowSynchronizationException(ex);
-        }
-    }
-
-    private File getFlowBackupFile() {
-        final File flowConfigurationFile = nifiProperties.getFlowConfigurationFile();
-        final String baseFilename = StringUtils.substringBeforeLast(flowConfigurationFile.getName(), ".xml.gz");
-        final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
-        final String timestamp = dateFormat.format(new Date());
-        final String backupFilename = baseFilename + "-" + timestamp + ".xml.gz";
-        final File backupFile = new File(flowConfigurationFile.getParentFile(), backupFilename);
-
-        if (!backupFile.getParentFile().exists() && !backupFile.getParentFile().mkdirs()) {
-            throw new UninheritableFlowException("Failed to backup existing flow because the configured directory for flow.xml.gz <" + backupFile.getParentFile().getAbsolutePath()
-                + "> does not exist and could not be created");
-        }
-
-        return backupFile;
-    }
-
-    private DataFlow getExistingDataFlow(final FlowController controller) {
-        final FlowManager flowManager = controller.getFlowManager();
-        final ProcessGroup root = flowManager.getRootGroup();
-
-        // Determine missing components
-        final Set<String> missingComponents = new HashSet<>();
-        flowManager.getAllControllerServices().stream().filter(ComponentNode::isExtensionMissing).forEach(cs -> missingComponents.add(cs.getIdentifier()));
-        flowManager.getAllReportingTasks().stream().filter(ComponentNode::isExtensionMissing).forEach(r -> missingComponents.add(r.getIdentifier()));
-        flowManager.getAllFlowAnalysisRules().stream().filter(ComponentNode::isExtensionMissing).forEach(r -> missingComponents.add(r.getIdentifier()));
-        flowManager.getAllParameterProviders().stream().filter(ComponentNode::isExtensionMissing).forEach(r -> missingComponents.add(r.getIdentifier()));
-        flowManager.getAllFlowRegistryClients().stream().filter(ComponentNode::isExtensionMissing).forEach(c -> missingComponents.add(c.getIdentifier()));
-        root.findAllProcessors().stream().filter(AbstractComponentNode::isExtensionMissing).forEach(p -> missingComponents.add(p.getIdentifier()));
-
-        logger.trace("Exporting snippets from controller");
-        final byte[] existingSnippets = controller.getSnippetManager().export();
-
-        final byte[] existingAuthFingerprint;
-        final Authorizer authorizer = controller.getAuthorizer();
-        if (AuthorizerCapabilityDetection.isManagedAuthorizer(authorizer)) {
-            final ManagedAuthorizer managedAuthorizer = (ManagedAuthorizer) authorizer;
-            existingAuthFingerprint = managedAuthorizer.getFingerprint().getBytes(StandardCharsets.UTF_8);
-        } else {
-            existingAuthFingerprint = null;
-        }
-
-        // serialize controller state to bytes
-        final byte[] existingFlow;
-        try {
-            if (controller.isFlowSynchronized()) {
-                existingFlow = toBytes(controller);
-                return new StandardDataFlow(existingFlow, existingSnippets, existingAuthFingerprint, missingComponents);
-            } else {
-                existingFlow = readFlowFromDisk();
-                if (existingFlow == null || existingFlow.length == 0) {
-                    return new StandardDataFlow(existingFlow, existingSnippets, existingAuthFingerprint, missingComponents);
-                } else {
-                    return new StandardDataFlow(existingFlow, existingSnippets, existingAuthFingerprint, missingComponents);
-                }
-            }
-        } catch (final IOException e) {
-            throw new FlowSerializationException(e);
-        }
-    }
-
-    private void inheritSnippets(final FlowController controller, final DataFlow proposedFlow) {
-        // clear the snippets that are currently in memory
-        logger.trace("Clearing existing snippets");
-        final SnippetManager snippetManager = controller.getSnippetManager();
-        snippetManager.clear();
-
-        // if proposed flow has any snippets, load them
-        logger.trace("Loading proposed snippets");
-        final byte[] proposedSnippets = proposedFlow.getSnippets();
-        if (proposedSnippets != null && proposedSnippets.length > 0) {
-            for (final StandardSnippet snippet : SnippetManager.parseBytes(proposedSnippets)) {
-                snippetManager.addSnippet(snippet);
-            }
-        }
-    }
-
-    private void updateFlow(
-        final FlowController controller,
-        final Document configuration,
-        final DataFlow existingFlow,
-        final boolean existingFlowEmpty
-    ) throws ReportingTaskInstantiationException, FlowAnalysisRuleInstantiationException {
-        final boolean flowAlreadySynchronized = controller.isFlowSynchronized();
-        final FlowManager flowManager = controller.getFlowManager();
-
-        final PropertyEncryptor encryptor = controller.getEncryptor();
-
-        // get the root element
-        final Element rootElement = (Element) configuration.getElementsByTagName("flowController").item(0);
-        final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(rootElement);
-
-        // set controller config
-        logger.trace("Updating flow config");
-        final Integer maxThreadCount = getInteger(rootElement, "maxThreadCount");
-        if (maxThreadCount == null) {
-            controller.setMaxTimerDrivenThreadCount(getInt(rootElement, "maxTimerDrivenThreadCount"));
-        } else {
-            controller.setMaxTimerDrivenThreadCount(maxThreadCount * 2 / 3);
-        }
-
-        // get the root group XML element
-        final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
-
-        // get all the parameter provider elements
-        final Element parameterProvidersElement = DomUtils.getChild(rootElement, "parameterProviders");
-        final List<Element> parameterProviderElements = new ArrayList<>();
-        if (parameterProvidersElement != null) {
-            parameterProviderElements.addAll(DomUtils.getChildElementsByTagName(parameterProvidersElement, "parameterProvider"));
-        }
-
-        // get/create all the parameter provider nodes and DTOs
-        final Map<ParameterProviderNode, ParameterProviderDTO> parameterProviderNodesToDTOs = new HashMap<>();
-        for (final Element taskElement : parameterProviderElements) {
-            final ParameterProviderDTO dto = FlowFromDOMFactory.getParameterProvider(taskElement, encryptor, encodingVersion);
-            final ParameterProviderNode parameterProvider = getOrCreateParameterProvider(controller, dto, flowAlreadySynchronized, existingFlowEmpty);
-            parameterProviderNodesToDTOs.put(parameterProvider, dto);
-        }
-
-        // get all the flow registry client elements
-        final Element registriesElement = DomUtils.getChild(rootElement, "registries");
-        if (registriesElement != null) {
-            for (final Element flowRegistryElement : DomUtils.getChildElementsByTagName(registriesElement, "flowRegistry")) {
-                final FlowRegistryClientDTO dto = FlowFromDOMFactory.getFlowRegistryClient(flowRegistryElement, encryptor, encodingVersion);
-                getOrCreateFlowRegistryClient(controller, dto, flowAlreadySynchronized, existingFlowEmpty);
-            }
-        }
-
-        // if this controller isn't initialized or its empty, add the root group, otherwise update
-        final ProcessGroup rootGroup;
-        if (!flowAlreadySynchronized || existingFlowEmpty) {
-            controller.getFlowManager().withParameterContextResolution(() -> {
-                final Element parameterContextsElement = DomUtils.getChild(rootElement, "parameterContexts");
-                if (parameterContextsElement != null) {
-                    final List<Element> contextElements = DomUtils.getChildElementsByTagName(parameterContextsElement, "parameterContext");
-                    for (final Element contextElement : contextElements) {
-                        final ParameterContextDTO parameterContextDto = FlowFromDOMFactory.getParameterContext(contextElement, encryptor);
-                        createParameterContext(parameterContextDto, controller.getFlowManager());
-                    }
-                }
-            });
-
-            logger.trace("Adding root process group");
-            rootGroup = addProcessGroup(controller, /* parent group */ null, rootGroupElement, encodingVersion);
-        } else {
-            logger.trace("Updating root process group");
-            rootGroup = updateProcessGroup(controller, /* parent group */ null, rootGroupElement, encodingVersion);
-        }
-
-        rootGroup.findAllRemoteProcessGroups().forEach(RemoteProcessGroup::initialize);
-
-        // get all the reporting task elements
-        final Element reportingTasksElement = DomUtils.getChild(rootElement, "reportingTasks");
-        final List<Element> reportingTaskElements = new ArrayList<>();
-        if (reportingTasksElement != null) {
-            reportingTaskElements.addAll(DomUtils.getChildElementsByTagName(reportingTasksElement, "reportingTask"));
-        }
-
-        // get/create all the reporting task nodes and DTOs, but don't apply their scheduled state yet
-        final Map<ReportingTaskNode, ReportingTaskDTO> reportingTaskNodesToDTOs = new HashMap<>();
-        for (final Element taskElement : reportingTaskElements) {
-            final ReportingTaskDTO dto = FlowFromDOMFactory.getReportingTask(taskElement, encryptor, encodingVersion);
-            final ReportingTaskNode reportingTask = getOrCreateReportingTask(controller, dto, flowAlreadySynchronized, existingFlowEmpty);
-            reportingTaskNodesToDTOs.put(reportingTask, dto);
-        }
-
-        // get all the flow analysis rule elements
-        final Element flowAnalysisRulesElement = DomUtils.getChild(rootElement, "flowAnalysisRules");
-        final List<Element> flowAnalysisRuleElements = new ArrayList<>();
-        if (flowAnalysisRulesElement != null) {
-            flowAnalysisRuleElements.addAll(DomUtils.getChildElementsByTagName(flowAnalysisRulesElement, "flowAnalysisRule"));
-        }
-
-        // get/create all the flow analysis rule nodes and DTOs, but don't apply their state yet
-        final Map<FlowAnalysisRuleNode, FlowAnalysisRuleDTO> flowAnalysisRuleNodesToDTOs = new HashMap<>();
-        for (final Element taskElement : flowAnalysisRuleElements) {
-            final FlowAnalysisRuleDTO dto = FlowFromDOMFactory.getFlowAnalysisRule(taskElement, encryptor, encodingVersion);
-            final FlowAnalysisRuleNode flowAnalysisRule = getOrCreateFlowAnalysisRule(controller, dto, flowAlreadySynchronized, existingFlowEmpty);
-            flowAnalysisRuleNodesToDTOs.put(flowAnalysisRule, dto);
-        }
-
-        final Element controllerServicesElement = DomUtils.getChild(rootElement, "controllerServices");
-        if (controllerServicesElement != null) {
-            final List<Element> serviceElements = DomUtils.getChildElementsByTagName(controllerServicesElement, "controllerService");
-
-            if (!flowAlreadySynchronized || existingFlowEmpty) {
-                // If the encoding version is null, we are loading a flow from NiFi 0.x, where Controller
-                // Services could not be scoped by Process Group. As a result, we want to move the Process Groups
-                // to the root Group. Otherwise, we want to use a null group, which indicates a Controller-level
-                // Controller Service.
-                final ProcessGroup group = (encodingVersion == null) ? rootGroup : null;
-                final Map<ControllerServiceNode, Element> controllerServices = ControllerServiceLoader.loadControllerServices(
-                    serviceElements, controller, group, encryptor, encodingVersion);
-
-                // If we are moving controller services to the root group we also need to see if any reporting tasks
-                // or flow analysis rules reference them, and if so we need to clone the CS and update the task- and rule references
-                if (group != null) {
-                    // find all the controller service ids referenced by reporting tasks and flow analysis rules
-                    final Set<String> controllerServicesInReportingTasksAndFlowAnalysisRules = Stream.concat(
-                        reportingTaskNodesToDTOs.keySet().stream(),
-                        flowAnalysisRuleNodesToDTOs.keySet().stream()
-                    )
-                        .flatMap(r -> r.getEffectivePropertyValues().entrySet().stream())
-                        .filter(e -> e.getKey().getControllerServiceDefinition() != null)
-                        .map(Map.Entry::getValue)
-                        .collect(Collectors.toSet());
-                    // find all the controller service ids referenced by parameter providers
-                    final Set<String> controllerServicesInParameterProviders = parameterProviderNodesToDTOs.keySet().stream()
-                            .flatMap(r -> r.getEffectivePropertyValues().entrySet().stream())
-                            .filter(e -> e.getKey().getControllerServiceDefinition() != null)
-                            .map(Map.Entry::getValue)
-                            .collect(Collectors.toSet());
-
-                    // find the controller service nodes for each id referenced by a reporting task or flow analysis rule
-                    final Set<ControllerServiceNode> controllerServicesToClone = controllerServices.keySet().stream()
-                        .filter(cs -> controllerServicesInReportingTasksAndFlowAnalysisRules.contains(cs.getIdentifier())
-                                || controllerServicesInParameterProviders.contains(cs.getIdentifier()))
-                        .collect(Collectors.toSet());
-
-                    // clone the controller services and map the original id to the clone
-                    final Map<String, ControllerServiceNode> controllerServiceMapping = new HashMap<>();
-                    for (ControllerServiceNode controllerService : controllerServicesToClone) {
-                        final ControllerServiceNode clone = ControllerServiceLoader.cloneControllerService(controller, controllerService);
-                        flowManager.addRootControllerService(clone);
-                        controllerServiceMapping.put(controllerService.getIdentifier(), clone);
-                    }
-
-                    // update the reporting tasks and parameter providers to reference the cloned controller services
-                    updateControllerLevelControllerServices(reportingTaskNodesToDTOs.keySet(), controllerServiceMapping);
-                    updateControllerLevelControllerServices(parameterProviderNodesToDTOs.keySet(), controllerServiceMapping);
-
-                    // enable all the cloned controller services
-                    ControllerServiceLoader.enableControllerServices(controllerServiceMapping.values(), controller, autoResumeState);
-                }
-
-                // enable all the original controller services
-                ControllerServiceLoader.enableControllerServices(controllerServices, controller, encryptor, autoResumeState, encodingVersion);
-            }
-        }
-
-        // Now that root controller services are available, attempt to fetch parameters
-        for (final ParameterProviderNode parameterProviderNode : parameterProviderNodesToDTOs.keySet()) {
-            try {
-                parameterProviderNode.fetchParameters();
-            } catch (final Exception e) {
-                logger.warn("Failed to fetch parameters for provider " + parameterProviderNode.getName(), e);
-            }
-        }
-
-        scaleRootGroup(rootGroup, encodingVersion);
-
-        // now that controller services are loaded and enabled we can apply the scheduled state to each reporting task
-        for (Map.Entry<ReportingTaskNode, ReportingTaskDTO> entry : reportingTaskNodesToDTOs.entrySet()) {
-            applyReportingTaskScheduleState(controller, entry.getValue(), entry.getKey(), flowAlreadySynchronized, existingFlowEmpty);
-        }
-
-        // now that controller services are loaded and enabled we can apply the state to each flow analysis rule
-        for (Map.Entry<FlowAnalysisRuleNode, FlowAnalysisRuleDTO> entry : flowAnalysisRuleNodesToDTOs.entrySet()) {
-            applyFlowAnalysisRuleState(controller, entry.getValue(), entry.getKey(), flowAlreadySynchronized, existingFlowEmpty);
-        }
-    }
-
-    private ParameterContext createParameterContext(final ParameterContextDTO dto, final FlowManager flowManager) {
-        final Map<String, Parameter> parameters = dto.getParameters().stream()
-            .map(ParameterEntity::getParameter)
-            .map(this::createParameter)
-            .collect(Collectors.toMap(param -> param.getDescriptor().getName(), Function.identity()));
-
-        final List<String> referencedIds = dto.getInheritedParameterContexts() == null ? Collections.emptyList()
-                : dto.getInheritedParameterContexts().stream()
-                        .map(ParameterContextReferenceEntity::getId)
-                        .collect(Collectors.toList());
-
-        ParameterProviderConfiguration parameterProviderConfiguration = null;
-        if (dto.getParameterProviderConfiguration() != null) {
-            final ParameterProviderConfigurationEntity parameterProviderConfigurationEntity = dto.getParameterProviderConfiguration();
-            final ParameterProviderConfigurationDTO configurationDTO = parameterProviderConfigurationEntity.getComponent();
-            parameterProviderConfiguration = new StandardParameterProviderConfiguration(configurationDTO.getParameterProviderId(),
-                    configurationDTO.getParameterGroupName(), configurationDTO.getSynchronized());
-        }
-        final ParameterContext context = flowManager.createParameterContext(dto.getId(), dto.getName(), parameters, referencedIds, parameterProviderConfiguration);
-        context.setDescription(dto.getDescription());
-        return context;
-    }
-
-    private Parameter createParameter(final ParameterDTO dto) {
-        final ParameterDescriptor parameterDescriptor = new ParameterDescriptor.Builder()
-            .name(dto.getName())
-            .description(dto.getDescription())
-            .sensitive(Boolean.TRUE.equals(dto.getSensitive()))
-            .build();
-
-        return new Parameter(parameterDescriptor, dto.getValue(), null, dto.getProvided());
-    }
-
-    public static String getReferenceId(final ComponentReferenceEntity referenceEntity) {
-        if (referenceEntity == null) {
-            return null;
-        }
-        final ComponentReferenceDTO dto = referenceEntity.getComponent();
-        if (dto == null) {
-            return null;
-        }
-        return dto.getId();
-    }
-
-    private void updateControllerLevelControllerServices(final Set<? extends ComponentNode> componentNodes, final Map<String, ControllerServiceNode> controllerServiceMapping) {
-        for (final ComponentNode componentNode : componentNodes) {
-            if (componentNode.getProperties() != null) {
-                componentNode.pauseValidationTrigger();
-                try {
-                    final Set<Map.Entry<PropertyDescriptor, String>> propertyDescriptors = componentNode.getEffectivePropertyValues().entrySet().stream()
-                            .filter(e -> e.getKey().getControllerServiceDefinition() != null)
-                            .filter(e -> controllerServiceMapping.containsKey(e.getValue()))
-                            .collect(Collectors.toSet());
-
-                    final Map<String,String> controllerServiceProps = new HashMap<>();
-
-                    for (Map.Entry<PropertyDescriptor, String> propEntry : propertyDescriptors) {
-                        final PropertyDescriptor propertyDescriptor = propEntry.getKey();
-                        final ControllerServiceNode clone = controllerServiceMapping.get(propEntry.getValue());
-                        controllerServiceProps.put(propertyDescriptor.getName(), clone.getIdentifier());
-                    }
-
-                    componentNode.setProperties(controllerServiceProps);
-                } finally {
-                    componentNode.resumeValidationTrigger();
-                }
-            }
-        }
-    }
-
-    void scaleRootGroup(final ProcessGroup rootGroup, final FlowEncodingVersion encodingVersion) {
-        if (encodingVersion == null || encodingVersion.getMajorVersion() < 1) {
-            // Calculate new Positions if the encoding version of the flow is older than 1.0.
-            PositionScaler.scale(rootGroup, 1.5, 1.34);
-        }
-    }
-
-    private void updateThreadCounts(final Element rootElement, final FlowController controller) {
-        logger.trace("Setting controller thread counts");
-        final Integer maxThreadCount = getInteger(rootElement, "maxThreadCount");
-        if (maxThreadCount == null) {
-            controller.setMaxTimerDrivenThreadCount(getInt(rootElement, "maxTimerDrivenThreadCount"));
-        } else {
-            controller.setMaxTimerDrivenThreadCount(maxThreadCount * 2 / 3);
-        }
-    }
-
-    public static boolean isFlowEmpty(final Document flowDocument) {
-        if (flowDocument == null) {
-            return true;
-        }
-
-        final Element rootElement = flowDocument.getDocumentElement();
-        if (rootElement == null) {
-            return true;
-        }
-
-        final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(rootElement);
-
-        final Element reportingTasksElement = DomUtils.getChild(rootElement, "reportingTasks");
-        if (reportingTasksElement != null) {
-            final List<Element> taskElements = DomUtils.getChildElementsByTagName(reportingTasksElement, "reportingTask");
-            if (!taskElements.isEmpty()) {
-                return false;
-            }
-        }
-
-        final Element flowAnalysisRulesElement = DomUtils.getChild(rootElement, "flowAnalysisRules");
-        if (flowAnalysisRulesElement != null) {
-            final List<Element> flowAnalysisRulesElements = DomUtils.getChildElementsByTagName(flowAnalysisRulesElement, "flowAnalysisRule");
-            if (!flowAnalysisRulesElements.isEmpty()) {
-                return false;
-            }
-        }
-
-        final Element parameterProvidersElement = DomUtils.getChild(rootElement, "parameterProviders");
-        if (parameterProvidersElement != null) {
-            final List<Element> providerElements = DomUtils.getChildElementsByTagName(parameterProvidersElement, "parameterProvider");
-            if (!providerElements.isEmpty()) {
-                return false;
-            }
-        }
-
-        final Element controllerServicesElement = DomUtils.getChild(rootElement, "controllerServices");
-        if (controllerServicesElement != null) {
-            final List<Element> unrootedControllerServiceElements = DomUtils.getChildElementsByTagName(controllerServicesElement, "controllerService");
-            if (!unrootedControllerServiceElements.isEmpty()) {
-                return false;
-            }
-        }
-
-        final Element registriesElement = DomUtils.getChild(rootElement, "registries");
-        if (registriesElement != null) {
-            final List<Element> flowRegistryElems = DomUtils.getChildElementsByTagName(registriesElement, "flowRegistry");
-            if (!flowRegistryElems.isEmpty()) {
-                return false;
-            }
-        }
-
-        final Element parameterContextsElement = DomUtils.getChild(rootElement, "parameterContexts");
-        if (parameterContextsElement != null) {
-            final List<Element> contextList = DomUtils.getChildElementsByTagName(parameterContextsElement, "parameterContext");
-            if (!contextList.isEmpty()) {
-                return false;
-            }
-        }
-
-        logger.trace("Parsing process group from DOM");
-        final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
-        final ProcessGroupDTO rootGroupDto = FlowFromDOMFactory.getProcessGroup(null, rootGroupElement, null, encodingVersion);
-        return isEmpty(rootGroupDto);
-    }
-
-    private static boolean isEmpty(final ProcessGroupDTO dto) {
-        if (dto == null) {
-            return true;
-        }
-
-        final FlowSnippetDTO contents = dto.getContents();
-        if (contents == null) {
-            return true;
-        }
-
-        final String parameterContextId = dto.getParameterContext() == null ? null : dto.getParameterContext().getId();
-
-        return CollectionUtils.isEmpty(contents.getProcessors())
-                && CollectionUtils.isEmpty(contents.getConnections())
-                && CollectionUtils.isEmpty(contents.getFunnels())
-                && CollectionUtils.isEmpty(contents.getLabels())
-                && CollectionUtils.isEmpty(contents.getInputPorts())
-                && CollectionUtils.isEmpty(contents.getOutputPorts())
-                && CollectionUtils.isEmpty(contents.getProcessGroups())
-                && CollectionUtils.isEmpty(contents.getRemoteProcessGroups())
-                && CollectionUtils.isEmpty(contents.getControllerServices())
-                && parameterContextId == null;
-    }
-
-
-    private byte[] readFlowFromDisk() throws IOException {
-        final Path flowPath = nifiProperties.getFlowConfigurationFile().toPath();
-        if (!Files.exists(flowPath) || Files.size(flowPath) == 0) {
-            return new byte[0];
-        }
-
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-        try (final InputStream in = Files.newInputStream(flowPath, StandardOpenOption.READ);
-                final InputStream gzipIn = new GZIPInputStream(in)) {
-            FileUtils.copy(gzipIn, baos);
-        }
-
-        return baos.toByteArray();
-    }
-
-    private ParameterProviderNode getOrCreateParameterProvider(final FlowController controller, final ParameterProviderDTO dto,
-                                                               final boolean controllerInitialized, final boolean existingFlowEmpty) {
-        // create a new parameter provider node when the controller is not initialized or the flow is empty
-        if (!controllerInitialized || existingFlowEmpty) {
-            BundleCoordinate coordinate;
-            try {
-                coordinate = BundleUtils.getCompatibleBundle(extensionManager, dto.getType(), dto.getBundle());
-            } catch (final IllegalStateException e) {
-                final BundleDTO bundleDTO = dto.getBundle();
-                if (bundleDTO == null) {
-                    coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-                } else {
-                    coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-                }
-            }
-
-            final ParameterProviderNode parameterProvider = controller.getFlowManager().createParameterProvider(dto.getType(), dto.getId(), coordinate, false);
-            parameterProvider.setName(dto.getName());
-            parameterProvider.setComments(dto.getComments());
-
-            parameterProvider.setAnnotationData(dto.getAnnotationData());
-            parameterProvider.setProperties(dto.getProperties());
-            return parameterProvider;
-        } else {
-            // otherwise, return the existing parameter provider node
-            return controller.getFlowManager().getParameterProvider(dto.getId());
-        }
-    }
-
-    private FlowRegistryClientNode getOrCreateFlowRegistryClient(final FlowController controller, final FlowRegistryClientDTO dto,
-                                                                 final boolean controllerInitialized, final boolean existingFlowEmpty) {
-        // create a new flow registry client node when the controller is not initialized or the flow is empty
-        if (!controllerInitialized || existingFlowEmpty) {
-            BundleCoordinate coordinate;
-            try {
-                coordinate = BundleUtils.getCompatibleBundle(extensionManager, dto.getType(), dto.getBundle());
-            } catch (final IllegalStateException e) {
-                final BundleDTO bundleDTO = dto.getBundle();
-                if (bundleDTO == null) {
-                    coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-                } else {
-                    coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-                }
-            }
-
-            final FlowRegistryClientNode registryClient = controller.getFlowManager().createFlowRegistryClient(dto.getType(), dto.getId(), coordinate, Collections.emptySet(), false, true, null);
-            registryClient.setName(dto.getName());
-            registryClient.setDescription(dto.getDescription());
-            registryClient.setAnnotationData(dto.getAnnotationData());
-            final Set<String> sensitiveDynamicPropertyNames = getSensitiveDynamicPropertyNames(dto.getSensitiveDynamicPropertyNames(), registryClient);
-            registryClient.setProperties(dto.getProperties(), false, sensitiveDynamicPropertyNames);
-            return registryClient;
-        } else {
-            // otherwise return the existing flow registry client node
-            return controller.getFlowManager().getFlowRegistryClient(dto.getId());
-        }
-    }
-
-    private ReportingTaskNode getOrCreateReportingTask(final FlowController controller, final ReportingTaskDTO dto, final boolean controllerInitialized, final boolean existingFlowEmpty)
-            throws ReportingTaskInstantiationException {
-        // create a new reporting task node when the controller is not initialized or the flow is empty
-        if (!controllerInitialized || existingFlowEmpty) {
-            BundleCoordinate coordinate;
-            try {
-                coordinate = BundleUtils.getCompatibleBundle(extensionManager, dto.getType(), dto.getBundle());
-            } catch (final IllegalStateException e) {
-                final BundleDTO bundleDTO = dto.getBundle();
-                if (bundleDTO == null) {
-                    coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-                } else {
-                    coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-                }
-            }
-
-            final ReportingTaskNode reportingTask = controller.createReportingTask(dto.getType(), dto.getId(), coordinate, false);
-            reportingTask.setName(dto.getName());
-            reportingTask.setComments(dto.getComments());
-            reportingTask.setSchedulingPeriod(dto.getSchedulingPeriod());
-            reportingTask.setSchedulingStrategy(SchedulingStrategy.valueOf(dto.getSchedulingStrategy()));
-
-            reportingTask.setAnnotationData(dto.getAnnotationData());
-            final Set<String> sensitiveDynamicPropertyNames = getSensitiveDynamicPropertyNames(dto.getSensitiveDynamicPropertyNames(), reportingTask);
-            reportingTask.setProperties(dto.getProperties(), false, sensitiveDynamicPropertyNames);
-            return reportingTask;
-        } else {
-            // otherwise return the existing reporting task node
-            return controller.getReportingTaskNode(dto.getId());
-        }
-    }
-
-    private void applyReportingTaskScheduleState(final FlowController controller, final ReportingTaskDTO dto, final ReportingTaskNode reportingTask,
-            final boolean controllerInitialized, final boolean existingFlowEmpty) {
-        if (!controllerInitialized || existingFlowEmpty) {
-            applyNewReportingTaskScheduleState(controller, dto, reportingTask);
-        } else {
-            applyExistingReportingTaskScheduleState(controller, dto, reportingTask);
-        }
-    }
-
-    private void applyNewReportingTaskScheduleState(final FlowController controller, final ReportingTaskDTO dto, final ReportingTaskNode reportingTask) {
-        if (autoResumeState) {
-            if (ScheduledState.RUNNING.name().equals(dto.getState())) {
-                try {
-                    controller.startReportingTask(reportingTask);
-                } catch (final Exception e) {
-                    logger.error("Failed to start {} due to {}", reportingTask, e);
-                    if (logger.isDebugEnabled()) {
-                        logger.error("", e);
-                    }
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin(
-                            "Reporting Tasks", Severity.ERROR.name(), "Failed to start " + reportingTask + " due to " + e));
-                }
-            } else if (ScheduledState.DISABLED.name().equals(dto.getState())) {
-                try {
-                    controller.disableReportingTask(reportingTask);
-                } catch (final Exception e) {
-                    logger.error("Failed to mark {} as disabled due to {}", reportingTask, e);
-                    if (logger.isDebugEnabled()) {
-                        logger.error("", e);
-                    }
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin(
-                            "Reporting Tasks", Severity.ERROR.name(), "Failed to mark " + reportingTask + " as disabled due to " + e));
-                }
-            }
-        }
-    }
-
-    private void applyExistingReportingTaskScheduleState(final FlowController controller, final ReportingTaskDTO dto, final ReportingTaskNode taskNode) {
-        if (!taskNode.getScheduledState().name().equals(dto.getState())) {
-            try {
-                switch (ScheduledState.valueOf(dto.getState())) {
-                    case DISABLED:
-                        if (taskNode.isRunning()) {
-                            controller.stopReportingTask(taskNode);
-                        }
-                        controller.disableReportingTask(taskNode);
-                        break;
-                    case RUNNING:
-                        if (taskNode.getScheduledState() == ScheduledState.DISABLED) {
-                            controller.enableReportingTask(taskNode);
-                        }
-                        controller.startReportingTask(taskNode);
-                        break;
-                    case STOPPED:
-                        if (taskNode.getScheduledState() == ScheduledState.DISABLED) {
-                            controller.enableReportingTask(taskNode);
-                        } else if (taskNode.getScheduledState() == ScheduledState.RUNNING) {
-                            controller.stopReportingTask(taskNode);
-                        }
-                        break;
-                }
-            } catch (final IllegalStateException ise) {
-                logger.error("Failed to change Scheduled State of {} from {} to {} due to {}", taskNode, taskNode.getScheduledState().name(), dto.getState(), ise.toString());
-                logger.error("", ise);
-
-                // create bulletin for the Processor Node
-                controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin("Node Reconnection", Severity.ERROR.name(),
-                        "Failed to change Scheduled State of " + taskNode + " from " + taskNode.getScheduledState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-
-                // create bulletin at Controller level.
-                controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin("Node Reconnection", Severity.ERROR.name(),
-                        "Failed to change Scheduled State of " + taskNode + " from " + taskNode.getScheduledState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-            }
-        }
-    }
-
-    private FlowAnalysisRuleNode getOrCreateFlowAnalysisRule(final FlowController controller, final FlowAnalysisRuleDTO dto, final boolean controllerInitialized, final boolean existingFlowEmpty)
-        throws FlowAnalysisRuleInstantiationException {
-        // create a new flow analysis rule node when the controller is not initialized or the flow is empty
-        if (!controllerInitialized || existingFlowEmpty) {
-            BundleCoordinate coordinate;
-            try {
-                coordinate = BundleUtils.getCompatibleBundle(extensionManager, dto.getType(), dto.getBundle());
-            } catch (final IllegalStateException e) {
-                final BundleDTO bundleDTO = dto.getBundle();
-                if (bundleDTO == null) {
-                    coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-                } else {
-                    coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-                }
-            }
-
-            final FlowAnalysisRuleNode flowAnalysisRule = controller.createFlowAnalysisRule(dto.getType(), dto.getId(), coordinate, false);
-            flowAnalysisRule.setName(dto.getName());
-            flowAnalysisRule.setComments(dto.getComments());
-
-            flowAnalysisRule.setEnforcementPolicy(EnforcementPolicy.valueOf(dto.getEnforcementPolicy()));
-
-            final Set<String> sensitiveDynamicPropertyNames = getSensitiveDynamicPropertyNames(dto.getSensitiveDynamicPropertyNames(), flowAnalysisRule);
-            flowAnalysisRule.setProperties(dto.getProperties(), false, sensitiveDynamicPropertyNames);
-
-            return flowAnalysisRule;
-        } else {
-            // otherwise return the existing flow analysis rule node
-            return controller.getFlowAnalysisRuleNode(dto.getId());
-        }
-    }
-
-    private void applyFlowAnalysisRuleState(final FlowController controller, final FlowAnalysisRuleDTO dto, final FlowAnalysisRuleNode flowAnalysisRule,
-                                            final boolean controllerInitialized, final boolean existingFlowEmpty) {
-        if (!controllerInitialized || existingFlowEmpty) {
-            applyNewFlowAnalysisRuleState(controller, dto, flowAnalysisRule);
-        } else {
-            applyExistingFlowAnalysisRuleState(controller, dto, flowAnalysisRule);
-        }
-    }
-
-    private void applyNewFlowAnalysisRuleState(final FlowController controller, final FlowAnalysisRuleDTO dto, final FlowAnalysisRuleNode flowAnalysisRule) {
-        if (autoResumeState) {
-            if (FlowAnalysisRuleState.ENABLED.name().equals(dto.getState())) {
-                try {
-                    controller.enableFlowAnalysisRule(flowAnalysisRule);
-                } catch (final Exception e) {
-                    logger.error("Failed to enable {} due to {}", flowAnalysisRule, e);
-                    if (logger.isDebugEnabled()) {
-                        logger.error("", e);
-                    }
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin(
-                            "Flow Analysis Rules", Severity.ERROR.name(), "Failed to start " + flowAnalysisRule + " due to " + e));
-                }
-            } else if (FlowAnalysisRuleState.DISABLED.name().equals(dto.getState())) {
-                try {
-                    controller.disableFlowAnalysisRule(flowAnalysisRule);
-                } catch (final Exception e) {
-                    logger.error("Failed to mark {} as disabled due to {}", flowAnalysisRule, e);
-                    if (logger.isDebugEnabled()) {
-                        logger.error("", e);
-                    }
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin(
-                            "Flow Analysis Rules", Severity.ERROR.name(), "Failed to mark " + flowAnalysisRule + " as disabled due to " + e));
-                }
-            }
-        }
-    }
-
-    private void applyExistingFlowAnalysisRuleState(final FlowController controller, final FlowAnalysisRuleDTO dto, final FlowAnalysisRuleNode node) {
-        if (!node.getState().name().equals(dto.getState())) {
-            try {
-                switch (FlowAnalysisRuleState.valueOf(dto.getState())) {
-                    case DISABLED:
-                        if (node.isEnabled()) {
-                            controller.disableFlowAnalysisRule(node);
-                        }
-                        break;
-                    case ENABLED:
-                        if (!node.isEnabled()) {
-                            controller.enableFlowAnalysisRule(node);
-                        }
-                        break;
-                }
-            } catch (final IllegalStateException ise) {
-                logger.error("Failed to change State of {} from {} to {} due to {}", node, node.getState().name(), dto.getState(), ise.toString());
-                logger.error("", ise);
-
-                // create bulletin for node
-                controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin("Node Reconnection", Severity.ERROR.name(),
-                        "Failed to change State of " + node + " from " + node.getState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-
-                // create bulletin at Controller level.
-                controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin("Node Reconnection", Severity.ERROR.name(),
-                        "Failed to change State of " + node + " from " + node.getState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-            }
-        }
-    }
-
-    private ControllerServiceState getFinalTransitionState(final ControllerServiceState state) {
-        switch (state) {
-            case DISABLED:
-            case DISABLING:
-                return ControllerServiceState.DISABLED;
-            case ENABLED:
-            case ENABLING:
-                return ControllerServiceState.ENABLED;
-            default:
-                throw new AssertionError();
-        }
-    }
-
-    private ProcessGroup updateProcessGroup(final FlowController controller, final ProcessGroup parentGroup, final Element processGroupElement,
-                                            final FlowEncodingVersion encodingVersion) {
-
-        // get the parent group ID
-        final String parentId = (parentGroup == null) ? null : parentGroup.getIdentifier();
-
-        final PropertyEncryptor encryptor = controller.getEncryptor();
-
-        // get the process group
-        final ProcessGroupDTO processGroupDto = FlowFromDOMFactory.getProcessGroup(parentId, processGroupElement, encryptor, encodingVersion);
-        final FlowManager flowManager = controller.getFlowManager();
-
-        // update the process group
-        if (parentId == null) {
-
-            /*
-             * Labels are not included in the "inherit flow" algorithm, so we cannot
-             * blindly update them because they may not exist in the current flow.
-             * Therefore, we first remove all labels, and then let the updating
-             * process add labels defined in the new flow.
-             */
-            final ProcessGroup root = flowManager.getRootGroup();
-            for (final Label label : root.findAllLabels()) {
-                label.getProcessGroup().removeLabel(label);
-            }
-        }
-
-        // update the process group
-        final ProcessGroup processGroup = flowManager.getGroup(processGroupDto.getId());
-        if (processGroup == null) {
-            throw new IllegalStateException("No Group with ID " + processGroupDto.getId() + " exists");
-        }
-
-        updateProcessGroup(processGroup, processGroupDto, controller.getFlowManager().getParameterContextManager());
-
-        // determine the scheduled state of all of the Controller Service
-        final List<Element> controllerServiceNodeList = getChildrenByTagName(processGroupElement, "controllerService");
-        final Set<ControllerServiceNode> toDisable = new HashSet<>();
-        final Set<ControllerServiceNode> toEnable = new HashSet<>();
-
-        for (final Element serviceElement : controllerServiceNodeList) {
-            final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(serviceElement, encryptor, encodingVersion);
-            final ControllerServiceNode serviceNode = processGroup.getControllerService(dto.getId());
-
-            // Check if the controller service is in the correct state. We consider it the correct state if
-            // we are in a transitional state and heading in the right direction or already in the correct state.
-            // E.g., it is the correct state if it should be 'DISABLED' and it is either DISABLED or DISABLING.
-            final ControllerServiceState serviceState = getFinalTransitionState(serviceNode.getState());
-            final ControllerServiceState clusterState = getFinalTransitionState(ControllerServiceState.valueOf(dto.getState()));
-
-            if (serviceState != clusterState) {
-                switch (clusterState) {
-                    case DISABLED:
-                        toDisable.add(serviceNode);
-                        break;
-                    case ENABLED:
-                        toEnable.add(serviceNode);
-                        break;
-                }
-            }
-        }
-
-        // Ensure that all services have been validated, so that we don't attempt to enable a service that is still in a 'validating' state
-        toEnable.forEach(ControllerServiceNode::performValidation);
-
-        final ControllerServiceProvider serviceProvider = controller.getControllerServiceProvider();
-        serviceProvider.disableControllerServicesAsync(toDisable);
-        serviceProvider.enableControllerServices(toEnable);
-
-        // processors & ports cannot be updated - they must be the same. Except for the scheduled state.
-        final List<Element> processorNodeList = getChildrenByTagName(processGroupElement, "processor");
-        for (final Element processorElement : processorNodeList) {
-            final ProcessorDTO dto = FlowFromDOMFactory.getProcessor(processorElement, encryptor, encodingVersion);
-            final ProcessorNode procNode = processGroup.getProcessor(dto.getId());
-
-            final ScheduledState procState = getScheduledState(procNode, controller);
-            updateNonFingerprintedProcessorSettings(procNode, dto);
-
-            if (!procState.name().equals(dto.getState())) {
-                try {
-                    switch (ScheduledState.valueOf(dto.getState())) {
-                        case DISABLED:
-                            // switch processor do disabled. This means we have to stop it (if it's already stopped, this method does nothing),
-                            // and then we have to disable it.
-                            controller.stopProcessor(procNode.getProcessGroupIdentifier(), procNode.getIdentifier());
-                            procNode.getProcessGroup().disableProcessor(procNode);
-                            break;
-                        case RUNNING:
-                            // we want to run now. Make sure processor is not disabled and then start it.
-                            procNode.performValidation();
-                            procNode.getProcessGroup().enableProcessor(procNode);
-                            controller.startProcessor(procNode.getProcessGroupIdentifier(), procNode.getIdentifier(), false);
-                            break;
-                        case STOPPED:
-                        case RUN_ONCE:
-                            if (procState == ScheduledState.DISABLED) {
-                                procNode.getProcessGroup().enableProcessor(procNode);
-                            } else if (procState == ScheduledState.RUNNING || procState == ScheduledState.RUN_ONCE) {
-                                controller.stopProcessor(procNode.getProcessGroupIdentifier(), procNode.getIdentifier());
-                            }
-                            break;
-                    }
-                } catch (final IllegalStateException ise) {
-                    logger.error("Failed to change Scheduled State of {} from {} to {} due to {}", procNode, procNode.getScheduledState().name(), dto.getState(), ise.toString());
-                    logger.error("", ise);
-
-                    // create bulletin for the Processor Node
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin(procNode, "Node Reconnection", Severity.ERROR.name(),
-                            "Failed to change Scheduled State of " + procNode + " from " + procNode.getScheduledState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-
-                    // create bulletin at Controller level.
-                    controller.getBulletinRepository().addBulletin(BulletinFactory.createBulletin("Node Reconnection", Severity.ERROR.name(),
-                            "Failed to change Scheduled State of " + procNode + " from " + procNode.getScheduledState().name() + " to " + dto.getState() + " due to " + ise.toString()));
-                }
-            }
-        }
-
-        final List<Element> inputPortList = getChildrenByTagName(processGroupElement, "inputPort");
-        for (final Element portElement : inputPortList) {
-            final PortDTO dto = FlowFromDOMFactory.getPort(portElement);
-            final Port port = processGroup.getInputPort(dto.getId());
-
-            final ScheduledState portState = getScheduledState(port, controller);
-
-            if (!portState.name().equals(dto.getState())) {
-                switch (ScheduledState.valueOf(dto.getState())) {
-                    case DISABLED:
-                        // switch processor do disabled. This means we have to stop it (if it's already stopped, this method does nothing),
-                        // and then we have to disable it.
-                        controller.stopConnectable(port);
-                        port.getProcessGroup().disableInputPort(port);
-                        break;
-                    case RUNNING:
-                        // we want to run now. Make sure processor is not disabled and then start it.
-                        port.getProcessGroup().enableInputPort(port);
-                        controller.startConnectable(port);
-                        break;
-                    case STOPPED:
-                        if (portState == ScheduledState.DISABLED) {
-                            port.getProcessGroup().enableInputPort(port);
-                        } else if (portState == ScheduledState.RUNNING) {
-                            controller.stopConnectable(port);
-                        }
-                        break;
-                }
-            }
-        }
-
-        final List<Element> outputPortList = getChildrenByTagName(processGroupElement, "outputPort");
-        for (final Element portElement : outputPortList) {
-            final PortDTO dto = FlowFromDOMFactory.getPort(portElement);
-            final Port port = processGroup.getOutputPort(dto.getId());
-
-            final ScheduledState portState = getScheduledState(port, controller);
-
-            if (!portState.name().equals(dto.getState())) {
-                switch (ScheduledState.valueOf(dto.getState())) {
-                    case DISABLED:
-                        // switch processor do disabled. This means we have to stop it (if it's already stopped, this method does nothing),
-                        // and then we have to disable it.
-                        controller.stopConnectable(port);
-                        port.getProcessGroup().disableOutputPort(port);
-                        break;
-                    case RUNNING:
-                        // we want to run now. Make sure processor is not disabled and then start it.
-                        port.getProcessGroup().enableOutputPort(port);
-                        controller.startConnectable(port);
-                        break;
-                    case STOPPED:
-                        if (portState == ScheduledState.DISABLED) {
-                            port.getProcessGroup().enableOutputPort(port);
-                        } else if (portState == ScheduledState.RUNNING) {
-                            controller.stopConnectable(port);
-                        }
-                        break;
-                }
-            }
-        }
-
-        // Update scheduled state of Remote Group Ports
-        final List<Element> remoteProcessGroupList = getChildrenByTagName(processGroupElement, "remoteProcessGroup");
-        for (final Element remoteGroupElement : remoteProcessGroupList) {
-            final RemoteProcessGroupDTO remoteGroupDto = FlowFromDOMFactory.getRemoteProcessGroup(remoteGroupElement, encryptor);
-            final RemoteProcessGroup rpg = processGroup.getRemoteProcessGroup(remoteGroupDto.getId());
-
-            // input ports
-            final List<Element> inputPortElements = getChildrenByTagName(remoteGroupElement, "inputPort");
-            for (final Element inputPortElement : inputPortElements) {
-                final RemoteProcessGroupPortDescriptor portDescriptor = FlowFromDOMFactory.getRemoteProcessGroupPort(inputPortElement);
-                final String inputPortId = portDescriptor.getId();
-                final RemoteGroupPort inputPort = rpg.getInputPort(inputPortId);
-                if (inputPort == null) {
-                    continue;
-                }
-
-                final ScheduledState portState = getScheduledState(inputPort, controller);
-
-                if (portDescriptor.isTransmitting()) {
-                    if (portState != ScheduledState.RUNNING && portState != ScheduledState.STARTING) {
-                        controller.startTransmitting(inputPort);
-                    }
-                } else if (portState != ScheduledState.STOPPED && portState != ScheduledState.STOPPING) {
-                    controller.stopTransmitting(inputPort);
-                }
-            }
-
-            // output ports
-            final List<Element> outputPortElements = getChildrenByTagName(remoteGroupElement, "outputPort");
-            for (final Element outputPortElement : outputPortElements) {
-                final RemoteProcessGroupPortDescriptor portDescriptor = FlowFromDOMFactory.getRemoteProcessGroupPort(outputPortElement);
-                final String outputPortId = portDescriptor.getId();
-                final RemoteGroupPort outputPort = rpg.getOutputPort(outputPortId);
-                if (outputPort == null) {
-                    continue;
-                }
-
-                final ScheduledState portState = getScheduledState(outputPort, controller);
-
-                if (portDescriptor.isTransmitting()) {
-                    if (portState != ScheduledState.RUNNING && portState != ScheduledState.STARTING) {
-                        controller.startTransmitting(outputPort);
-                    }
-                } else if (portState != ScheduledState.STOPPED && portState != ScheduledState.STOPPING) {
-                    controller.stopTransmitting(outputPort);
-                }
-            }
-        }
-
-        // add labels
-        final List<Element> labelNodeList = getChildrenByTagName(processGroupElement, "label");
-        for (final Element labelElement : labelNodeList) {
-            final LabelDTO labelDTO = FlowFromDOMFactory.getLabel(labelElement);
-            final Label label = flowManager.createLabel(labelDTO.getId(), labelDTO.getLabel());
-            label.setStyle(labelDTO.getStyle());
-            label.setPosition(new Position(labelDTO.getPosition().getX(), labelDTO.getPosition().getY()));
-            label.setVersionedComponentId(labelDTO.getVersionedComponentId());
-            if (labelDTO.getWidth() != null && labelDTO.getHeight() != null) {
-                label.setSize(new Size(labelDTO.getWidth(), labelDTO.getHeight()));
-            }
-            if (labelDTO.getzIndex() != null) {
-                label.setZIndex(labelDTO.getzIndex());
-            }
-
-            processGroup.addLabel(label);
-        }
-
-        // update nested process groups (recursively)
-        final List<Element> nestedProcessGroupNodeList = getChildrenByTagName(processGroupElement, "processGroup");
-        for (final Element nestedProcessGroupElement : nestedProcessGroupNodeList) {
-            updateProcessGroup(controller, processGroup, nestedProcessGroupElement, encodingVersion);
-        }
-
-        // update connections
-        final List<Element> connectionNodeList = getChildrenByTagName(processGroupElement, "connection");
-        for (final Element connectionElement : connectionNodeList) {
-            final ConnectionDTO dto = FlowFromDOMFactory.getConnection(connectionElement);
-
-            final Connection connection = processGroup.getConnection(dto.getId());
-            connection.setName(dto.getName());
-            connection.setProcessGroup(processGroup);
-
-            if (dto.getLabelIndex() != null) {
-                connection.setLabelIndex(dto.getLabelIndex());
-            }
-            if (dto.getzIndex() != null) {
-                connection.setZIndex(dto.getzIndex());
-            }
-
-            final List<Position> bendPoints = new ArrayList<>();
-            for (final PositionDTO bend : dto.getBends()) {
-                bendPoints.add(new Position(bend.getX(), bend.getY()));
-            }
-            connection.setBendPoints(bendPoints);
-
-            List<FlowFilePrioritizer> newPrioritizers = null;
-            final List<String> prioritizers = dto.getPrioritizers();
-            if (prioritizers != null) {
-                final List<String> newPrioritizersClasses = new ArrayList<>(prioritizers);
-                newPrioritizers = new ArrayList<>();
-                for (final String className : newPrioritizersClasses) {
-                    try {
-                        newPrioritizers.add(flowManager.createPrioritizer(className));
-                    } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
-                        throw new IllegalArgumentException("Unable to set prioritizer " + className + ": " + e);
-                    }
-                }
-            }
-
-            if (newPrioritizers != null) {
-                connection.getFlowFileQueue().setPriorities(newPrioritizers);
-            }
-
-            if (dto.getBackPressureObjectThreshold() != null) {
-                connection.getFlowFileQueue().setBackPressureObjectThreshold(dto.getBackPressureObjectThreshold());
-            }
-
-            if (dto.getBackPressureDataSizeThreshold() != null && !dto.getBackPressureDataSizeThreshold().trim().isEmpty()) {
-                connection.getFlowFileQueue().setBackPressureDataSizeThreshold(dto.getBackPressureDataSizeThreshold());
-            }
-
-            if (dto.getFlowFileExpiration() != null) {
-                connection.getFlowFileQueue().setFlowFileExpiration(dto.getFlowFileExpiration());
-            }
-        }
-
-        return processGroup;
-    }
-
-    /**
-     * Updates the process group corresponding to the specified DTO. Any field
-     * in DTO that is <code>null</code> (with the exception of the required ID)
-     * will be ignored, or in the case of back pressure settings, will obtain
-     * value from the parent of this process group
-     *
-     * @throws IllegalStateException if no process group can be found with the
-     * ID of DTO or with the ID of the DTO's parentGroupId, or if the DTO's Parent Group ID changes but the
-     * parent group has incoming or outgoing connections
-     *
-     * @throws NullPointerException if the DTO or its ID is null
-     */
-    private void updateProcessGroup(final ProcessGroup group, final ProcessGroupDTO dto, final ParameterContextManager parameterContextManager) {
-        final String name = dto.getName();
-        final PositionDTO position = dto.getPosition();
-        final String comments = dto.getComments();
-        final String flowfileConcurrencyName = dto.getFlowfileConcurrency();
-        final String flowfileOutboundPolicyName = dto.getFlowfileOutboundPolicy();
-        final String defaultFlowFileExpiration = dto.getDefaultFlowFileExpiration();
-        final Long defaultBackPressureObjectThreshold = dto.getDefaultBackPressureObjectThreshold();
-        final String defaultBackPressureDataSizeThreshold = dto.getDefaultBackPressureDataSizeThreshold();
-        final String logFileSuffix = dto.getLogFileSuffix();
-
-        if (name != null) {
-            group.setName(name);
-        }
-        if (position != null) {
-            group.setPosition(toPosition(position));
-        }
-        if (comments != null) {
-            group.setComments(comments);
-        }
-
-        if (flowfileConcurrencyName == null) {
-            group.setFlowFileConcurrency(FlowFileConcurrency.UNBOUNDED);
-        } else {
-            group.setFlowFileConcurrency(FlowFileConcurrency.valueOf(flowfileConcurrencyName));
-        }
-
-        if (flowfileOutboundPolicyName == null) {
-            group.setFlowFileOutboundPolicy(FlowFileOutboundPolicy.STREAM_WHEN_AVAILABLE);
-        } else {
-            group.setFlowFileOutboundPolicy(FlowFileOutboundPolicy.valueOf(flowfileOutboundPolicyName));
-        }
-
-        final ParameterContextReferenceEntity parameterContextReference = dto.getParameterContext();
-        if (parameterContextReference != null && parameterContextReference.getId() != null) {
-            final String parameterContextId = parameterContextReference.getId();
-            final ParameterContext parameterContext = parameterContextManager.getParameterContext(parameterContextId);
-            if (!Objects.equals(parameterContext, group.getParameterContext())) {
-                group.setParameterContext(parameterContext);
-            }
-        }
-
-        if (defaultFlowFileExpiration != null) {
-            group.setDefaultFlowFileExpiration(defaultFlowFileExpiration);
-        }
-        if (defaultBackPressureObjectThreshold != null) {
-            group.setDefaultBackPressureObjectThreshold(defaultBackPressureObjectThreshold);
-        }
-        if (defaultBackPressureDataSizeThreshold != null) {
-            group.setDefaultBackPressureDataSizeThreshold(defaultBackPressureDataSizeThreshold);
-        }
-
-        if (logFileSuffix != null) {
-            group.setLogFileSuffix(logFileSuffix);
-        }
-    }
-
-    private <T extends Connectable & Triggerable> ScheduledState getScheduledState(final T component, final FlowController flowController) {
-        final ScheduledState componentState = component.getScheduledState();
-        if (componentState == ScheduledState.STOPPED) {
-            if (flowController.isStartAfterInitialization(component)) {
-                return ScheduledState.RUNNING;
-            }
-        }
-
-        return componentState;
-    }
-
-    private Position toPosition(final PositionDTO dto) {
-        return new Position(dto.getX(), dto.getY());
-    }
-
-    private void updateProcessor(final ProcessorNode procNode, final ProcessorDTO processorDTO, final ProcessGroup processGroup, final FlowController controller) {
-
-        procNode.pauseValidationTrigger();
-        try {
-            final ProcessorConfigDTO config = processorDTO.getConfig();
-            procNode.setProcessGroup(processGroup);
-            procNode.setLossTolerant(config.isLossTolerant());
-            procNode.setPenalizationPeriod(config.getPenaltyDuration());
-            procNode.setYieldPeriod(config.getYieldDuration());
-            procNode.setBulletinLevel(LogLevel.valueOf(config.getBulletinLevel()));
-            procNode.setRetryCount(config.getRetryCount());
-            procNode.setRetriedRelationships(config.getRetriedRelationships());
-
-            if (config.getBackoffMechanism() != null) {
-                procNode.setBackoffMechanism(BackoffMechanism.valueOf(config.getBackoffMechanism()));
-            }
-            procNode.setMaxBackoffPeriod(config.getMaxBackoffPeriod());
-            updateNonFingerprintedProcessorSettings(procNode, processorDTO);
-
-            if (config.getSchedulingStrategy() != null) {
-                procNode.setSchedulingStrategy(SchedulingStrategy.valueOf(config.getSchedulingStrategy()));
-            }
-
-            if (config.getExecutionNode() != null) {
-                procNode.setExecutionNode(ExecutionNode.valueOf(config.getExecutionNode()));
-            }
-
-            // must set scheduling strategy before these two
-            procNode.setMaxConcurrentTasks(config.getConcurrentlySchedulableTaskCount());
-            procNode.setSchedulingPeriod(config.getSchedulingPeriod());
-            if (config.getRunDurationMillis() != null) {
-                procNode.setRunDuration(config.getRunDurationMillis(), TimeUnit.MILLISECONDS);
-            }
-
-            procNode.setAnnotationData(config.getAnnotationData());
-
-            if (config.getAutoTerminatedRelationships() != null) {
-                final Set<Relationship> relationships = new HashSet<>();
-                for (final String rel : config.getAutoTerminatedRelationships()) {
-                    relationships.add(procNode.getRelationship(rel));
-                }
-                procNode.setAutoTerminatedRelationships(relationships);
-            }
-
-            final Set<String> sensitiveDynamicPropertyNames = getSensitiveDynamicPropertyNames(config.getSensitiveDynamicPropertyNames(), procNode);
-            procNode.setProperties(config.getProperties(), false, sensitiveDynamicPropertyNames);
-
-            final ScheduledState scheduledState = ScheduledState.valueOf(processorDTO.getState());
-            if (ScheduledState.RUNNING.equals(scheduledState)) {
-                procNode.performValidation(); // ensure that processor has been validated
-                controller.startProcessor(processGroup.getIdentifier(), procNode.getIdentifier());
-            } else if (ScheduledState.DISABLED.equals(scheduledState)) {
-                processGroup.disableProcessor(procNode);
-            } else if (ScheduledState.STOPPED.equals(scheduledState)) {
-                controller.stopProcessor(processGroup.getIdentifier(), procNode.getIdentifier());
-            }
-        } finally {
-            procNode.resumeValidationTrigger();
-        }
-    }
-
-    private Set<String> getSensitiveDynamicPropertyNames(final Set<String> parsedSensitivePropertyNames, final ComponentNode componentNode) {
-        final Set<String> sensitivePropertyNames = parsedSensitivePropertyNames == null ? Collections.emptySet() : parsedSensitivePropertyNames;
-        return sensitivePropertyNames.stream().filter(
-                propertyName -> {
-                    final PropertyDescriptor propertyDescriptor = componentNode.getPropertyDescriptor(propertyName);
-                    return propertyDescriptor.isDynamic();
-                }
-        ).collect(Collectors.toSet());
-    }
-
-    private void updateNonFingerprintedProcessorSettings(final ProcessorNode procNode, final ProcessorDTO processorDTO) {
-        procNode.setName(processorDTO.getName());
-        procNode.setPosition(toPosition(processorDTO.getPosition()));
-        procNode.setStyle(processorDTO.getStyle());
-        procNode.setComments(processorDTO.getConfig().getComments());
-    }
-
-    private ProcessGroup addProcessGroup(final FlowController controller, final ProcessGroup parentGroup, final Element processGroupElement,
-                                         final FlowEncodingVersion encodingVersion) {
-
-        // get the parent group ID
-        final String parentId = (parentGroup == null) ? null : parentGroup.getIdentifier();
-        final FlowManager flowManager = controller.getFlowManager();
-        final PropertyEncryptor encryptor = controller.getEncryptor();
-
-        // add the process group
-        final ProcessGroupDTO processGroupDTO = FlowFromDOMFactory.getProcessGroup(parentId, processGroupElement, encryptor, encodingVersion);
-        final ProcessGroup processGroup = flowManager.createProcessGroup(processGroupDTO.getId());
-        processGroup.setComments(processGroupDTO.getComments());
-        processGroup.setVersionedComponentId(processGroupDTO.getVersionedComponentId());
-        processGroup.setPosition(toPosition(processGroupDTO.getPosition()));
-        processGroup.setName(processGroupDTO.getName());
-        processGroup.setParent(parentGroup);
-        if (parentGroup == null) {
-            controller.setRootGroup(processGroup);
-        } else {
-            parentGroup.addProcessGroup(processGroup);
-        }
-
-        final String flowfileConcurrencyName = processGroupDTO.getFlowfileConcurrency();
-        final String flowfileOutboundPolicyName = processGroupDTO.getFlowfileOutboundPolicy();
-        if (flowfileConcurrencyName == null) {
-            processGroup.setFlowFileConcurrency(FlowFileConcurrency.UNBOUNDED);
-        } else {
-            processGroup.setFlowFileConcurrency(FlowFileConcurrency.valueOf(flowfileConcurrencyName));
-        }
-
-        if (flowfileOutboundPolicyName == null) {
-            processGroup.setFlowFileOutboundPolicy(FlowFileOutboundPolicy.STREAM_WHEN_AVAILABLE);
-        } else {
-            processGroup.setFlowFileOutboundPolicy(FlowFileOutboundPolicy.valueOf(flowfileOutboundPolicyName));
-        }
-
-        processGroup.setDefaultFlowFileExpiration(processGroupDTO.getDefaultFlowFileExpiration());
-        processGroup.setDefaultBackPressureObjectThreshold(processGroupDTO.getDefaultBackPressureObjectThreshold());
-        processGroup.setDefaultBackPressureDataSizeThreshold(processGroupDTO.getDefaultBackPressureDataSizeThreshold());
-
-        processGroup.setLogFileSuffix(processGroupDTO.getLogFileSuffix());
-
-        final String parameterContextId = getString(processGroupElement, "parameterContextId");
-        if (parameterContextId != null) {
-            final ParameterContext parameterContext = controller.getFlowManager().getParameterContextManager().getParameterContext(parameterContextId);
-            processGroup.setParameterContext(parameterContext);
-        }
-
-        addVersionControlInfo(processGroup, processGroupDTO, controller);
-        addControllerServices(processGroupElement, processGroup, controller, encodingVersion);
-        addProcessors(processGroupElement, processGroup, controller, encodingVersion);
-        addInputPorts(processGroupElement, processGroup, controller);
-        addOutputPorts(processGroupElement, processGroup, controller);
-        addFunnels(processGroupElement, processGroup, controller);
-        addLabels(processGroupElement, processGroup, controller);
-        addNestedProcessGroups(processGroupElement, processGroup, controller, encodingVersion);
-        addRemoteProcessGroups(processGroupElement, processGroup, controller);
-        addConnections(processGroupElement, processGroup, controller);
-
-        return processGroup;
-    }
-
-    private void addNestedProcessGroups(final Element processGroupElement, final ProcessGroup processGroup, final FlowController flowController, final FlowEncodingVersion encodingVersion) {
-        final List<Element> nestedProcessGroupNodeList = getChildrenByTagName(processGroupElement, "processGroup");
-        for (final Element nestedProcessGroupElement : nestedProcessGroupNodeList) {
-            addProcessGroup(flowController, processGroup, nestedProcessGroupElement, encodingVersion);
-        }
-    }
-
-    private void addVersionControlInfo(final ProcessGroup processGroup, final ProcessGroupDTO processGroupDTO, final FlowController flowController) {
-        final VersionControlInformationDTO versionControlInfoDto = processGroupDTO.getVersionControlInformation();
-        if (versionControlInfoDto != null) {
-            final FlowRegistryClientNode flowRegistry = flowController.getFlowManager().getFlowRegistryClient(versionControlInfoDto.getRegistryId());
-            final String registryName = flowRegistry == null ? versionControlInfoDto.getRegistryId() : flowRegistry.getName();
-
-            versionControlInfoDto.setState(VersionedFlowState.SYNC_FAILURE.name());
-            versionControlInfoDto.setStateExplanation("Process Group has not yet been synchronized with the Flow Registry");
-            final StandardVersionControlInformation versionControlInformation = StandardVersionControlInformation.Builder.fromDto(versionControlInfoDto)
-                .registryName(registryName)
-                .build();
-
-            // pass empty map for the version control mapping because the VersionedComponentId has already been set on the components
-            processGroup.setVersionControlInformation(versionControlInformation, Collections.emptyMap());
-        }
-    }
-
-    private void addControllerServices(final Element processGroupElement, final ProcessGroup processGroup, final FlowController flowController, final FlowEncodingVersion encodingVersion) {
-        final List<Element> serviceNodeList = getChildrenByTagName(processGroupElement, "controllerService");
-        final PropertyEncryptor encryptor = flowController.getEncryptor();
-        if (!serviceNodeList.isEmpty()) {
-            final Map<ControllerServiceNode, Element> controllerServices = ControllerServiceLoader.loadControllerServices(serviceNodeList, flowController, processGroup, encryptor, encodingVersion);
-            ControllerServiceLoader.enableControllerServices(controllerServices, flowController, encryptor, autoResumeState, encodingVersion);
-        }
-    }
-
-    private void addProcessors(final Element processGroupElement, final ProcessGroup processGroup, final FlowController flowController, final FlowEncodingVersion encodingVersion) {
-        final List<Element> processorNodeList = getChildrenByTagName(processGroupElement, "processor");
-        final PropertyEncryptor encryptor = flowController.getEncryptor();
-        for (final Element processorElement : processorNodeList) {
-            final ProcessorDTO processorDTO = FlowFromDOMFactory.getProcessor(processorElement, encryptor, encodingVersion);
-
-            BundleCoordinate coordinate;
-            try {
-                coordinate = BundleUtils.getCompatibleBundle(extensionManager, processorDTO.getType(), processorDTO.getBundle());
-            } catch (final IllegalStateException e) {
-                final BundleDTO bundleDTO = processorDTO.getBundle();
-                if (bundleDTO == null) {
-                    coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-                } else {
-                    coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-                }
-            }
-
-            final ProcessorNode procNode = flowController.getFlowManager().createProcessor(processorDTO.getType(), processorDTO.getId(), coordinate, false);
-            procNode.setVersionedComponentId(processorDTO.getVersionedComponentId());
-            processGroup.addProcessor(procNode);
-            updateProcessor(procNode, processorDTO, processGroup, flowController);
-        }
-    }
-
-    private void addInputPorts(final Element processGroupElement, final ProcessGroup processGroup, final FlowController flowController) {
-        final FlowManager flowManager = flowController.getFlowManager();
-        final List<Element> inputPortNodeList = getChildrenByTagName(processGroupElement, "inputPort");
-        for (final Element inputPortElement : inputPortNodeList) {
-            final PortDTO portDTO = FlowFromDOMFactory.getPort(inputPortElement);
-
-            final Port port;
-            if (processGroup.isRootGroup() || Boolean.TRUE.equals(portDTO.getAllowRemoteAccess())) {
-                port = flowManager.createPublicInputPort(portDTO.getId(), portDTO.getName());
-            } else {
-                port = flowManager.createLocalInputPort(portDTO.getId(), portDTO.getName());
-            }
-
-            port.setVersionedComponentId(portDTO.getVersionedComponentId());
-            port.setPosition(toPosition(portDTO.getPosition()));
-            port.setComments(portDTO.getComments());
-            port.setProcessGroup(processGroup);
-
-            final Set<String> userControls = portDTO.getUserAccessControl();
-            if (userControls != null && !userControls.isEmpty()) {
-                if (!(port instanceof PublicPort)) {
-                    throw new IllegalStateException("Attempting to add User Access Controls to " + port.getIdentifier() + ", but it is not a RootGroupPort");
-                }
-                ((PublicPort) port).setUserAccessControl(userControls);
-            }
-            final Set<String> groupControls = portDTO.getGroupAccessControl();
-            if (groupControls != null && !groupControls.isEmpty()) {
-                if (!(port instanceof PublicPort)) {
-                    throw new IllegalStateException("Attempting to add Group Access Controls to " + port.getIdentifier() + ", but it is not a RootGroupPort");
-                }
-                ((PublicPort) port).setGroupAccessControl(groupControls);
-            }
-
-            processGroup.addInputPort(port);
-            if (portDTO.getConcurrentlySchedulableTaskCount() != null) {
-                port.setMaxConcurrentTasks(portDTO.getConcurrentlySchedulableTaskCount());
-            }
-
-            final ScheduledState scheduledState = ScheduledState.valueOf(portDTO.getState());
-            if (ScheduledState.RUNNING.equals(scheduledState)) {
-                flowController.startConnectable(port);
-            } else if (ScheduledState.DISABLED.equals(scheduledState)) {
-                processGroup.disableInputPort(port);
-            }
-        }
-    }
-
-    private void addOutputPorts(final Element processGroupElement, final ProcessGroup processGroup, final FlowController flowController) {
-        final FlowManager flowManager = flowController.getFlowManager();
-        final List<Element> outputPortNodeList = getChildrenByTagName(processGroupElement, "outputPort");
-        for (final Element outputPortElement : outputPortNodeList) {
-            final PortDTO portDTO = FlowFromDOMFactory.getPort(outputPortElement);
-
-            final Port port;
-            if (processGroup.isRootGroup() || Boolean.TRUE.equals(portDTO.getAllowRemoteAccess())) {
-                port = flowManager.createPublicOutputPort(portDTO.getId(), portDTO.getName());
-            } else {
-                port = flowManager.createLocalOutputPort(portDTO.getId(), portDTO.getName());
-            }
-
-            port.setVersionedComponentId(portDTO.getVersionedComponentId());
-            port.setPosition(toPosition(portDTO.getPosition()));
-            port.setComments(portDTO.getComments());
-            port.setProcessGroup(processGroup);
-
-            final Set<String> userControls = portDTO.getUserAccessControl();
-            if (userControls != null && !userControls.isEmpty()) {
-                if (!(port instanceof PublicPort)) {
-                    throw new IllegalStateException("Attempting to add User Access Controls to " + port.getIdentifier() + ", but it is not a RootGroupPort");
-                }
-                ((PublicPort) port).setUserAccessControl(userControls);
-            }
-            final Set<String> groupControls = portDTO.getGroupAccessControl();
-            if (groupControls != null && !groupControls.isEmpty()) {
-                if (!(port instanceof PublicPort)) {
-                    throw new IllegalStateException("Attempting to add Group Access Controls to " + port.getIdentifier() + ", but it is not a RootGroupPort");
-                }
-                ((PublicPort) port).setGroupAccessControl(groupControls);
-            }
-
-            processGroup.addOutputPort(port);
-            if (portDTO.getConcurrentlySchedulableTaskCount() != null) {
-                port.setMaxConcurrentTasks(portDTO.getConcurrentlySchedulableTaskCount());
-            }
-
-            final ScheduledState scheduledState = ScheduledState.valueOf(portDTO.getState());
-            if (ScheduledState.RUNNING.equals(scheduledState)) {
-                flowController.startConnectable(port);
-            } else if (ScheduledState.DISABLED.equals(scheduledState)) {
-                processGroup.disableOutputPort(port);
-            }
-        }
-    }
-
-    private void addFunnels(final Element processGroupElement, final ProcessGroup processGroup, final FlowController controller) {
-        final List<Element> funnelNodeList = getChildrenByTagName(processGroupElement, "funnel");
-        for (final Element funnelElement : funnelNodeList) {
-            final FunnelDTO funnelDTO = FlowFromDOMFactory.getFunnel(funnelElement);
-            final Funnel funnel = controller.getFlowManager().createFunnel(funnelDTO.getId());
-            funnel.setVersionedComponentId(funnelDTO.getVersionedComponentId());
-            funnel.setPosition(toPosition(funnelDTO.getPosition()));
-
-            // Since this is called during startup, we want to add the funnel without enabling it
-            // and then tell the controller to enable it. This way, if the controller is not fully
-            // initialized, the starting of the funnel is delayed until the controller is ready.
-            processGroup.addFunnel(funnel, false);
-            controller.startConnectable(funnel);
-        }
-    }
-
-    private void addLabels(final Element processGroupElement, final ProcessGroup processGroup, final FlowController controller) {
-        final List<Element> labelNodeList = getChildrenByTagName(processGroupElement, "label");
-        for (final Element labelElement : labelNodeList) {
-            final LabelDTO labelDTO = FlowFromDOMFactory.getLabel(labelElement);
-            final Label label = controller.getFlowManager().createLabel(labelDTO.getId(), labelDTO.getLabel());
-            label.setVersionedComponentId(labelDTO.getVersionedComponentId());
-            label.setStyle(labelDTO.getStyle());
-
-            label.setPosition(toPosition(labelDTO.getPosition()));
-            label.setSize(new Size(labelDTO.getWidth(), labelDTO.getHeight()));
-            final Long zIndex = labelDTO.getzIndex();
-            if (zIndex != null) {
-                label.setZIndex(zIndex);
-            }
-            processGroup.addLabel(label);
-        }
-    }
-
-    private void addRemoteProcessGroups(final Element processGroupElement, final ProcessGroup processGroup, final FlowController controller) {
-        final List<Element> remoteProcessGroupNodeList = getChildrenByTagName(processGroupElement, "remoteProcessGroup");
-        final PropertyEncryptor encryptor = controller.getEncryptor();
-        for (final Element remoteProcessGroupElement : remoteProcessGroupNodeList) {
-            final RemoteProcessGroupDTO remoteGroupDto = FlowFromDOMFactory.getRemoteProcessGroup(remoteProcessGroupElement, encryptor);
-            final RemoteProcessGroup remoteGroup = controller.getFlowManager().createRemoteProcessGroup(remoteGroupDto.getId(), remoteGroupDto.getTargetUris());
-            remoteGroup.setVersionedComponentId(remoteGroupDto.getVersionedComponentId());
-            remoteGroup.setComments(remoteGroupDto.getComments());
-            remoteGroup.setPosition(toPosition(remoteGroupDto.getPosition()));
-            final String name = remoteGroupDto.getName();
-            if (name != null && !name.trim().isEmpty()) {
-                remoteGroup.setName(name);
-            }
-            remoteGroup.setProcessGroup(processGroup);
-            remoteGroup.setCommunicationsTimeout(remoteGroupDto.getCommunicationsTimeout());
-
-            if (remoteGroupDto.getYieldDuration() != null) {
-                remoteGroup.setYieldDuration(remoteGroupDto.getYieldDuration());
-            }
-
-            final String transportProtocol = remoteGroupDto.getTransportProtocol();
-            if (transportProtocol != null && !transportProtocol.trim().isEmpty()) {
-                remoteGroup.setTransportProtocol(SiteToSiteTransportProtocol.valueOf(transportProtocol.toUpperCase()));
-            }
-
-            if (remoteGroupDto.getProxyHost() != null) {
-                remoteGroup.setProxyHost(remoteGroupDto.getProxyHost());
-            }
-
-            if (remoteGroupDto.getProxyPort() != null) {
-                remoteGroup.setProxyPort(remoteGroupDto.getProxyPort());
-            }
-
-            if (remoteGroupDto.getProxyUser() != null) {
-                remoteGroup.setProxyUser(remoteGroupDto.getProxyUser());
-            }
-
-            if (remoteGroupDto.getProxyPassword() != null) {
-                remoteGroup.setProxyPassword(remoteGroupDto.getProxyPassword());
-            }
-
-            if (StringUtils.isBlank(remoteGroupDto.getLocalNetworkInterface())) {
-                remoteGroup.setNetworkInterface(null);
-            } else {
-                remoteGroup.setNetworkInterface(remoteGroupDto.getLocalNetworkInterface());
-            }
-
-            final Set<RemoteProcessGroupPortDescriptor> inputPorts = new HashSet<>();
-            for (final Element portElement : getChildrenByTagName(remoteProcessGroupElement, "inputPort")) {
-                inputPorts.add(FlowFromDOMFactory.getRemoteProcessGroupPort(portElement));
-            }
-            remoteGroup.setInputPorts(inputPorts, false);
-
-            final Set<RemoteProcessGroupPortDescriptor> outputPorts = new HashSet<>();
-            for (final Element portElement : getChildrenByTagName(remoteProcessGroupElement, "outputPort")) {
-                outputPorts.add(FlowFromDOMFactory.getRemoteProcessGroupPort(portElement));
-            }
-            remoteGroup.setOutputPorts(outputPorts, false);
-            processGroup.addRemoteProcessGroup(remoteGroup);
-
-            for (final RemoteProcessGroupPortDescriptor remoteGroupPortDTO : outputPorts) {
-                final RemoteGroupPort port = remoteGroup.getOutputPort(remoteGroupPortDTO.getId());
-                if (Boolean.TRUE.equals(remoteGroupPortDTO.isTransmitting())) {
-                    controller.startTransmitting(port);
-                }
-            }
-            for (final RemoteProcessGroupPortDescriptor remoteGroupPortDTO : inputPorts) {
-                final RemoteGroupPort port = remoteGroup.getInputPort(remoteGroupPortDTO.getId());
-                if (Boolean.TRUE.equals(remoteGroupPortDTO.isTransmitting())) {
-                    controller.startTransmitting(port);
-                }
-            }
-        }
-    }
-
-    private void addConnections(final Element processGroupElement, final ProcessGroup processGroup, final FlowController controller) {
-        final FlowManager flowManager = controller.getFlowManager();
-
-        final List<Element> connectionNodeList = getChildrenByTagName(processGroupElement, "connection");
-        for (final Element connectionElement : connectionNodeList) {
-            final ConnectionDTO dto = FlowFromDOMFactory.getConnection(connectionElement);
-
-            final Connectable source;
-            final ConnectableDTO sourceDto = dto.getSource();
-            if (ConnectableType.REMOTE_OUTPUT_PORT.name().equals(sourceDto.getType())) {
-                final RemoteProcessGroup remoteGroup = processGroup.getRemoteProcessGroup(sourceDto.getGroupId());
-                source = remoteGroup.getOutputPort(sourceDto.getId());
-            } else {
-                final ProcessGroup sourceGroup = flowManager.getGroup(sourceDto.getGroupId());
-                if (sourceGroup == null) {
-                    throw new RuntimeException("Found Invalid ProcessGroup ID for Source: " + dto.getSource().getGroupId());
-                }
-
-                source = sourceGroup.getConnectable(sourceDto.getId());
-            }
-            if (source == null) {
-                throw new RuntimeException("Found Invalid Connectable ID for Source: " + dto.getSource().getId());
-            }
-
-            final Connectable destination;
-            final ConnectableDTO destinationDto = dto.getDestination();
-            if (ConnectableType.REMOTE_INPUT_PORT.name().equals(destinationDto.getType())) {
-                final RemoteProcessGroup remoteGroup = processGroup.getRemoteProcessGroup(destinationDto.getGroupId());
-                destination = remoteGroup.getInputPort(destinationDto.getId());
-            } else {
-                final ProcessGroup destinationGroup = flowManager.getGroup(destinationDto.getGroupId());
-                if (destinationGroup == null) {
-                    throw new RuntimeException("Found Invalid ProcessGroup ID for Destination: " + dto.getDestination().getGroupId());
-                }
-
-                destination = destinationGroup.getConnectable(destinationDto.getId());
-            }
-            if (destination == null) {
-                throw new RuntimeException("Found Invalid Connectable ID for Destination: " + dto.getDestination().getId());
-            }
-
-            final Connection connection = flowManager.createConnection(dto.getId(), dto.getName(), source, destination, dto.getSelectedRelationships());
-            connection.setVersionedComponentId(dto.getVersionedComponentId());
-            connection.setProcessGroup(processGroup);
-
-            final List<Position> bendPoints = new ArrayList<>();
-            for (final PositionDTO bend : dto.getBends()) {
-                bendPoints.add(new Position(bend.getX(), bend.getY()));
-            }
-            connection.setBendPoints(bendPoints);
-
-            final Long zIndex = dto.getzIndex();
-            if (zIndex != null) {
-                connection.setZIndex(zIndex);
-            }
-
-            if (dto.getLabelIndex() != null) {
-                connection.setLabelIndex(dto.getLabelIndex());
-            }
-
-            List<FlowFilePrioritizer> newPrioritizers = null;
-            final List<String> prioritizers = dto.getPrioritizers();
-            if (prioritizers != null) {
-                final List<String> newPrioritizersClasses = new ArrayList<>(prioritizers);
-                newPrioritizers = new ArrayList<>();
-                for (final String className : newPrioritizersClasses) {
-                    try {
-                        newPrioritizers.add(flowManager.createPrioritizer(className));
-                    } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
-                        throw new IllegalArgumentException("Unable to set prioritizer " + className + ": " + e);
-                    }
-                }
-            }
-            if (newPrioritizers != null) {
-                connection.getFlowFileQueue().setPriorities(newPrioritizers);
-            }
-
-            if (dto.getBackPressureObjectThreshold() != null) {
-                connection.getFlowFileQueue().setBackPressureObjectThreshold(dto.getBackPressureObjectThreshold());
-            }
-            if (dto.getBackPressureDataSizeThreshold() != null) {
-                connection.getFlowFileQueue().setBackPressureDataSizeThreshold(dto.getBackPressureDataSizeThreshold());
-            }
-            if (dto.getFlowFileExpiration() != null) {
-                connection.getFlowFileQueue().setFlowFileExpiration(dto.getFlowFileExpiration());
-            }
-
-            if (dto.getLoadBalanceStrategy() != null) {
-                connection.getFlowFileQueue().setLoadBalanceStrategy(LoadBalanceStrategy.valueOf(dto.getLoadBalanceStrategy()), dto.getLoadBalancePartitionAttribute());
-            }
-
-            if (dto.getLoadBalanceCompression() != null) {
-                connection.getFlowFileQueue().setLoadBalanceCompression(LoadBalanceCompression.valueOf(dto.getLoadBalanceCompression()));
-            }
-
-            processGroup.addConnection(connection);
-        }
-    }
-
-
-    private byte[] toBytes(final FlowController flowController) throws FlowSerializationException {
-        final ByteArrayOutputStream result = new ByteArrayOutputStream();
-        final StandardFlowSerializer flowSerializer = new StandardFlowSerializer();
-        flowController.serialize(flowSerializer, result);
-        return result.toByteArray();
-    }
-
-    private static String getString(final Element element, final String childElementName) {
-        final List<Element> nodeList = getChildrenByTagName(element, childElementName);
-        if (nodeList == null || nodeList.isEmpty()) {
-            return "";
-        }
-        final Element childElement = nodeList.get(0);
-        return childElement.getTextContent();
-    }
-
-    private static int getInt(final Element element, final String childElementName) {
-        return Integer.parseInt(getString(element, childElementName));
-    }
-
-    private static Integer getInteger(final Element element, final String childElementName) {
-        final String value = getString(element, childElementName);
-        return (value == null || value.trim().equals("") ? null : Integer.parseInt(value));
-    }
-
-    private static List<Element> getChildrenByTagName(final Element element, final String tagName) {
-        final List<Element> matches = new ArrayList<>();
-        final NodeList nodeList = element.getChildNodes();
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            final Node node = nodeList.item(i);
-            if (!(node instanceof Element)) {
-                continue;
-            }
-
-            final Element child = (Element) nodeList.item(i);
-            if (child.getNodeName().equals(tagName)) {
-                matches.add(child);
-            }
-        }
-
-        return matches;
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/BundleCompatibilityCheck.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/BundleCompatibilityCheck.java
index c0163141b0..077bb95d1b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/BundleCompatibilityCheck.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/BundleCompatibilityCheck.java
@@ -40,14 +40,6 @@ public class BundleCompatibilityCheck implements FlowInheritabilityCheck {
 
     @Override
     public FlowInheritability checkInheritability(final DataFlow existingFlow, final DataFlow proposedFlow, final FlowController flowController) {
-        if (proposedFlow.isXml()) {
-            return checkInheritability(proposedFlow.getFlowDocument(), flowController);
-        } else {
-            return checkVersionedFlowInheritability(proposedFlow, flowController);
-        }
-    }
-
-    private FlowInheritability checkVersionedFlowInheritability(final DataFlow proposedFlow, final FlowController flowController) {
         return checkBundles(proposedFlow, flowController.getExtensionManager());
     }
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/ConnectionMissingCheck.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/ConnectionMissingCheck.java
index 6832a03f78..5465b36eff 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/ConnectionMissingCheck.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/ConnectionMissingCheck.java
@@ -22,24 +22,17 @@ import org.apache.nifi.controller.FlowController;
 import org.apache.nifi.controller.flow.FlowManager;
 import org.apache.nifi.controller.flow.VersionedDataflow;
 import org.apache.nifi.controller.repository.FlowFileRepository;
-import org.apache.nifi.controller.serialization.FlowEncodingVersion;
-import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
 import org.apache.nifi.controller.serialization.FlowSynchronizationException;
 import org.apache.nifi.flow.ComponentType;
 import org.apache.nifi.flow.VersionedComponent;
 import org.apache.nifi.registry.flow.diff.DifferenceType;
 import org.apache.nifi.registry.flow.diff.FlowComparison;
 import org.apache.nifi.registry.flow.diff.FlowDifference;
-import org.apache.nifi.web.api.dto.ConnectionDTO;
-import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 
 import java.io.IOException;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -57,11 +50,7 @@ public class ConnectionMissingCheck implements FlowInheritabilityCheck {
 
     @Override
     public FlowInheritability checkInheritability(final DataFlow existingFlow, final DataFlow proposedFlow, final FlowController flowController) {
-        if (proposedFlow.isXml()) {
-            return checkInheritability(proposedFlow.getFlowDocument(), flowController);
-        } else {
-            return checkInheritability(existingFlow.getVersionedDataflow(), proposedFlow.getVersionedDataflow(), flowController);
-        }
+        return checkInheritability(existingFlow.getVersionedDataflow(), proposedFlow.getVersionedDataflow(), flowController);
     }
 
     private FlowInheritability checkInheritability(final VersionedDataflow existingFlow, final VersionedDataflow proposedFlow, final FlowController flowController) {
@@ -111,47 +100,4 @@ public class ConnectionMissingCheck implements FlowInheritabilityCheck {
 
         return FlowInheritability.inheritable();
     }
-
-    private FlowInheritability checkInheritability(final Document flowDocument, final FlowController flowController) {
-        final Element rootGroupElement = (Element) flowDocument.getDocumentElement().getElementsByTagName("rootGroup").item(0);
-        final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(flowDocument.getDocumentElement());
-
-        final ProcessGroupDTO rootGroupDto = FlowFromDOMFactory.getProcessGroup(null, rootGroupElement, null, encodingVersion);
-        final Set<String> connectionIds = findAllConnectionIds(rootGroupDto);
-
-        final FlowFileRepository flowFileRepository = flowController.getRepositoryContextFactory().getFlowFileRepository();
-
-        final Set<String> queuesWithFlowFiles;
-        try {
-            queuesWithFlowFiles = flowFileRepository.findQueuesWithFlowFiles(flowController.createSwapManager());
-        } catch (final IOException ioe) {
-            throw new FlowSynchronizationException("Failed to determine which connections have FlowFiles queued", ioe);
-        }
-
-        logger.debug("The following {} Connections/Queues have data queued up currently: {}", queuesWithFlowFiles.size(), queuesWithFlowFiles);
-
-        for (final String queueId : queuesWithFlowFiles) {
-            if (!connectionIds.contains(queueId)) {
-                return FlowInheritability.notInheritable("Proposed Flow does not contain a Connection with ID " + queueId + " but this instance has data queued in that connection");
-            }
-        }
-
-        return FlowInheritability.inheritable();
-    }
-
-    private Set<String> findAllConnectionIds(final ProcessGroupDTO group) {
-        final Set<String> connectionIds = new HashSet<>();
-        findAllConnectionIds(group, connectionIds);
-        return connectionIds;
-    }
-
-    private void findAllConnectionIds(final ProcessGroupDTO group, final Set<String> ids) {
-        for (final ConnectionDTO connectionDTO : group.getContents().getConnections()) {
-            ids.add(connectionDTO.getId());
-        }
-
-        for (final ProcessGroupDTO childGroup : group.getContents().getProcessGroups()) {
-            findAllConnectionIds(childGroup, ids);
-        }
-    }
 }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/FlowFingerprintCheck.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/FlowFingerprintCheck.java
deleted file mode 100644
index 079786d2e0..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/inheritance/FlowFingerprintCheck.java
+++ /dev/null
@@ -1,99 +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.controller.inheritance;
-
-import org.apache.nifi.cluster.protocol.DataFlow;
-import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.encrypt.SensitiveValueEncoder;
-import org.apache.nifi.fingerprint.FingerprintFactory;
-import org.apache.nifi.nar.ExtensionManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class FlowFingerprintCheck implements FlowInheritabilityCheck {
-    private static final Logger logger = LoggerFactory.getLogger(FlowFingerprintCheck.class);
-
-    @Override
-    public FlowInheritability checkInheritability(final DataFlow existingFlow, final DataFlow proposedFlow, final FlowController flowController) {
-        if (existingFlow == null) {
-            return FlowInheritability.inheritable();
-        }
-
-        final byte[] existingFlowBytes = existingFlow.getFlow();
-        final byte[] proposedFlowBytes = proposedFlow.getFlow();
-
-        final PropertyEncryptor encryptor = flowController.getEncryptor();
-        final ExtensionManager extensionManager = flowController.getExtensionManager();
-        final SensitiveValueEncoder sensitiveValueEncoder = flowController.getSensitiveValueEncoder();
-
-        final FingerprintFactory fingerprintFactory = new FingerprintFactory(encryptor, extensionManager, sensitiveValueEncoder);
-        final String existingFlowFingerprintBeforeHash = fingerprintFactory.createFingerprint(existingFlowBytes, flowController);
-        if (existingFlowFingerprintBeforeHash.trim().isEmpty()) {
-            return null;  // no existing flow, so equivalent to proposed flow
-        }
-
-        if (proposedFlow == null || proposedFlowBytes.length == 0) {
-            return FlowInheritability.notInheritable("Proposed Flow was empty but Current Flow is not");  // existing flow is not empty and proposed flow is empty (we could orphan flowfiles)
-        }
-
-        final String proposedFlowFingerprintBeforeHash = fingerprintFactory.createFingerprint(proposedFlow.getFlowDocument(), flowController);
-        if (proposedFlowFingerprintBeforeHash.trim().isEmpty()) {
-            return FlowInheritability.notInheritable("Proposed Flow was empty but Current Flow is not");  // existing flow is not empty and proposed flow is empty (we could orphan flowfiles)
-        }
-
-        if (logger.isTraceEnabled()) {
-            logger.trace("Local Fingerprint Before Hash = {}", new Object[] {existingFlowFingerprintBeforeHash});
-            logger.trace("Proposed Fingerprint Before Hash = {}", new Object[] {proposedFlowFingerprintBeforeHash});
-        }
-
-        final boolean inheritable = existingFlowFingerprintBeforeHash.equals(proposedFlowFingerprintBeforeHash);
-        if (!inheritable) {
-            final String discrepancy = findFirstDiscrepancy(existingFlowFingerprintBeforeHash, proposedFlowFingerprintBeforeHash, "Flows");
-            return FlowInheritability.notInheritable(discrepancy);
-        }
-
-        return FlowInheritability.inheritable();
-    }
-
-    private String findFirstDiscrepancy(final String existing, final String proposed, final String comparisonDescription) {
-        final int shortestFileLength = Math.min(existing.length(), proposed.length());
-        for (int i = 0; i < shortestFileLength; i++) {
-            if (existing.charAt(i) != proposed.charAt(i)) {
-                final String formattedExistingDelta = formatFlowDiscrepancy(existing, i, 100);
-                final String formattedProposedDelta = formatFlowDiscrepancy(proposed, i, 100);
-                return String.format("Found difference in %s:\nLocal Fingerprint:   %s\nCluster Fingerprint: %s", comparisonDescription, formattedExistingDelta, formattedProposedDelta);
-            }
-        }
-
-        // existing must startWith proposed or proposed must startWith existing
-        if (existing.length() > proposed.length()) {
-            final String formattedExistingDelta = existing.substring(proposed.length(), Math.min(existing.length(), proposed.length() + 200));
-            return String.format("Found difference in %s:\nLocal Fingerprint contains additional configuration from Cluster Fingerprint: %s", comparisonDescription, formattedExistingDelta);
-        } else if (proposed.length() > existing.length()) {
-            final String formattedProposedDelta = proposed.substring(existing.length(), Math.min(proposed.length(), existing.length() + 200));
-            return String.format("Found difference in %s:\nCluster Fingerprint contains additional configuration from Local Fingerprint: %s", comparisonDescription, formattedProposedDelta);
-        }
-
-        return "Unable to find any discrepancies between fingerprints. Please contact the NiFi support team";
-    }
-
-    private String formatFlowDiscrepancy(final String flowFingerprint, final int deltaIndex, final int deltaPad) {
-        return flowFingerprint.substring(Math.max(0, deltaIndex - deltaPad), Math.min(flowFingerprint.length(), deltaIndex + deltaPad));
-    }
-
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/FlowFromDOMFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/FlowFromDOMFactory.java
deleted file mode 100644
index 67dfc1d5ac..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/FlowFromDOMFactory.java
+++ /dev/null
@@ -1,783 +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.controller.serialization;
-
-import org.apache.nifi.connectable.Size;
-import org.apache.nifi.controller.ScheduledState;
-import org.apache.nifi.controller.service.ControllerServiceState;
-import org.apache.nifi.encrypt.EncryptionException;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.groups.RemoteProcessGroupPortDescriptor;
-import org.apache.nifi.parameter.ExpressionLanguageAwareParameterParser;
-import org.apache.nifi.parameter.ParameterParser;
-import org.apache.nifi.parameter.ParameterTokenList;
-import org.apache.nifi.remote.StandardRemoteProcessGroupPortDescriptor;
-import org.apache.nifi.scheduling.ExecutionNode;
-import org.apache.nifi.scheduling.SchedulingStrategy;
-import org.apache.nifi.util.DomUtils;
-import org.apache.nifi.web.api.dto.BundleDTO;
-import org.apache.nifi.web.api.dto.ConnectableDTO;
-import org.apache.nifi.web.api.dto.ConnectionDTO;
-import org.apache.nifi.web.api.dto.ControllerServiceDTO;
-import org.apache.nifi.web.api.dto.FlowAnalysisRuleDTO;
-import org.apache.nifi.web.api.dto.FlowRegistryClientDTO;
-import org.apache.nifi.web.api.dto.FlowSnippetDTO;
-import org.apache.nifi.web.api.dto.FunnelDTO;
-import org.apache.nifi.web.api.dto.LabelDTO;
-import org.apache.nifi.web.api.dto.ParameterContextDTO;
-import org.apache.nifi.web.api.dto.ParameterDTO;
-import org.apache.nifi.web.api.dto.ParameterProviderConfigurationDTO;
-import org.apache.nifi.web.api.dto.ParameterProviderDTO;
-import org.apache.nifi.web.api.dto.PortDTO;
-import org.apache.nifi.web.api.dto.PositionDTO;
-import org.apache.nifi.web.api.dto.ProcessGroupDTO;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
-import org.apache.nifi.web.api.dto.ProcessorDTO;
-import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
-import org.apache.nifi.web.api.dto.ReportingTaskDTO;
-import org.apache.nifi.web.api.dto.VersionControlInformationDTO;
-import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity;
-import org.apache.nifi.web.api.entity.ParameterEntity;
-import org.apache.nifi.web.api.entity.ParameterProviderConfigurationEntity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-public class FlowFromDOMFactory {
-    private static final Logger logger = LoggerFactory.getLogger(FlowFromDOMFactory.class);
-    private static final String DEPRECATED_FLOW_REGISTRY_CLIENT_TYPE = "org.apache.nifi.registry.flow.NifiRegistryFlowRegistryClient";
-
-    public static BundleDTO getBundle(final Element bundleElement) {
-        if (bundleElement == null) {
-            return null;
-        }
-
-        final Element groupElement = DomUtils.getChild(bundleElement, "group");
-        final Element artifactElement = DomUtils.getChild(bundleElement, "artifact");
-        final Element versionElement = DomUtils.getChild(bundleElement, "version");
-
-        return new BundleDTO(groupElement.getTextContent(), artifactElement.getTextContent(), versionElement.getTextContent());
-    }
-
-    public static PositionDTO getPosition(final Element positionElement) {
-        if (positionElement == null) {
-            throw new IllegalArgumentException("Invalid Flow: Found no 'position' element");
-        }
-        return new PositionDTO(Double.parseDouble(positionElement.getAttribute("x")), Double.parseDouble(positionElement.getAttribute("y")));
-    }
-
-    public static Size getSize(final Element sizeElement) {
-        if (sizeElement == null) {
-            throw new IllegalArgumentException("Invalid Flow: Found no 'size' element");
-        }
-
-        return new Size(Double.parseDouble(sizeElement.getAttribute("width")), Double.parseDouble(sizeElement.getAttribute("height")));
-    }
-
-    public static Map<String, String> getStyle(final Element stylesElement) {
-        final Map<String, String> styles = new HashMap<>();
-        if (stylesElement == null) {
-            return styles;
-        }
-
-        for (final Element styleElement : getChildrenByTagName(stylesElement, "style")) {
-            final String styleName = styleElement.getAttribute("name");
-            final String styleValue = styleElement.getTextContent();
-            styles.put(styleName, styleValue);
-        }
-
-        return styles;
-    }
-
-    public static ControllerServiceDTO getControllerService(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final ControllerServiceDTO dto = new ControllerServiceDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setName(getString(element, "name"));
-        dto.setComments(getString(element, "comment"));
-        dto.setBulletinLevel(getString(element, "bulletinLevel"));
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-
-        final boolean enabled = getBoolean(element, "enabled");
-        dto.setState(enabled ? ControllerServiceState.ENABLED.name() : ControllerServiceState.DISABLED.name());
-
-        dto.setSensitiveDynamicPropertyNames(getSensitivePropertyNames(element));
-        dto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-        dto.setAnnotationData(getString(element, "annotationData"));
-
-        return dto;
-    }
-
-    public static ReportingTaskDTO getReportingTask(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final ReportingTaskDTO dto = new ReportingTaskDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setComments(getString(element, "comment"));
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-        dto.setSchedulingPeriod(getString(element, "schedulingPeriod"));
-        dto.setState(getString(element, "scheduledState"));
-        dto.setSchedulingStrategy(getString(element, "schedulingStrategy"));
-
-        dto.setSensitiveDynamicPropertyNames(getSensitivePropertyNames(element));
-        dto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-        dto.setAnnotationData(getString(element, "annotationData"));
-
-        return dto;
-    }
-
-    public static FlowAnalysisRuleDTO getFlowAnalysisRule(Element element, PropertyEncryptor encryptor, FlowEncodingVersion flowEncodingVersion) {
-        final FlowAnalysisRuleDTO dto = new FlowAnalysisRuleDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setComments(getString(element, "comment"));
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-
-        dto.setEnforcementPolicy(getString(element, "enforcementPolicy"));
-        dto.setState(getString(element, "state"));
-
-        dto.setSensitiveDynamicPropertyNames(getSensitivePropertyNames(element));
-        dto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-
-        return dto;
-    }
-
-    public static FlowRegistryClientDTO getFlowRegistryClient(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final FlowRegistryClientDTO dto = new FlowRegistryClientDTO();
-
-        if (isOldStyleRegistryClient(element)) {
-            return getFlowRegistryClientFromOldStyleConfig(element);
-        }
-
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setDescription(getString(element, "description"));
-        dto.setUri(getString(element, "uri"));
-
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-
-        dto.setSensitiveDynamicPropertyNames(getSensitivePropertyNames(element));
-        dto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-        dto.setAnnotationData(getString(element, "annotationData"));
-
-        return dto;
-    }
-
-    private static FlowRegistryClientDTO getFlowRegistryClientFromOldStyleConfig(final Element element) {
-        final String id = getString(element, "id");
-        final String name = getString(element, "name");
-        final String url = getString(element, "url");
-        final String description = getString(element, "description");
-
-        final FlowRegistryClientDTO dto = new FlowRegistryClientDTO();
-        dto.setId(id);
-        dto.setName(name);
-        dto.setDescription(description);
-        dto.setUri(url);
-
-        dto.setType(DEPRECATED_FLOW_REGISTRY_CLIENT_TYPE);
-        dto.setBundle(new BundleDTO("org.apache.nifi", "nifi-flow-registry-client-nar", "1.18.0"));
-
-        dto.setSensitiveDynamicPropertyNames(Collections.emptySet());
-        dto.setProperties(Collections.singletonMap("url", url));
-        dto.setAnnotationData(null);
-
-        return dto;
-    }
-
-    private static boolean isOldStyleRegistryClient(final Element element) {
-        final String id = getString(element, "id");
-        final String identifier = getString(element, "identifier");
-        final List<Element> bundleElements = getChildrenByTagName(element, "bundle");
-
-        return id != null && identifier == null && bundleElements.isEmpty();
-    }
-
-    public static ParameterProviderDTO getParameterProvider(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final ParameterProviderDTO dto = new ParameterProviderDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setComments(getString(element, "comment"));
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-
-        dto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-        dto.setAnnotationData(getString(element, "annotationData"));
-
-        return dto;
-    }
-
-    public static ParameterContextDTO getParameterContext(final Element element, final PropertyEncryptor encryptor) {
-        final ParameterContextDTO dto = new ParameterContextDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setDescription(getString(element, "description"));
-
-        final Set<ParameterEntity> parameterDtos = new LinkedHashSet<>();
-        final List<Element> parameterElements = FlowFromDOMFactory.getChildrenByTagName(element, "parameter");
-        for (final Element parameterElement : parameterElements) {
-            final ParameterDTO parameterDto = new ParameterDTO();
-
-            parameterDto.setName(getString(parameterElement, "name"));
-            parameterDto.setDescription(getString(parameterElement, "description"));
-            parameterDto.setSensitive(getBoolean(parameterElement, "sensitive"));
-            parameterDto.setProvided(getBoolean(parameterElement, "provided"));
-
-            final String value = decrypt(getString(parameterElement, "value"), encryptor);
-            parameterDto.setValue(value);
-
-            final ParameterEntity parameterEntity = new ParameterEntity();
-            parameterEntity.setParameter(parameterDto);
-            parameterDtos.add(parameterEntity);
-        }
-        final List<Element> inheritedParameterContextIds = FlowFromDOMFactory.getChildrenByTagName(element, "inheritedParameterContextId");
-        final List<ParameterContextReferenceEntity> parameterContexts = new ArrayList<>();
-        for (final Element inheritedParameterContextElement : inheritedParameterContextIds) {
-            final ParameterContextReferenceEntity parameterContextReference = new ParameterContextReferenceEntity();
-            parameterContextReference.setId(inheritedParameterContextElement.getTextContent());
-            parameterContexts.add(parameterContextReference);
-        }
-        dto.setInheritedParameterContexts(parameterContexts);
-
-        final ParameterProviderConfigurationEntity parameterProviderConfiguration = getParameterProviderConfiguration(element);
-        if (parameterProviderConfiguration != null) {
-            dto.setParameterProviderConfiguration(parameterProviderConfiguration);
-        }
-
-        dto.setParameters(parameterDtos);
-
-        return dto;
-    }
-
-    private static ParameterProviderConfigurationEntity getParameterProviderConfiguration(final Element parameterContextElement) {
-        final String parameterProviderId = getString(parameterContextElement, "parameterProviderId");
-        if (parameterProviderId != null) {
-            final ParameterProviderConfigurationEntity entity = new ParameterProviderConfigurationEntity();
-            entity.setId(parameterProviderId);
-            final ParameterProviderConfigurationDTO dto = new ParameterProviderConfigurationDTO();
-            final String parameterGroupName = getString(parameterContextElement, "parameterGroupName");
-            final Boolean isSynchronized = getBoolean(parameterContextElement, "isSynchronized");
-            dto.setParameterProviderId(parameterProviderId);
-            dto.setParameterGroupName(parameterGroupName);
-            dto.setSynchronized(isSynchronized);
-            entity.setComponent(dto);
-
-            return entity;
-        }
-        return null;
-    }
-
-    public static ProcessGroupDTO getProcessGroup(final String parentId, final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion encodingVersion) {
-        final ProcessGroupDTO dto = new ProcessGroupDTO();
-        final String groupId = getString(element, "id");
-        dto.setId(groupId);
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setParentGroupId(parentId);
-        dto.setName(getString(element, "name"));
-        dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
-        dto.setComments(getString(element, "comment"));
-        dto.setFlowfileConcurrency(getString(element, "flowfileConcurrency"));
-        dto.setFlowfileOutboundPolicy(getString(element, "flowfileOutboundPolicy"));
-        dto.setDefaultFlowFileExpiration(getString(element, "defaultFlowFileExpiration"));
-        dto.setDefaultBackPressureObjectThreshold(getLong(element, "defaultBackPressureObjectThreshold"));
-        dto.setDefaultBackPressureDataSizeThreshold(getString(element, "defaultBackPressureDataSizeThreshold"));
-        dto.setLogFileSuffix(getString(element, "logFileSuffix"));
-
-        final Element versionControlInfoElement = DomUtils.getChild(element, "versionControlInformation");
-        dto.setVersionControlInformation(getVersionControlInformation(versionControlInfoElement));
-
-        final String parameterContextId = getString(element, "parameterContextId");
-        final ParameterContextReferenceEntity parameterContextReference = new ParameterContextReferenceEntity();
-        parameterContextReference.setId(parameterContextId);
-        dto.setParameterContext(parameterContextReference);
-
-        final Set<ProcessorDTO> processors = new HashSet<>();
-        final Set<ConnectionDTO> connections = new HashSet<>();
-        final Set<FunnelDTO> funnels = new HashSet<>();
-        final Set<PortDTO> inputPorts = new HashSet<>();
-        final Set<PortDTO> outputPorts = new HashSet<>();
-        final Set<LabelDTO> labels = new HashSet<>();
-        final Set<ProcessGroupDTO> processGroups = new HashSet<>();
-        final Set<RemoteProcessGroupDTO> remoteProcessGroups = new HashSet<>();
-        final Set<ControllerServiceDTO> controllerServices = new HashSet<>();
-
-        NodeList nodeList = DomUtils.getChildNodesByTagName(element, "processor");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            processors.add(getProcessor((Element) nodeList.item(i), encryptor, encodingVersion));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "funnel");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            funnels.add(getFunnel((Element) nodeList.item(i)));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "inputPort");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            inputPorts.add(getPort((Element) nodeList.item(i)));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "outputPort");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            outputPorts.add(getPort((Element) nodeList.item(i)));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "label");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            labels.add(getLabel((Element) nodeList.item(i)));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "processGroup");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            processGroups.add(getProcessGroup(groupId, (Element) nodeList.item(i), encryptor, encodingVersion));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "remoteProcessGroup");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            remoteProcessGroups.add(getRemoteProcessGroup((Element) nodeList.item(i), encryptor));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "connection");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            connections.add(getConnection((Element) nodeList.item(i)));
-        }
-
-        nodeList = DomUtils.getChildNodesByTagName(element, "controllerService");
-        for (int i=0; i < nodeList.getLength(); i++) {
-            controllerServices.add(getControllerService((Element) nodeList.item(i), encryptor, encodingVersion));
-        }
-
-        final FlowSnippetDTO groupContents = new FlowSnippetDTO();
-        groupContents.setConnections(connections);
-        groupContents.setFunnels(funnels);
-        groupContents.setInputPorts(inputPorts);
-        groupContents.setLabels(labels);
-        groupContents.setOutputPorts(outputPorts);
-        groupContents.setProcessGroups(processGroups);
-        groupContents.setProcessors(processors);
-        groupContents.setRemoteProcessGroups(remoteProcessGroups);
-        groupContents.setControllerServices(controllerServices);
-
-        dto.setContents(groupContents);
-        return dto;
-    }
-
-    private static VersionControlInformationDTO getVersionControlInformation(final Element versionControlInfoElement) {
-        if (versionControlInfoElement == null) {
-            return null;
-        }
-
-        final VersionControlInformationDTO dto = new VersionControlInformationDTO();
-        dto.setRegistryId(getString(versionControlInfoElement, "registryId"));
-        dto.setBucketId(getString(versionControlInfoElement, "bucketId"));
-        dto.setBucketName(getString(versionControlInfoElement, "bucketName"));
-        dto.setFlowId(getString(versionControlInfoElement, "flowId"));
-        dto.setFlowName(getString(versionControlInfoElement, "flowName"));
-        dto.setFlowDescription(getString(versionControlInfoElement, "flowDescription"));
-        dto.setVersion(getInt(versionControlInfoElement, "version"));
-        dto.setStorageLocation(getString(versionControlInfoElement, "storageLocation"));
-        return dto;
-    }
-
-    public static ConnectionDTO getConnection(final Element element) {
-        final ConnectionDTO dto = new ConnectionDTO();
-        dto.setId(getString(element, "id"));
-        dto.setName(getString(element, "name"));
-        dto.setLabelIndex(getOptionalInt(element, "labelIndex"));
-        dto.setzIndex(getOptionalLong(element, "zIndex"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-
-        final List<PositionDTO> bends = new ArrayList<>();
-        final Element bendPointsElement = DomUtils.getChild(element, "bendPoints");
-        if (bendPointsElement != null) {
-            for (final Element bendPointElement : getChildrenByTagName(bendPointsElement, "bendPoint")) {
-                final PositionDTO bend = getPosition(bendPointElement);
-                bends.add(bend);
-            }
-        }
-        dto.setBends(bends);
-
-        final ConnectableDTO sourceConnectable = new ConnectableDTO();
-        dto.setSource(sourceConnectable);
-        sourceConnectable.setId(getString(element, "sourceId"));
-        sourceConnectable.setGroupId(getString(element, "sourceGroupId"));
-        sourceConnectable.setType(getString(element, "sourceType"));
-
-        final ConnectableDTO destConnectable = new ConnectableDTO();
-        dto.setDestination(destConnectable);
-        destConnectable.setId(getString(element, "destinationId"));
-        destConnectable.setGroupId(getString(element, "destinationGroupId"));
-        destConnectable.setType(getString(element, "destinationType"));
-
-        final Set<String> relationships = new HashSet<>();
-        final List<Element> relationshipNodeList = getChildrenByTagName(element, "relationship");
-        for (final Element relationshipElem : relationshipNodeList) {
-            relationships.add(relationshipElem.getTextContent());
-        }
-        dto.setSelectedRelationships(relationships);
-
-        dto.setBackPressureObjectThreshold(getLong(element, "maxWorkQueueSize"));
-
-        final String maxDataSize = getString(element, "maxWorkQueueDataSize");
-        if (maxDataSize != null && !maxDataSize.trim().isEmpty()) {
-            dto.setBackPressureDataSizeThreshold(maxDataSize);
-        }
-
-        String expiration = getString(element, "flowFileExpiration");
-        if (expiration == null) {
-            expiration = "0 sec";
-        }
-        dto.setFlowFileExpiration(expiration);
-
-        final List<String> prioritizerClasses = new ArrayList<>();
-        final List<Element> prioritizerNodeList = getChildrenByTagName(element, "queuePrioritizerClass");
-        for (final Element prioritizerElement : prioritizerNodeList) {
-            prioritizerClasses.add(prioritizerElement.getTextContent().trim());
-        }
-        dto.setPrioritizers(prioritizerClasses);
-
-        dto.setLoadBalanceStrategy(getString(element, "loadBalanceStrategy"));
-        dto.setLoadBalancePartitionAttribute(getString(element, "partitioningAttribute"));
-        dto.setLoadBalanceCompression(getString(element, "loadBalanceCompression"));
-
-        return dto;
-    }
-
-    public static RemoteProcessGroupDTO getRemoteProcessGroup(final Element element, final PropertyEncryptor encryptor) {
-        final RemoteProcessGroupDTO dto = new RemoteProcessGroupDTO();
-        dto.setId(getString(element, "id"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setName(getString(element, "name"));
-        dto.setTargetUri(getString(element, "url"));
-        dto.setTargetUris(getString(element, "urls"));
-        dto.setTransmitting(getBoolean(element, "transmitting"));
-        dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
-        dto.setCommunicationsTimeout(getString(element, "timeout"));
-        dto.setComments(getString(element, "comment"));
-        dto.setYieldDuration(getString(element, "yieldPeriod"));
-        dto.setTransportProtocol(getString(element, "transportProtocol"));
-        dto.setProxyHost(getString(element, "proxyHost"));
-        dto.setProxyPort(getOptionalInt(element, "proxyPort"));
-        dto.setProxyUser(getString(element, "proxyUser"));
-        dto.setLocalNetworkInterface(getString(element, "networkInterface"));
-
-        final String rawPassword = getString(element, "proxyPassword");
-        final String proxyPassword = encryptor == null ? rawPassword : decrypt(rawPassword, encryptor);
-        dto.setProxyPassword(proxyPassword);
-
-        return dto;
-    }
-
-    public static LabelDTO getLabel(final Element element) {
-        final LabelDTO dto = new LabelDTO();
-        dto.setId(getString(element, "id"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setLabel(getString(element, "value"));
-        dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
-        final Size size = getSize(DomUtils.getChild(element, "size"));
-        dto.setWidth(size.getWidth());
-        dto.setHeight(size.getHeight());
-        dto.setzIndex(getLong(element, "zIndex"));
-        dto.setStyle(getStyle(DomUtils.getChild(element, "styles")));
-
-        return dto;
-    }
-
-    public static FunnelDTO getFunnel(final Element element) {
-        final FunnelDTO dto = new FunnelDTO();
-        dto.setId(getString(element, "id"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
-
-        return dto;
-    }
-
-    public static PortDTO getPort(final Element element) {
-        final PortDTO portDTO = new PortDTO();
-        portDTO.setId(getString(element, "id"));
-        portDTO.setVersionedComponentId(getString(element, "versionedComponentId"));
-        portDTO.setPosition(getPosition(DomUtils.getChild(element, "position")));
-        portDTO.setName(getString(element, "name"));
-        portDTO.setComments(getString(element, "comments"));
-        portDTO.setAllowRemoteAccess(getBoolean(element, "allowRemoteAccess"));
-        final ScheduledState scheduledState = getScheduledState(element);
-        portDTO.setState(scheduledState.toString());
-
-        final List<Element> maxTasksElements = getChildrenByTagName(element, "maxConcurrentTasks");
-        if (!maxTasksElements.isEmpty()) {
-            portDTO.setConcurrentlySchedulableTaskCount(Integer.parseInt(maxTasksElements.get(0).getTextContent()));
-        }
-
-        final List<Element> userAccessControls = getChildrenByTagName(element, "userAccessControl");
-        if (userAccessControls != null && !userAccessControls.isEmpty()) {
-            final Set<String> users = new HashSet<>();
-            portDTO.setUserAccessControl(users);
-            for (final Element userElement : userAccessControls) {
-                users.add(userElement.getTextContent());
-            }
-        }
-
-        final List<Element> groupAccessControls = getChildrenByTagName(element, "groupAccessControl");
-        if (groupAccessControls != null && !groupAccessControls.isEmpty()) {
-            final Set<String> groups = new HashSet<>();
-            portDTO.setGroupAccessControl(groups);
-            for (final Element groupElement : groupAccessControls) {
-                groups.add(groupElement.getTextContent());
-            }
-        }
-
-        return portDTO;
-    }
-
-    public static RemoteProcessGroupPortDescriptor getRemoteProcessGroupPort(final Element element) {
-        final StandardRemoteProcessGroupPortDescriptor descriptor = new StandardRemoteProcessGroupPortDescriptor();
-
-        // What we have serialized is the ID of the Remote Process Group, followed by a dash ('-'), followed by
-        // the actual ID of the port; we want to get rid of the remote process group id.
-        String id = getString(element, "id");
-        if (id.length() > 37) {
-            id = id.substring(37);
-        }
-
-        descriptor.setId(id);
-
-        final String targetId = getString(element, "targetId");
-        descriptor.setTargetId(targetId == null ? id : targetId);
-
-        descriptor.setVersionedComponentId(getString(element, "versionedComponentId"));
-        descriptor.setName(getString(element, "name"));
-        descriptor.setComments(getString(element, "comments"));
-        descriptor.setConcurrentlySchedulableTaskCount(getInt(element, "maxConcurrentTasks"));
-        descriptor.setUseCompression(getBoolean(element, "useCompression"));
-        descriptor.setBatchCount(getOptionalInt(element, "batchCount"));
-        descriptor.setBatchSize(getString(element, "batchSize"));
-        descriptor.setBatchDuration(getString(element, "batchDuration"));
-        descriptor.setTransmitting("RUNNING".equalsIgnoreCase(getString(element, "scheduledState")));
-
-        return descriptor;
-    }
-
-    public static ProcessorDTO getProcessor(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final ProcessorDTO dto = new ProcessorDTO();
-
-        dto.setId(getString(element, "id"));
-        dto.setVersionedComponentId(getString(element, "versionedComponentId"));
-        dto.setName(getString(element, "name"));
-        dto.setType(getString(element, "class"));
-        dto.setBundle(getBundle(DomUtils.getChild(element, "bundle")));
-        dto.setPosition(getPosition(DomUtils.getChild(element, "position")));
-        dto.setStyle(getStyle(DomUtils.getChild(element, "styles")));
-
-        final ProcessorConfigDTO configDto = new ProcessorConfigDTO();
-        dto.setConfig(configDto);
-        configDto.setComments(getString(element, "comment"));
-        configDto.setConcurrentlySchedulableTaskCount(getInt(element, "maxConcurrentTasks"));
-        final String schedulingPeriod = getString(element, "schedulingPeriod");
-        configDto.setSchedulingPeriod(schedulingPeriod);
-        configDto.setPenaltyDuration(getString(element, "penalizationPeriod"));
-        configDto.setYieldDuration(getString(element, "yieldPeriod"));
-        configDto.setBulletinLevel(getString(element, "bulletinLevel"));
-        configDto.setLossTolerant(getBoolean(element, "lossTolerant"));
-        if (getString(element, "retryCount") != null) {
-            configDto.setRetryCount(getInt(element, "retryCount"));
-        } else {
-            configDto.setRetryCount(10);
-        }
-        configDto.setMaxBackoffPeriod(getString(element, "maxBackoffPeriod"));
-        configDto.setBackoffMechanism(getString(element, "backoffMechanism"));
-
-        final Set<String> retriedRelationships = new HashSet<>();
-        final List<Element> retriedRelationshipList = getChildrenByTagName(element, "retriedRelationship");
-        for (final Element retriedRelationship : retriedRelationshipList) {
-            retriedRelationships.add(retriedRelationship.getTextContent());
-        }
-        configDto.setRetriedRelationships(retriedRelationships);
-
-        final ScheduledState scheduledState = getScheduledState(element);
-        dto.setState(scheduledState.toString());
-
-        // handle scheduling strategy
-        final String schedulingStrategyName = getString(element, "schedulingStrategy");
-        if (schedulingStrategyName == null || schedulingStrategyName.trim().isEmpty()) {
-            configDto.setSchedulingStrategy(SchedulingStrategy.TIMER_DRIVEN.name());
-        } else {
-            configDto.setSchedulingStrategy(schedulingStrategyName.trim());
-        }
-
-        // handle execution node
-        final String executionNode = getString(element, "executionNode");
-        if (executionNode == null || executionNode.trim().isEmpty()) {
-            configDto.setExecutionNode(ExecutionNode.ALL.name());
-        } else {
-            configDto.setExecutionNode(executionNode.trim());
-        }
-
-        final Long runDurationNanos = getOptionalLong(element, "runDurationNanos");
-        if (runDurationNanos != null) {
-            configDto.setRunDurationMillis(TimeUnit.NANOSECONDS.toMillis(runDurationNanos));
-        }
-
-        configDto.setSensitiveDynamicPropertyNames(getSensitivePropertyNames(element));
-        configDto.setProperties(getProperties(element, encryptor, flowEncodingVersion));
-        configDto.setAnnotationData(getString(element, "annotationData"));
-
-        final Set<String> autoTerminatedRelationships = new HashSet<>();
-        final List<Element> autoTerminateList = getChildrenByTagName(element, "autoTerminatedRelationship");
-        for (final Element autoTerminateElement : autoTerminateList) {
-            autoTerminatedRelationships.add(autoTerminateElement.getTextContent());
-        }
-        configDto.setAutoTerminatedRelationships(autoTerminatedRelationships);
-
-        return dto;
-    }
-
-    private static Set<String> getSensitivePropertyNames(final Element element) {
-        final Set<String> sensitivePropertyNames = new LinkedHashSet<>();
-
-        final List<Element> propertyElements = getChildrenByTagName(element, "property");
-        for (final Element propertyElement : propertyElements) {
-            final String rawPropertyValue = getString(propertyElement, "value");
-            if (isValueSensitive(rawPropertyValue)) {
-                final String name = getString(propertyElement, "name");
-                sensitivePropertyNames.add(name);
-            }
-        }
-
-        return sensitivePropertyNames;
-    }
-
-    private static LinkedHashMap<String, String> getProperties(final Element element, final PropertyEncryptor encryptor, final FlowEncodingVersion flowEncodingVersion) {
-        final LinkedHashMap<String, String> properties = new LinkedHashMap<>();
-        final List<Element> propertyNodeList = getChildrenByTagName(element, "property");
-
-        final ParameterParser parameterParser = new ExpressionLanguageAwareParameterParser();
-
-        for (final Element propertyElement : propertyNodeList) {
-            final String name = getString(propertyElement, "name");
-
-            final String rawPropertyValue = getString(propertyElement, "value");
-            final String value = encryptor == null ? rawPropertyValue : decrypt(rawPropertyValue, encryptor);
-
-            if (flowEncodingVersion == null || (flowEncodingVersion.getMajorVersion() <= 1 && flowEncodingVersion.getMinorVersion() < 4)) {
-                // Version 1.4 introduced the #{paramName} syntax for referencing parameters. If the version is less than 1.4, we must escpae any
-                // #{...} reference that we find.
-                final ParameterTokenList parameterTokenList = parameterParser.parseTokens(value);
-                final String escaped = parameterTokenList.escape();
-                properties.put(name, escaped);
-            } else {
-                properties.put(name, value);
-            }
-        }
-
-        return properties;
-    }
-
-    private static String getString(final Element element, final String childElementName) {
-        final List<Element> nodeList = getChildrenByTagName(element, childElementName);
-        if (nodeList == null || nodeList.isEmpty()) {
-            return null;
-        }
-        final Element childElement = nodeList.get(0);
-        return childElement.getTextContent();
-    }
-
-    private static Integer getOptionalInt(final Element element, final String childElementName) {
-        final List<Element> nodeList = getChildrenByTagName(element, childElementName);
-        if (nodeList == null || nodeList.isEmpty()) {
-            return null;
-        }
-        final Element childElement = nodeList.get(0);
-        final String val = childElement.getTextContent();
-        if (val == null) {
-            return null;
-        }
-        return Integer.parseInt(val);
-    }
-
-    private static Long getOptionalLong(final Element element, final String childElementName) {
-        final List<Element> nodeList = getChildrenByTagName(element, childElementName);
-        if (nodeList == null || nodeList.isEmpty()) {
-            return null;
-        }
-        final Element childElement = nodeList.get(0);
-        final String val = childElement.getTextContent();
-        if (val == null) {
-            return null;
-        }
-        return Long.parseLong(val);
-    }
-
-    private static int getInt(final Element element, final String childElementName) {
-        return Integer.parseInt(getString(element, childElementName));
-    }
-
-    private static Long getLong(final Element element, final String childElementName) {
-        // missing element must be handled gracefully, e.g. flow definition from a previous version without this element
-        String longString = getString(element, childElementName);
-        return longString == null ? null : Long.parseLong(longString);
-    }
-
-    private static boolean getBoolean(final Element element, final String childElementName) {
-        return Boolean.parseBoolean(getString(element, childElementName));
-    }
-
-    private static ScheduledState getScheduledState(final Element element) {
-        return ScheduledState.valueOf(getString(element, "scheduledState"));
-    }
-
-    private static List<Element> getChildrenByTagName(final Element element, final String childElementName) {
-        return DomUtils.getChildElementsByTagName(element, childElementName);
-    }
-
-    private static String decrypt(final String value, final PropertyEncryptor encryptor) {
-        if (isValueSensitive(value)) {
-            try {
-                return encryptor.decrypt(value.substring(FlowSerializer.ENC_PREFIX.length(), value.length() - FlowSerializer.ENC_SUFFIX.length()));
-            } catch (EncryptionException e) {
-                final String moreDescriptiveMessage = "There was a problem decrypting a sensitive flow configuration value. " +
-                        "Check that the nifi.sensitive.props.key value in nifi.properties matches the value used to encrypt the flow.xml.gz file";
-                logger.error(moreDescriptiveMessage, e);
-                throw new EncryptionException(moreDescriptiveMessage, e);
-            }
-        } else {
-            return value;
-        }
-    }
-
-    private static boolean isValueSensitive(final String value) {
-        return value != null && value.startsWith(FlowSerializer.ENC_PREFIX) && value.endsWith(FlowSerializer.ENC_SUFFIX);
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/RunningComponentSetFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/RunningComponentSetFilter.java
index cb0db371ca..3fa49c3cac 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/RunningComponentSetFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/RunningComponentSetFilter.java
@@ -53,7 +53,9 @@ public class RunningComponentSetFilter implements ComponentSetFilter {
     public RunningComponentSetFilter(final VersionedDataflow dataflow) {
         dataflow.getControllerServices().forEach(service -> controllerServices.put(service.getInstanceIdentifier(), service));
         dataflow.getReportingTasks().forEach(task -> reportingTasks.put(task.getInstanceIdentifier(), task));
-        dataflow.getFlowAnalysisRules().forEach(rule -> flowAnalysisRules.put(rule.getInstanceIdentifier(), rule));
+        if (dataflow.getFlowAnalysisRules() != null) {
+            dataflow.getFlowAnalysisRules().forEach(rule -> flowAnalysisRules.put(rule.getInstanceIdentifier(), rule));
+        }
         flatten(dataflow.getRootGroup());
     }
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
deleted file mode 100644
index 4339d3040a..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
+++ /dev/null
@@ -1,716 +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.controller.serialization;
-
-import org.apache.nifi.bundle.BundleCoordinate;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.connectable.ConnectableType;
-import org.apache.nifi.connectable.Connection;
-import org.apache.nifi.connectable.Funnel;
-import org.apache.nifi.connectable.Port;
-import org.apache.nifi.connectable.Position;
-import org.apache.nifi.connectable.Size;
-import org.apache.nifi.controller.FlowAnalysisRuleNode;
-import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.ParameterProviderNode;
-import org.apache.nifi.controller.ProcessorNode;
-import org.apache.nifi.controller.ReportingTaskNode;
-import org.apache.nifi.controller.flow.FlowManager;
-import org.apache.nifi.controller.label.Label;
-import org.apache.nifi.controller.service.ControllerServiceNode;
-import org.apache.nifi.controller.service.ControllerServiceState;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.flowfile.FlowFilePrioritizer;
-import org.apache.nifi.groups.ProcessGroup;
-import org.apache.nifi.groups.RemoteProcessGroup;
-import org.apache.nifi.parameter.Parameter;
-import org.apache.nifi.parameter.ParameterContext;
-import org.apache.nifi.parameter.ParameterContextManager;
-import org.apache.nifi.parameter.ParameterDescriptor;
-import org.apache.nifi.parameter.ParameterProviderConfiguration;
-import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.registry.flow.FlowRegistryClientNode;
-import org.apache.nifi.registry.flow.VersionControlInformation;
-import org.apache.nifi.remote.PublicPort;
-import org.apache.nifi.remote.RemoteGroupPort;
-import org.apache.nifi.util.CharacterFilterUtils;
-import org.apache.nifi.util.StringUtils;
-import org.apache.nifi.xml.processing.ProcessingException;
-import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
-import org.apache.nifi.xml.processing.transform.StandardTransformProvider;
-import org.w3c.dom.DOMException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-/**
-* Serializes a Flow Controller as XML to an output stream.
-*
-* NOT THREAD-SAFE.
-*/
-public class StandardFlowSerializer implements FlowSerializer<Document> {
-
-   private static final String MAX_ENCODING_VERSION = "1.4";
-
-   public StandardFlowSerializer() {
-   }
-
-
-   @Override
-   public Document transform(final FlowController controller, final ScheduledStateLookup scheduledStateLookup) throws FlowSerializationException {
-       final PropertyEncryptor encryptor = controller.getEncryptor();
-       try {
-           // create a new, empty document
-           final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
-           documentProvider.setNamespaceAware(true);
-           final Document doc = documentProvider.newDocument();
-
-           // populate document with controller state
-           final Element rootNode = doc.createElement("flowController");
-           rootNode.setAttribute("encoding-version", MAX_ENCODING_VERSION);
-           doc.appendChild(rootNode);
-           addTextElement(rootNode, "maxTimerDrivenThreadCount", controller.getMaxTimerDrivenThreadCount());
-
-           final Element registriesElement = doc.createElement("registries");
-           rootNode.appendChild(registriesElement);
-           addFlowRegistryClients(registriesElement, controller.getFlowManager(), encryptor);
-
-           final Element parameterContextsElement = doc.createElement("parameterContexts");
-           rootNode.appendChild(parameterContextsElement);
-           addParameterContexts(parameterContextsElement, controller.getFlowManager().getParameterContextManager(), encryptor);
-
-           addProcessGroup(rootNode, controller.getFlowManager().getRootGroup(), "rootGroup", scheduledStateLookup, encryptor);
-
-           // Add root-level controller services
-           final Element controllerServicesNode = doc.createElement("controllerServices");
-           rootNode.appendChild(controllerServicesNode);
-           for (final ControllerServiceNode serviceNode : controller.getFlowManager().getRootControllerServices()) {
-               addControllerService(controllerServicesNode, serviceNode, encryptor);
-           }
-
-           final Element reportingTasksNode = doc.createElement("reportingTasks");
-           rootNode.appendChild(reportingTasksNode);
-           for (final ReportingTaskNode taskNode : controller.getAllReportingTasks()) {
-               addReportingTask(reportingTasksNode, taskNode, encryptor);
-           }
-
-           final Element flowAnalysisRulesNode = doc.createElement("flowAnalysisRules");
-           rootNode.appendChild(flowAnalysisRulesNode);
-           for (final FlowAnalysisRuleNode flowAnalysisRuleNode : controller.getAllFlowAnalysisRules()) {
-               addFlowAnalysisRule(flowAnalysisRulesNode, flowAnalysisRuleNode, encryptor);
-           }
-
-           final Element parameterProvidersNode = doc.createElement("parameterProviders");
-           rootNode.appendChild(parameterProvidersNode);
-           for (final ParameterProviderNode providerNode : controller.getFlowManager().getAllParameterProviders()) {
-               addParameterProvider(parameterProvidersNode, providerNode, encryptor);
-           }
-
-           return doc;
-       } catch (final ProcessingException | DOMException | IllegalArgumentException e) {
-           throw new FlowSerializationException(e);
-       }
-   }
-
-   @Override
-   public void serialize(final Document flowConfiguration, final OutputStream os) throws FlowSerializationException {
-       try {
-           final DOMSource domSource = new DOMSource(flowConfiguration);
-           final StreamResult streamResult = new StreamResult(new BufferedOutputStream(os));
-
-           // configure the transformer and convert the DOM
-           final StandardTransformProvider transformProvider = new StandardTransformProvider();
-           transformProvider.setIndent(true);
-
-           // transform the document to byte stream
-           transformProvider.transform(domSource, streamResult);
-
-       } catch (final DOMException | IllegalArgumentException | ProcessingException e) {
-           throw new FlowSerializationException(e);
-       }
-   }
-
-   private void addParameterContexts(final Element parentElement, final ParameterContextManager parameterContextManager,
-                                     final PropertyEncryptor encryptor) {
-       for (final ParameterContext parameterContext : parameterContextManager.getParameterContexts()) {
-           final Element parameterContextElement = parentElement.getOwnerDocument().createElement("parameterContext");
-           parentElement.appendChild(parameterContextElement);
-
-           addStringElement(parameterContextElement, "id", parameterContext.getIdentifier());
-           addStringElement(parameterContextElement, "name", parameterContext.getName());
-           addStringElement(parameterContextElement, "description", parameterContext.getDescription());
-
-           for(final ParameterContext childContext : parameterContext.getInheritedParameterContexts()) {
-               addStringElement(parameterContextElement, "inheritedParameterContextId", childContext.getIdentifier());
-           }
-           if (parameterContext.getParameterProviderConfiguration() != null) {
-               final ParameterProviderConfiguration parameterProviderConfiguration = parameterContext.getParameterProviderConfiguration();
-               addStringElement(parameterContextElement, "parameterProviderId", parameterProviderConfiguration.getParameterProviderId());
-               if (parameterProviderConfiguration.getParameterGroupName() != null) {
-                   addStringElement(parameterContextElement, "parameterGroupName", parameterProviderConfiguration.getParameterGroupName());
-               }
-               addStringElement(parameterContextElement, "isSynchronized", String.valueOf(parameterProviderConfiguration.isSynchronized()));
-           }
-
-           for (final Parameter parameter : parameterContext.getParameters().values()) {
-               addParameter(parameterContextElement, parameter, encryptor);
-           }
-       }
-   }
-
-   private void addParameter(final Element parentElement, final Parameter parameter, final PropertyEncryptor encryptor) {
-       final Element parameterElement = parentElement.getOwnerDocument().createElement("parameter");
-       parentElement.appendChild(parameterElement);
-
-       final ParameterDescriptor descriptor = parameter.getDescriptor();
-       addStringElement(parameterElement, "name", descriptor.getName());
-       addStringElement(parameterElement, "description", descriptor.getDescription());
-       addStringElement(parameterElement, "sensitive", String.valueOf(descriptor.isSensitive()));
-       addStringElement(parameterElement, "provided", String.valueOf(parameter.isProvided()));
-
-       if (parameter.getValue() != null) {
-           if (descriptor.isSensitive()) {
-               final String parameterValue = parameter.getValue();
-               addStringElement(parameterElement, "value", parameterValue == null ? null : ENC_PREFIX + encryptor.encrypt(parameterValue) + ENC_SUFFIX);
-           } else {
-               addStringElement(parameterElement, "value", parameter.getValue());
-           }
-       }
-   }
-
-   private void addFlowRegistryClients(final Element parentElement, final FlowManager flowManager, final PropertyEncryptor encryptor) {
-       for (final String registryId : flowManager.getAllFlowRegistryClients().stream().map(FlowRegistryClientNode::getIdentifier).collect(Collectors.toSet())) {
-           final FlowRegistryClientNode flowRegistry = flowManager.getFlowRegistryClient(registryId);
-
-           final Element registryElement = parentElement.getOwnerDocument().createElement("flowRegistry");
-           parentElement.appendChild(registryElement);
-
-           addTextElement(registryElement, "id", flowRegistry.getIdentifier());
-           addTextElement(registryElement, "name", flowRegistry.getName());
-           addTextElement(registryElement, "description", flowRegistry.getDescription());
-           addTextElement(registryElement, "class", flowRegistry.getCanonicalClassName());
-           addBundle(registryElement, flowRegistry.getBundleCoordinate());
-           addConfiguration(registryElement, flowRegistry.getRawPropertyValues(), flowRegistry.getAnnotationData(), encryptor);
-       }
-   }
-
-   private void addStringElement(final Element parentElement, final String elementName, final String value) {
-       final Element childElement = parentElement.getOwnerDocument().createElement(elementName);
-       childElement.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(value));
-       parentElement.appendChild(childElement);
-   }
-
-   private void addSize(final Element parentElement, final Size size) {
-       final Element element = parentElement.getOwnerDocument().createElement("size");
-       element.setAttribute("width", String.valueOf(size.getWidth()));
-       element.setAttribute("height", String.valueOf(size.getHeight()));
-       parentElement.appendChild(element);
-   }
-
-   private void addPosition(final Element parentElement, final Position position) {
-       addPosition(parentElement, position, "position");
-   }
-
-   private void addPosition(final Element parentElement, final Position position, final String elementName) {
-       final Element element = parentElement.getOwnerDocument().createElement(elementName);
-       element.setAttribute("x", String.valueOf(position.getX()));
-       element.setAttribute("y", String.valueOf(position.getY()));
-       parentElement.appendChild(element);
-   }
-
-   private void addProcessGroup(final Element parentElement, final ProcessGroup group, final String elementName, final ScheduledStateLookup scheduledStateLookup,
-                                final PropertyEncryptor encryptor) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement(elementName);
-       parentElement.appendChild(element);
-       addTextElement(element, "id", group.getIdentifier());
-       addTextElement(element, "versionedComponentId", group.getVersionedComponentId());
-       addTextElement(element, "name", group.getName());
-       addPosition(element, group.getPosition());
-       addTextElement(element, "comment", group.getComments());
-       addTextElement(element, "flowfileConcurrency", group.getFlowFileConcurrency().name());
-       addTextElement(element, "flowfileOutboundPolicy", group.getFlowFileOutboundPolicy().name());
-       addTextElement(element, "defaultFlowFileExpiration", group.getDefaultFlowFileExpiration());
-       addTextElement(element, "defaultBackPressureObjectThreshold", group.getDefaultBackPressureObjectThreshold());
-       addTextElement(element, "defaultBackPressureDataSizeThreshold", group.getDefaultBackPressureDataSizeThreshold());
-       addTextElement(element, "logFileSuffix", group.getLogFileSuffix());
-
-       final VersionControlInformation versionControlInfo = group.getVersionControlInformation();
-       if (versionControlInfo != null) {
-           final Element versionControlInfoElement = doc.createElement("versionControlInformation");
-           addTextElement(versionControlInfoElement, "registryId", versionControlInfo.getRegistryIdentifier());
-           addTextElement(versionControlInfoElement, "bucketId", versionControlInfo.getBucketIdentifier());
-           addTextElement(versionControlInfoElement, "bucketName", versionControlInfo.getBucketName());
-           addTextElement(versionControlInfoElement, "flowId", versionControlInfo.getFlowIdentifier());
-           addTextElement(versionControlInfoElement, "flowName", versionControlInfo.getFlowName());
-           addTextElement(versionControlInfoElement, "flowDescription", versionControlInfo.getFlowDescription());
-           addTextElement(versionControlInfoElement, "version", versionControlInfo.getVersion());
-           addTextElement(versionControlInfoElement, "storageLocation", versionControlInfo.getStorageLocation());
-           element.appendChild(versionControlInfoElement);
-       }
-
-       for (final ProcessorNode processor : group.getProcessors()) {
-           addProcessor(element, processor, scheduledStateLookup, encryptor);
-       }
-
-       for (final Port port : group.getInputPorts()) {
-           if (port instanceof PublicPort) {
-               addPublicPort(element, (PublicPort) port, "inputPort", scheduledStateLookup);
-           } else {
-               addPort(element, port, "inputPort", scheduledStateLookup);
-           }
-       }
-
-       for (final Port port : group.getOutputPorts()) {
-           if (port instanceof PublicPort) {
-               addPublicPort(element, (PublicPort) port, "outputPort", scheduledStateLookup);
-           } else {
-               addPort(element, port, "outputPort", scheduledStateLookup);
-           }
-       }
-
-       for (final Label label : group.getLabels()) {
-           addLabel(element, label);
-       }
-
-       for (final Funnel funnel : group.getFunnels()) {
-           addFunnel(element, funnel);
-       }
-
-       for (final ProcessGroup childGroup : group.getProcessGroups()) {
-           addProcessGroup(element, childGroup, "processGroup", scheduledStateLookup, encryptor);
-       }
-
-       for (final RemoteProcessGroup remoteRef : group.getRemoteProcessGroups()) {
-           addRemoteProcessGroup(element, remoteRef, scheduledStateLookup, encryptor);
-       }
-
-       for (final Connection connection : group.getConnections()) {
-           addConnection(element, connection);
-       }
-
-       for (final ControllerServiceNode service : group.getControllerServices(false)) {
-           addControllerService(element, service, encryptor);
-       }
-
-       final ParameterContext parameterContext = group.getParameterContext();
-       if (parameterContext != null) {
-           addTextElement(element, "parameterContextId", parameterContext.getIdentifier());
-       }
-   }
-
-   private static void addBundle(final Element parentElement, final BundleCoordinate coordinate) {
-       // group
-       final Element groupElement = parentElement.getOwnerDocument().createElement("group");
-       groupElement.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(coordinate.getGroup()));
-
-       // artifact
-       final Element artifactElement = parentElement.getOwnerDocument().createElement("artifact");
-       artifactElement.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(coordinate.getId()));
-
-       // version
-       final Element versionElement = parentElement.getOwnerDocument().createElement("version");
-       versionElement.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(coordinate.getVersion()));
-
-       // bundle
-       final Element bundleElement = parentElement.getOwnerDocument().createElement("bundle");
-       bundleElement.appendChild(groupElement);
-       bundleElement.appendChild(artifactElement);
-       bundleElement.appendChild(versionElement);
-
-       parentElement.appendChild(bundleElement);
-   }
-
-   private void addStyle(final Element parentElement, final Map<String, String> style) {
-       final Element element = parentElement.getOwnerDocument().createElement("styles");
-
-       for (final Map.Entry<String, String> entry : style.entrySet()) {
-           final Element styleElement = parentElement.getOwnerDocument().createElement("style");
-           styleElement.setAttribute("name", entry.getKey());
-           styleElement.setTextContent(entry.getValue());
-           element.appendChild(styleElement);
-       }
-
-       parentElement.appendChild(element);
-   }
-
-   private void addLabel(final Element parentElement, final Label label) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement("label");
-       parentElement.appendChild(element);
-       addTextElement(element, "id", label.getIdentifier());
-       addTextElement(element, "versionedComponentId", label.getVersionedComponentId());
-       addTextElement(element, "zIndex", label.getZIndex());
-
-       addPosition(element, label.getPosition());
-       addSize(element, label.getSize());
-       addStyle(element, label.getStyle());
-
-       addTextElement(element, "value", label.getValue());
-       parentElement.appendChild(element);
-   }
-
-   private void addFunnel(final Element parentElement, final Funnel funnel) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement("funnel");
-       parentElement.appendChild(element);
-       addTextElement(element, "id", funnel.getIdentifier());
-       addTextElement(element, "versionedComponentId", funnel.getVersionedComponentId());
-       addPosition(element, funnel.getPosition());
-   }
-
-   private void addRemoteProcessGroup(final Element parentElement, final RemoteProcessGroup remoteRef, final ScheduledStateLookup scheduledStateLookup,
-                                      final PropertyEncryptor encryptor) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement("remoteProcessGroup");
-       parentElement.appendChild(element);
-       addTextElement(element, "id", remoteRef.getIdentifier());
-       addTextElement(element, "versionedComponentId", remoteRef.getVersionedComponentId());
-       addTextElement(element, "name", remoteRef.getName());
-       addPosition(element, remoteRef.getPosition());
-       addTextElement(element, "comment", remoteRef.getComments());
-       addTextElement(element, "url", remoteRef.getTargetUri());
-       addTextElement(element, "urls", remoteRef.getTargetUris());
-       addTextElement(element, "timeout", remoteRef.getCommunicationsTimeout());
-       addTextElement(element, "yieldPeriod", remoteRef.getYieldDuration());
-       addTextElement(element, "transmitting", String.valueOf(remoteRef.isTransmitting()));
-       addTextElement(element, "transportProtocol", remoteRef.getTransportProtocol().name());
-       addTextElement(element, "proxyHost", remoteRef.getProxyHost());
-       if (remoteRef.getProxyPort() != null) {
-           addTextElement(element, "proxyPort", remoteRef.getProxyPort());
-       }
-       addTextElement(element, "proxyUser", remoteRef.getProxyUser());
-       if (!StringUtils.isEmpty(remoteRef.getProxyPassword())) {
-           final String value = ENC_PREFIX + encryptor.encrypt(remoteRef.getProxyPassword()) + ENC_SUFFIX;
-           addTextElement(element, "proxyPassword", value);
-       }
-       if (remoteRef.getNetworkInterface() != null) {
-           addTextElement(element, "networkInterface", remoteRef.getNetworkInterface());
-       }
-
-       for (final RemoteGroupPort port : remoteRef.getInputPorts()) {
-           if (port.hasIncomingConnection()) {
-               addRemoteGroupPort(element, port, "inputPort", scheduledStateLookup);
-           }
-       }
-
-       for (final RemoteGroupPort port : remoteRef.getOutputPorts()) {
-           if (!port.getConnections().isEmpty()) {
-               addRemoteGroupPort(element, port, "outputPort", scheduledStateLookup);
-           }
-       }
-
-       parentElement.appendChild(element);
-   }
-
-   private void addRemoteGroupPort(final Element parentElement, final RemoteGroupPort port, final String elementName, final ScheduledStateLookup scheduledStateLookup) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement(elementName);
-       parentElement.appendChild(element);
-       addTextElement(element, "id", port.getIdentifier());
-       addTextElement(element, "versionedComponentId", port.getVersionedComponentId());
-       addTextElement(element, "name", port.getName());
-       addPosition(element, port.getPosition());
-       addTextElement(element, "comments", port.getComments());
-       addTextElement(element, "scheduledState", scheduledStateLookup.getScheduledState(port).name());
-       addTextElement(element, "targetId", port.getTargetIdentifier());
-       addTextElement(element, "maxConcurrentTasks", port.getMaxConcurrentTasks());
-       addTextElement(element, "useCompression", String.valueOf(port.isUseCompression()));
-       final Integer batchCount = port.getBatchCount();
-       if (batchCount != null && batchCount > 0) {
-           addTextElement(element, "batchCount", batchCount);
-       }
-       final String batchSize = port.getBatchSize();
-       if (batchSize != null && batchSize.length() > 0) {
-           addTextElement(element, "batchSize", batchSize);
-       }
-       final String batchDuration = port.getBatchDuration();
-       if (batchDuration != null && batchDuration.length() > 0) {
-           addTextElement(element, "batchDuration", batchDuration);
-       }
-
-       parentElement.appendChild(element);
-   }
-
-   private void addPort(final Element parentElement, final Port port, final String elementName, final ScheduledStateLookup scheduledStateLookup) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement(elementName);
-       parentElement.appendChild(element);
-       addTextElement(element, "id", port.getIdentifier());
-       addTextElement(element, "versionedComponentId", port.getVersionedComponentId());
-       addTextElement(element, "name", port.getName());
-       addPosition(element, port.getPosition());
-       addTextElement(element, "comments", port.getComments());
-       addTextElement(element, "scheduledState", scheduledStateLookup.getScheduledState(port).name());
-
-       parentElement.appendChild(element);
-   }
-
-   private void addPublicPort(final Element parentElement, final PublicPort port, final String elementName, final ScheduledStateLookup scheduledStateLookup) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement(elementName);
-       parentElement.appendChild(element);
-       addTextElement(element, "id", port.getIdentifier());
-       addTextElement(element, "versionedComponentId", port.getVersionedComponentId());
-       addTextElement(element, "name", port.getName());
-       addPosition(element, port.getPosition());
-       addTextElement(element, "comments", port.getComments());
-       addTextElement(element, "scheduledState", scheduledStateLookup.getScheduledState(port).name());
-       addTextElement(element, "maxConcurrentTasks", String.valueOf(port.getMaxConcurrentTasks()));
-       addTextElement(element, "allowRemoteAccess", Boolean.TRUE.toString());
-       for (final String user : port.getUserAccessControl()) {
-           addTextElement(element, "userAccessControl", user);
-       }
-       for (final String group : port.getGroupAccessControl()) {
-           addTextElement(element, "groupAccessControl", group);
-       }
-
-       parentElement.appendChild(element);
-   }
-
-   private void addProcessor(final Element parentElement, final ProcessorNode processor, final ScheduledStateLookup scheduledStateLookup,
-                             final PropertyEncryptor encryptor) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement("processor");
-       parentElement.appendChild(element);
-       addTextElement(element, "id", processor.getIdentifier());
-       addTextElement(element, "versionedComponentId", processor.getVersionedComponentId());
-       addTextElement(element, "name", processor.getName());
-
-       addPosition(element, processor.getPosition());
-       addStyle(element, processor.getStyle());
-
-       addTextElement(element, "comment", processor.getComments());
-       addTextElement(element, "class", processor.getCanonicalClassName());
-
-       addBundle(element, processor.getBundleCoordinate());
-
-       addTextElement(element, "maxConcurrentTasks", processor.getMaxConcurrentTasks());
-       addTextElement(element, "schedulingPeriod", processor.getSchedulingPeriod());
-       addTextElement(element, "penalizationPeriod", processor.getPenalizationPeriod());
-       addTextElement(element, "yieldPeriod", processor.getYieldPeriod());
-       addTextElement(element, "bulletinLevel", processor.getBulletinLevel().toString());
-       addTextElement(element, "lossTolerant", String.valueOf(processor.isLossTolerant()));
-       addTextElement(element, "scheduledState", scheduledStateLookup.getScheduledState(processor).name());
-       addTextElement(element, "schedulingStrategy", processor.getSchedulingStrategy().name());
-       addTextElement(element, "executionNode", processor.getExecutionNode().name());
-       addTextElement(element, "runDurationNanos", processor.getRunDuration(TimeUnit.NANOSECONDS));
-       addTextElement(element, "retryCount", processor.getRetryCount());
-       addTextElement(element, "backoffMechanism", processor.getBackoffMechanism().name());
-       addTextElement(element, "maxBackoffPeriod", processor.getMaxBackoffPeriod());
-
-       for (final String relationship : processor.getRetriedRelationships()) {
-           addTextElement(element, "retriedRelationship", relationship);
-       }
-
-       addConfiguration(element, processor.getRawPropertyValues(), processor.getAnnotationData(), encryptor);
-
-       for (final Relationship rel : processor.getAutoTerminatedRelationships()) {
-           addTextElement(element, "autoTerminatedRelationship", rel.getName());
-       }
-   }
-
-   private static void addConfiguration(final Element element, final Map<PropertyDescriptor, String> properties, final String annotationData, final PropertyEncryptor encryptor) {
-       final Document doc = element.getOwnerDocument();
-       for (final Map.Entry<PropertyDescriptor, String> entry : properties.entrySet()) {
-           final PropertyDescriptor descriptor = entry.getKey();
-           String value = entry.getValue();
-
-           if (value == null) {
-               value = descriptor.getDefaultValue();
-           }
-
-           if (value != null && descriptor.isSensitive()) {
-               value = ENC_PREFIX + encryptor.encrypt(value) + ENC_SUFFIX;
-           }
-
-           final Element propElement = doc.createElement("property");
-           addTextElement(propElement, "name", descriptor.getName());
-           if (value != null) {
-               addTextElement(propElement, "value", value);
-           }
-
-           element.appendChild(propElement);
-       }
-
-       if (annotationData != null) {
-           addTextElement(element, "annotationData", annotationData);
-       }
-   }
-
-   private void addConnection(final Element parentElement, final Connection connection) {
-       final Document doc = parentElement.getOwnerDocument();
-       final Element element = doc.createElement("connection");
-       parentElement.appendChild(element);
-       addTextElement(element, "id", connection.getIdentifier());
-       addTextElement(element, "versionedComponentId", connection.getVersionedComponentId());
-       addTextElement(element, "name", connection.getName());
-
-       final Element bendPointsElement = doc.createElement("bendPoints");
-       element.appendChild(bendPointsElement);
-       for (final Position bendPoint : connection.getBendPoints()) {
-           addPosition(bendPointsElement, bendPoint, "bendPoint");
-       }
-
-       addTextElement(element, "labelIndex", connection.getLabelIndex());
-       addTextElement(element, "zIndex", connection.getZIndex());
-
-       final String sourceId = connection.getSource().getIdentifier();
-       final ConnectableType sourceType = connection.getSource().getConnectableType();
-       final String sourceGroupId;
-       if (sourceType == ConnectableType.REMOTE_OUTPUT_PORT) {
-           sourceGroupId = ((RemoteGroupPort) connection.getSource()).getRemoteProcessGroup().getIdentifier();
-       } else {
-           sourceGroupId = connection.getSource().getProcessGroup().getIdentifier();
-       }
-
-       final ConnectableType destinationType = connection.getDestination().getConnectableType();
-       final String destinationId = connection.getDestination().getIdentifier();
-       final String destinationGroupId;
-       if (destinationType == ConnectableType.REMOTE_INPUT_PORT) {
-           destinationGroupId = ((RemoteGroupPort) connection.getDestination()).getRemoteProcessGroup().getIdentifier();
-       } else {
-           destinationGroupId = connection.getDestination().getProcessGroup().getIdentifier();
-       }
-
-       addTextElement(element, "sourceId", sourceId);
-       addTextElement(element, "sourceGroupId", sourceGroupId);
-       addTextElement(element, "sourceType", sourceType.toString());
-
-       addTextElement(element, "destinationId", destinationId);
-       addTextElement(element, "destinationGroupId", destinationGroupId);
-       addTextElement(element, "destinationType", destinationType.toString());
-
-       for (final Relationship relationship : connection.getRelationships()) {
-           addTextElement(element, "relationship", relationship.getName());
-       }
-
-       addTextElement(element, "maxWorkQueueSize", connection.getFlowFileQueue().getBackPressureObjectThreshold());
-       addTextElement(element, "maxWorkQueueDataSize", connection.getFlowFileQueue().getBackPressureDataSizeThreshold());
-
-       addTextElement(element, "flowFileExpiration", connection.getFlowFileQueue().getFlowFileExpiration());
-       for (final FlowFilePrioritizer comparator : connection.getFlowFileQueue().getPriorities()) {
-           final String className = comparator.getClass().getCanonicalName();
-           addTextElement(element, "queuePrioritizerClass", className);
-       }
-
-       addTextElement(element, "loadBalanceStrategy", connection.getFlowFileQueue().getLoadBalanceStrategy().name());
-       addTextElement(element, "partitioningAttribute", connection.getFlowFileQueue().getPartitioningAttribute());
-       addTextElement(element, "loadBalanceCompression", connection.getFlowFileQueue().getLoadBalanceCompression().name());
-
-       parentElement.appendChild(element);
-   }
-
-   public void addControllerService(final Element element, final ControllerServiceNode serviceNode, final PropertyEncryptor encryptor) {
-       final Element serviceElement = element.getOwnerDocument().createElement("controllerService");
-       addTextElement(serviceElement, "id", serviceNode.getIdentifier());
-       addTextElement(serviceElement, "versionedComponentId", serviceNode.getVersionedComponentId());
-       addTextElement(serviceElement, "name", serviceNode.getName());
-       addTextElement(serviceElement, "comment", serviceNode.getComments());
-       addTextElement(serviceElement, "bulletinLevel", serviceNode.getBulletinLevel().toString());
-       addTextElement(serviceElement, "class", serviceNode.getCanonicalClassName());
-
-       addBundle(serviceElement, serviceNode.getBundleCoordinate());
-
-       final ControllerServiceState state = serviceNode.getState();
-       final boolean enabled = (state == ControllerServiceState.ENABLED || state == ControllerServiceState.ENABLING);
-       addTextElement(serviceElement, "enabled", String.valueOf(enabled));
-
-       addConfiguration(serviceElement, serviceNode.getRawPropertyValues(), serviceNode.getAnnotationData(), encryptor);
-
-       element.appendChild(serviceElement);
-   }
-
-   public static void addReportingTask(final Element element, final ReportingTaskNode taskNode, final PropertyEncryptor encryptor) {
-       final Element taskElement = element.getOwnerDocument().createElement("reportingTask");
-       addTextElement(taskElement, "id", taskNode.getIdentifier());
-       addTextElement(taskElement, "name", taskNode.getName());
-       addTextElement(taskElement, "comment", taskNode.getComments());
-       addTextElement(taskElement, "class", taskNode.getCanonicalClassName());
-
-       addBundle(taskElement, taskNode.getBundleCoordinate());
-
-       addTextElement(taskElement, "schedulingPeriod", taskNode.getSchedulingPeriod());
-       addTextElement(taskElement, "scheduledState", taskNode.getScheduledState().name());
-       addTextElement(taskElement, "schedulingStrategy", taskNode.getSchedulingStrategy().name());
-
-       addConfiguration(taskElement, taskNode.getRawPropertyValues(), taskNode.getAnnotationData(), encryptor);
-
-       element.appendChild(taskElement);
-   }
-
-   private void addFlowAnalysisRule(Element flowAnalysisRulesNode, FlowAnalysisRuleNode flowAnalysisRuleNode, final PropertyEncryptor encryptor) {
-       final Element taskElement = flowAnalysisRulesNode.getOwnerDocument().createElement("flowAnalysisRule");
-       addTextElement(taskElement, "id", flowAnalysisRuleNode.getIdentifier());
-       addTextElement(taskElement, "name", flowAnalysisRuleNode.getName());
-       addTextElement(taskElement, "comment", flowAnalysisRuleNode.getComments());
-       addTextElement(taskElement, "class", flowAnalysisRuleNode.getCanonicalClassName());
-
-       addBundle(taskElement, flowAnalysisRuleNode.getBundleCoordinate());
-
-       addTextElement(taskElement, "enforcementPolicy", flowAnalysisRuleNode.getEnforcementPolicy().name());
-       addTextElement(taskElement, "state", flowAnalysisRuleNode.getState().name());
-
-       addConfiguration(taskElement, flowAnalysisRuleNode.getRawPropertyValues(), flowAnalysisRuleNode.getAnnotationData(), encryptor);
-
-       flowAnalysisRulesNode.appendChild(taskElement);
-   }
-
-   public static void addParameterProvider(final Element element, final ParameterProviderNode providerNode, final PropertyEncryptor encryptor) {
-       final Element taskElement = element.getOwnerDocument().createElement("parameterProvider");
-       addTextElement(taskElement, "id", providerNode.getIdentifier());
-       addTextElement(taskElement, "name", providerNode.getName());
-       addTextElement(taskElement, "comment", providerNode.getComments());
-       addTextElement(taskElement, "class", providerNode.getCanonicalClassName());
-
-       addBundle(taskElement, providerNode.getBundleCoordinate());
-
-       addConfiguration(taskElement, providerNode.getRawPropertyValues(), providerNode.getAnnotationData(), encryptor);
-
-       element.appendChild(taskElement);
-   }
-
-   private static void addTextElement(final Element element, final String name, final long value) {
-       addTextElement(element, name, String.valueOf(value));
-   }
-
-   private static void addTextElement(final Element element, final String name, final String value) {
-       final Document doc = element.getOwnerDocument();
-       final Element toAdd = doc.createElement(name);
-       toAdd.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(value)); // value should already be filtered, but just in case ensure there are no invalid xml characters
-       element.appendChild(toAdd);
-   }
-
-   private static void addTextElement(final Element element, final String name, final Optional<String> value) {
-       if (!value.isPresent()) {
-           return;
-       }
-
-       final Document doc = element.getOwnerDocument();
-       final Element toAdd = doc.createElement(name);
-       toAdd.setTextContent(CharacterFilterUtils.filterInvalidXmlCharacters(value.get())); // value should already be filtered, but just in case ensure there are no invalid xml characters
-       element.appendChild(toAdd);
-   }
-}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSynchronizer.java
deleted file mode 100644
index 0b8d142e0c..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSynchronizer.java
+++ /dev/null
@@ -1,64 +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.controller.serialization;
-
-import org.apache.nifi.cluster.protocol.DataFlow;
-import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.MissingBundleException;
-import org.apache.nifi.controller.UninheritableFlowException;
-import org.apache.nifi.controller.XmlFlowSynchronizer;
-import org.apache.nifi.groups.BundleUpdateStrategy;
-import org.apache.nifi.services.FlowService;
-
-public class StandardFlowSynchronizer implements FlowSynchronizer {
-    private final XmlFlowSynchronizer xmlFlowSynchronizer;
-    private final VersionedFlowSynchronizer versionedFlowSynchronizer;
-
-    public StandardFlowSynchronizer(final XmlFlowSynchronizer xmlFlowSynchronizer, final VersionedFlowSynchronizer versionedFlowSynchronizer) {
-        this.xmlFlowSynchronizer = xmlFlowSynchronizer;
-        this.versionedFlowSynchronizer = versionedFlowSynchronizer;
-    }
-
-    @Override
-    public void sync(final FlowController controller, final DataFlow dataFlow, final FlowService flowService, final BundleUpdateStrategy bundleUpdateStrategy)
-            throws FlowSerializationException, UninheritableFlowException, FlowSynchronizationException, MissingBundleException {
-
-        final FlowSynchronizer synchronizer = isXml(dataFlow) ? xmlFlowSynchronizer : versionedFlowSynchronizer;
-        synchronizer.sync(controller, dataFlow, flowService, bundleUpdateStrategy);
-    }
-
-    public static boolean isFlowEmpty(final DataFlow dataFlow) {
-        if (dataFlow == null || dataFlow.getFlow() == null || dataFlow.getFlow().length == 0) {
-            return true;
-        }
-
-        if (isXml(dataFlow)) {
-            return XmlFlowSynchronizer.isFlowEmpty(dataFlow.getFlowDocument());
-        } else {
-            return VersionedFlowSynchronizer.isFlowEmpty(dataFlow);
-        }
-    }
-
-    private static boolean isXml(final DataFlow dataFlow) {
-        if (dataFlow == null || dataFlow.getFlow() == null || dataFlow.getFlow().length == 0) {
-            return true;
-        }
-
-        return dataFlow.isXml();
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
index f53fddd21c..8e8537f2a2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
@@ -66,6 +66,7 @@ import org.apache.nifi.controller.inheritance.BundleCompatibilityCheck;
 import org.apache.nifi.controller.inheritance.ConnectionMissingCheck;
 import org.apache.nifi.controller.inheritance.FlowInheritability;
 import org.apache.nifi.controller.inheritance.FlowInheritabilityCheck;
+import org.apache.nifi.controller.inheritance.MissingComponentsCheck;
 import org.apache.nifi.controller.reporting.ReportingTaskInstantiationException;
 import org.apache.nifi.controller.service.ControllerServiceNode;
 import org.apache.nifi.encrypt.EncryptionException;
@@ -163,56 +164,78 @@ public class VersionedFlowSynchronizer implements FlowSynchronizer {
         final boolean flowAlreadySynchronized = controller.isFlowSynchronized();
         logger.info("Synchronizing FlowController with proposed flow: Controller Already Synchronized = {}", flowAlreadySynchronized);
 
+        final DataFlow existingDataFlow = getExistingDataFlow(controller);
+        boolean existingFlowEmpty = isFlowEmpty(existingDataFlow);
+
         // If bundle update strategy is configured to allow for compatible bundles, update any components to use compatible bundles if
         // the exact bundle does not exist.
-        if (bundleUpdateStrategy == BundleUpdateStrategy.USE_SPECIFIED_OR_COMPATIBLE_OR_GHOST) {
+        if (!existingFlowEmpty && bundleUpdateStrategy == BundleUpdateStrategy.USE_SPECIFIED_OR_COMPATIBLE_OR_GHOST) {
             mapCompatibleBundles(proposedFlow, controller.getExtensionManager());
         }
 
         // serialize controller state to bytes
-        final DataFlow existingDataFlow = getExistingDataFlow(controller);
         checkFlowInheritability(existingDataFlow, proposedFlow, controller, bundleUpdateStrategy);
 
-        final FlowComparison flowComparison = compareFlows(existingDataFlow, proposedFlow, controller.getEncryptor());
-        final Set<FlowDifference> flowDifferences = flowComparison.getDifferences();
-        if (flowDifferences.isEmpty()) {
-            logger.debug("No differences between current flow and proposed flow. Will not create backup of existing flow.");
-        } else if (isExistingFlowEmpty(controller)) {
-            logger.debug("Currently loaded dataflow is empty. Will not create backup of existing flow.");
-        } else {
-            backupExistingFlow();
+        logger.debug("Checking missing component inheritability");
+        final FlowInheritabilityCheck missingComponentsCheck = new MissingComponentsCheck();
+        final FlowInheritability componentInheritability = missingComponentsCheck.checkInheritability(existingDataFlow, proposedFlow, controller);
+        if (!componentInheritability.isInheritable()) {
+            throw new UninheritableFlowException("Proposed Flow is not inheritable by the flow controller because of differences in missing components: " + componentInheritability.getExplanation());
         }
 
-        final AffectedComponentSet affectedComponents = determineAffectedComponents(flowComparison, controller);
-        final AffectedComponentSet activeSet = affectedComponents.toActiveSet();
+        FlowComparison flowComparison = null;
+        AffectedComponentSet affectedComponents = null;
+        AffectedComponentSet activeSet = null;
 
-        // Stop the active components, and then wait for all components to be stopped.
-        logger.info("In order to inherit proposed dataflow, will stop any components that will be affected by the update");
-        if (logger.isDebugEnabled()) {
-            logger.debug("Will stop the following components:");
-            logger.debug(activeSet.toString());
-            final String differencesToString = flowDifferences.stream()
-                .map(FlowDifference::toString)
-                .collect(Collectors.joining("\n"));
-            logger.debug("This Active Set was determined from the following Flow Differences:\n{}", differencesToString);
-        }
+        if (!existingFlowEmpty) {
+            flowComparison = compareFlows(existingDataFlow, proposedFlow, controller.getEncryptor());
+            final Set<FlowDifference> flowDifferences = flowComparison.getDifferences();
+
+            if (flowDifferences.isEmpty()) {
+                logger.debug("No differences between current flow and proposed flow. Will not create backup of existing flow.");
+            } else if (isExistingFlowEmpty(controller)) {
+                logger.debug("Currently loaded dataflow is empty. Will not create backup of existing flow.");
+            } else {
+                backupExistingFlow();
+            }
+
+            affectedComponents = determineAffectedComponents(flowComparison, controller);
+            activeSet = affectedComponents.toActiveSet();
+
+            // Stop the active components, and then wait for all components to be stopped.
+            logger.info("In order to inherit proposed dataflow, will stop any components that will be affected by the update");
+            if (logger.isDebugEnabled()) {
+                logger.debug("Will stop the following components:");
+                logger.debug(activeSet.toString());
+                final String differencesToString = flowDifferences.stream()
+                        .map(FlowDifference::toString)
+                        .collect(Collectors.joining("\n"));
+                logger.debug("This Active Set was determined from the following Flow Differences:\n{}",
+                        differencesToString);
+            }
 
-        activeSet.stop();
+            activeSet.stop();
+        }
 
         try {
             // Ensure that the proposed flow doesn't remove any Connections for which there is currently data queued
-            verifyNoConnectionsWithDataRemoved(existingDataFlow, proposedFlow, controller, flowComparison);
+            if (!existingFlowEmpty) {
+                verifyNoConnectionsWithDataRemoved(existingDataFlow, proposedFlow, controller, flowComparison);
+            }
 
             synchronizeFlow(controller, existingDataFlow, proposedFlow, affectedComponents);
         } finally {
             // We have to call toExistingSet() here because some of the components that existed in the active set may no longer exist,
             // so attempting to start them will fail.
-            final AffectedComponentSet startable = activeSet.toExistingSet().toStartableSet();
 
-            final ComponentSetFilter runningComponentFilter = new RunningComponentSetFilter(proposedFlow.getVersionedDataflow());
-            final ComponentSetFilter stoppedComponentFilter = runningComponentFilter.reverse();
-            startable.removeComponents(stoppedComponentFilter);
-            startable.start();
+            if (!existingFlowEmpty) {
+                final AffectedComponentSet startable = activeSet.toExistingSet().toStartableSet();
+
+                final ComponentSetFilter runningComponentFilter = new RunningComponentSetFilter(proposedFlow.getVersionedDataflow());
+                final ComponentSetFilter stoppedComponentFilter = runningComponentFilter.reverse();
+                startable.removeComponents(stoppedComponentFilter);
+                startable.start();
+            }
         }
 
         final long millis = System.currentTimeMillis() - start;
@@ -661,6 +684,11 @@ public class VersionedFlowSynchronizer implements FlowSynchronizer {
         final VersionedDataflow dataflow,
         final AffectedComponentSet affectedComponentSet
     ) throws FlowAnalysisRuleInstantiationException {
+        // Guard state in order to be able to read flow.json from before adding the flow analysis rules
+        if (dataflow.getFlowAnalysisRules() == null) {
+            return;
+        }
+
         for (final VersionedFlowAnalysisRule versionedFlowAnalysisRule : dataflow.getFlowAnalysisRules()) {
             final FlowAnalysisRuleNode existing = controller.getFlowAnalysisRuleNode(versionedFlowAnalysisRule.getInstanceIdentifier());
             if (existing == null) {
@@ -1201,13 +1229,15 @@ public class VersionedFlowSynchronizer implements FlowSynchronizer {
 
     private DataFlow getExistingDataFlow(final FlowController controller) {
         final FlowManager flowManager = controller.getFlowManager();
+        final ProcessGroup root = flowManager.getRootGroup();
 
         // Determine missing components
         final Set<String> missingComponents = new HashSet<>();
         flowManager.getAllControllerServices().stream().filter(ComponentNode::isExtensionMissing).forEach(cs -> missingComponents.add(cs.getIdentifier()));
         flowManager.getAllReportingTasks().stream().filter(ComponentNode::isExtensionMissing).forEach(r -> missingComponents.add(r.getIdentifier()));
         flowManager.getAllParameterProviders().stream().filter(ComponentNode::isExtensionMissing).forEach(r -> missingComponents.add(r.getIdentifier()));
-        flowManager.findAllProcessors(AbstractComponentNode::isExtensionMissing).forEach(p -> missingComponents.add(p.getIdentifier()));
+        flowManager.getAllFlowRegistryClients().stream().filter(ComponentNode::isExtensionMissing).forEach(c -> missingComponents.add(c.getIdentifier()));
+        root.findAllProcessors().stream().filter(AbstractComponentNode::isExtensionMissing).forEach(p -> missingComponents.add(p.getIdentifier()));
 
         logger.trace("Exporting snippets from controller");
         final byte[] existingSnippets = controller.getSnippetManager().export();
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
deleted file mode 100644
index e330f0fc6e..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
+++ /dev/null
@@ -1,188 +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.controller.service;
-
-import org.apache.nifi.bundle.BundleCoordinate;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.serialization.FlowEncodingVersion;
-import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.groups.ProcessGroup;
-import org.apache.nifi.logging.LogLevel;
-import org.apache.nifi.util.BundleUtils;
-import org.apache.nifi.web.api.dto.BundleDTO;
-import org.apache.nifi.web.api.dto.ControllerServiceDTO;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-public class ControllerServiceLoader {
-
-    private static final Logger logger = LoggerFactory.getLogger(ControllerServiceLoader.class);
-
-    public static Map<ControllerServiceNode, Element> loadControllerServices(final List<Element> serviceElements, final FlowController controller,
-                                                                             final ProcessGroup parentGroup, final PropertyEncryptor encryptor, final FlowEncodingVersion encodingVersion) {
-
-        final Map<ControllerServiceNode, Element> nodeMap = new HashMap<>();
-        for (final Element serviceElement : serviceElements) {
-            final ControllerServiceNode serviceNode = createControllerService(controller, serviceElement, encryptor, encodingVersion);
-            if (parentGroup == null) {
-                controller.getFlowManager().addRootControllerService(serviceNode);
-            } else {
-                parentGroup.addControllerService(serviceNode);
-            }
-
-            // We need to clone the node because it will be used in a separate thread below, and
-            // Element is not thread-safe.
-            nodeMap.put(serviceNode, (Element) serviceElement.cloneNode(true));
-        }
-        for (final Map.Entry<ControllerServiceNode, Element> entry : nodeMap.entrySet()) {
-            configureControllerService(entry.getKey(), entry.getValue(), encryptor, encodingVersion);
-        }
-
-        return nodeMap;
-    }
-
-    public static void enableControllerServices(final Map<ControllerServiceNode, Element> nodeMap, final FlowController controller,
-                                                final PropertyEncryptor encryptor, final boolean autoResumeState, final FlowEncodingVersion encodingVersion) {
-        // Start services
-        if (autoResumeState) {
-            final Set<ControllerServiceNode> nodesToEnable = new HashSet<>();
-
-            for (final ControllerServiceNode node : nodeMap.keySet()) {
-                final Element controllerServiceElement = nodeMap.get(node);
-
-                final ControllerServiceDTO dto;
-                synchronized (controllerServiceElement.getOwnerDocument()) {
-                    dto = FlowFromDOMFactory.getControllerService(controllerServiceElement, encryptor, encodingVersion);
-                }
-
-                final ControllerServiceState state = ControllerServiceState.valueOf(dto.getState());
-                if (state == ControllerServiceState.ENABLED) {
-                    nodesToEnable.add(node);
-                    logger.debug("Will enable Controller Service {}", node);
-                } else {
-                    logger.debug("Will not enable Controller Service {} because its state is set to {}", node, state);
-                }
-            }
-
-            enableControllerServices(nodesToEnable, controller, autoResumeState);
-        } else {
-            logger.debug("Will not enable the following Controller Services because 'auto-resume state' flag is false: {}", nodeMap.keySet());
-        }
-    }
-
-    public static void enableControllerServices(final Collection<ControllerServiceNode> nodesToEnable, final FlowController controller, final boolean autoResumeState) {
-        // Start services
-        if (autoResumeState) {
-            logger.debug("Enabling Controller Services {}", nodesToEnable);
-            nodesToEnable.forEach(ControllerServiceNode::performValidation); // validate services before attempting to enable them
-
-            controller.getControllerServiceProvider().enableControllerServices(nodesToEnable);
-        } else {
-            logger.debug("Will not enable the following Controller Services because 'auto-resume state' flag is false: {}", nodesToEnable);
-        }
-    }
-
-    public static ControllerServiceNode cloneControllerService(final FlowController flowController, final ControllerServiceNode controllerService) {
-        // 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 = flowController.getFlowManager().createControllerService(controllerService.getCanonicalClassName(), id.toString(),
-                controllerService.getBundleCoordinate(), Collections.emptySet(), false, true, null);
-        clone.setName(controllerService.getName());
-        clone.setComments(controllerService.getComments());
-        clone.setBulletinLevel(controllerService.getBulletinLevel());
-
-        if (controllerService.getProperties() != null) {
-            Map<String,String> properties = new HashMap<>();
-            for (Map.Entry<PropertyDescriptor, String> propEntry : controllerService.getRawPropertyValues().entrySet()) {
-                properties.put(propEntry.getKey().getName(), propEntry.getValue());
-            }
-            clone.setProperties(properties);
-        }
-
-        return clone;
-    }
-
-    private static ControllerServiceNode createControllerService(final FlowController flowController, final Element controllerServiceElement, final PropertyEncryptor encryptor,
-                                                                 final FlowEncodingVersion encodingVersion) {
-        final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(controllerServiceElement, encryptor, encodingVersion);
-
-        BundleCoordinate coordinate;
-        try {
-            coordinate = BundleUtils.getCompatibleBundle(flowController.getExtensionManager(), dto.getType(), dto.getBundle());
-        } catch (final IllegalStateException e) {
-            final BundleDTO bundleDTO = dto.getBundle();
-            if (bundleDTO == null) {
-                coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-            } else {
-                coordinate = new BundleCoordinate(bundleDTO.getGroup(), bundleDTO.getArtifact(), bundleDTO.getVersion());
-            }
-        }
-
-        final ControllerServiceNode node = flowController.getFlowManager().createControllerService(dto.getType(), dto.getId(), coordinate, Collections.emptySet(), false, true, null);
-        node.setName(dto.getName());
-        node.setComments(dto.getComments());
-
-        if (dto.getBulletinLevel() != null) {
-            node.setBulletinLevel(LogLevel.valueOf(dto.getBulletinLevel()));
-        } else {
-            // this situation exists for backward compatibility with nifi 1.16 and earlier where controller services do not have bulletinLevels set in flow.xml/flow.json
-            // and bulletinLevels are at the WARN level by default
-            node.setBulletinLevel(LogLevel.WARN);
-        }
-
-        node.setVersionedComponentId(dto.getVersionedComponentId());
-        return node;
-    }
-
-    private static void configureControllerService(final ControllerServiceNode node, final Element controllerServiceElement, final PropertyEncryptor encryptor,
-                                                   final FlowEncodingVersion encodingVersion) {
-        final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(controllerServiceElement, encryptor, encodingVersion);
-        node.pauseValidationTrigger();
-        try {
-            node.setAnnotationData(dto.getAnnotationData());
-            final Set<String> sensitiveDynamicPropertyNames = getSensitiveDynamicPropertyNames(dto.getSensitiveDynamicPropertyNames(), node);
-            node.setProperties(dto.getProperties(), false, sensitiveDynamicPropertyNames);
-        } finally {
-            node.resumeValidationTrigger();
-        }
-    }
-
-    private static Set<String> getSensitiveDynamicPropertyNames(final Set<String> parsedSensitivePropertyNames, final ControllerServiceNode controllerServiceNode) {
-        final Set<String> sensitivePropertyNames = parsedSensitivePropertyNames == null ? Collections.emptySet() : parsedSensitivePropertyNames;
-        return sensitivePropertyNames.stream().filter(
-                propertyName -> {
-                    final PropertyDescriptor propertyDescriptor = controllerServiceNode.getPropertyDescriptor(propertyName);
-                    return propertyDescriptor.isDynamic();
-                }
-        ).collect(Collectors.toSet());
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintException.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintException.java
deleted file mode 100644
index 7c3b9bc5f1..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintException.java
+++ /dev/null
@@ -1,40 +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.fingerprint;
-
-/**
- */
-public class FingerprintException extends RuntimeException {
-
-    private static final long serialVersionUID = 189234798327894327L;
-
-    public FingerprintException(Throwable cause) {
-        super(cause);
-    }
-
-    public FingerprintException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    public FingerprintException(String message) {
-        super(message);
-    }
-
-    public FingerprintException() {
-    }
-
-}
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
deleted file mode 100644
index 1a2402483e..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
+++ /dev/null
@@ -1,1050 +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.fingerprint;
-
-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.FlowController;
-import org.apache.nifi.controller.serialization.FlowEncodingVersion;
-import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.encrypt.SensitiveValueEncoder;
-import org.apache.nifi.nar.ExtensionManager;
-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.FlowAnalysisRuleDTO;
-import org.apache.nifi.web.api.dto.FlowRegistryClientDTO;
-import org.apache.nifi.web.api.dto.ParameterProviderDTO;
-import org.apache.nifi.web.api.dto.ReportingTaskDTO;
-import org.apache.nifi.xml.processing.ProcessingException;
-import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.ErrorHandler;
-
-import javax.xml.XMLConstants;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import java.io.ByteArrayInputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.stream.Stream;
-
-/**
- * <p>Creates a fingerprint of a flow.xml. The order of elements or attributes in the flow.xml does not influence the fingerprint generation.
- *
- * <p>Only items in the flow.xml that influence the processing of data are incorporated into the fingerprint.
- * Examples of items involved in the fingerprint are: processor IDs, processor relationships, and processor properties.
- * Examples of items not involved in the fingerprint are: items in the processor "comments" tabs, position information, flow controller settings, and counters.
- *
- * <p>The determination for making items into the fingerprint is whether we can
- * easily change the setting in order to inherit the cluster's flow.
- * For example, if the component has to be stopped to apply the change and started again,
- * then the item should be included in a fingerprint.
- */
-public class FingerprintFactory {
-
-    /*
-     * Developer Note: This class should be changed with care and coordinated
-     * with all classes that use fingerprinting.  Improper coordination may
-     * lead to orphaning flow files, especially when flows are reloaded in a
-     * clustered environment.
-     */
-    // no fingerprint value
-    public static final String NO_VALUE = "NO_VALUE";
-
-    static final String FLOW_CONFIG_XSD = "/FlowConfiguration.xsd";
-    private static final String ENCRYPTED_VALUE_PREFIX = "enc{";
-    private static final String ENCRYPTED_VALUE_SUFFIX = "}";
-    private final PropertyEncryptor encryptor;
-    private final Schema schema;
-    private final ExtensionManager extensionManager;
-    private final SensitiveValueEncoder sensitiveValueEncoder;
-
-    private static final Logger logger = LoggerFactory.getLogger(FingerprintFactory.class);
-
-    public FingerprintFactory(final PropertyEncryptor encryptor, final ExtensionManager extensionManager, final SensitiveValueEncoder sensitiveValueEncoder) {
-        this.encryptor = encryptor;
-        this.extensionManager = extensionManager;
-        this.sensitiveValueEncoder = sensitiveValueEncoder;
-
-        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        try {
-            schema = schemaFactory.newSchema(FingerprintFactory.class.getResource(FLOW_CONFIG_XSD));
-        } catch (final Exception e) {
-            throw new RuntimeException("Failed to parse schema for file flow configuration.", e);
-        }
-    }
-
-    /**
-     * Creates a fingerprint of a flow. The order of elements or attributes in the flow does not influence the fingerprint generation.
-     * This method does not accept a FlowController, which means that Processors cannot be created in order to verify default property
-     * values, etc. As a result, if Flow A and Flow B are fingerprinted and Flow B, for instance, contains a property with a default value
-     * that is not present in Flow A, then the two will have different fingerprints.
-     *
-     * @param flowBytes the flow represented as bytes
-     * @return a generated fingerprint
-     * @throws FingerprintException if the fingerprint failed to be generated
-     */
-    public synchronized String createFingerprint(final byte[] flowBytes) throws FingerprintException {
-        return createFingerprint(flowBytes, null);
-    }
-
-    /**
-     * Creates a fingerprint of a flow. The order of elements or attributes in the flow does not influence the fingerprint generation.
-     *
-     * @param flowBytes  the flow represented as bytes
-     * @param controller the controller
-     * @return a generated fingerprint
-     * @throws FingerprintException if the fingerprint failed to be generated
-     */
-    public synchronized String createFingerprint(final byte[] flowBytes, final FlowController controller) throws FingerprintException {
-        return createFingerprint(parseFlow(flowBytes), controller);
-    }
-
-    /**
-     * Creates a fingerprint from an XML document representing the flow.xml.
-     *
-     * @param flowDoc the DOM
-     * @return the fingerprint
-     */
-    public synchronized String createFingerprint(final Document flowDoc, final FlowController controller) {
-        if (flowDoc == null) {
-            return "";
-        }
-
-        // builder to hold fingerprint state
-        final StringBuilder fingerprintBuilder = new StringBuilder();
-
-        // add flow controller fingerprint
-        final Element flowControllerElem = flowDoc.getDocumentElement();
-        if (flowControllerElem == null) {
-            logger.warn("Unable to create fingerprint because no 'flowController' element found in XML.");
-            return "";
-        }
-
-        final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(flowControllerElem);
-
-        addFlowControllerFingerprint(fingerprintBuilder, flowControllerElem, controller, encodingVersion);
-
-        return fingerprintBuilder.toString();
-    }
-
-    /**
-     * Parse the given flow.xml bytes into a Document instance.
-     *
-     * @param flow a flow
-     * @return the DOM
-     * @throws FingerprintException if the flow could not be parsed
-     */
-    private Document parseFlow(final byte[] flow) throws FingerprintException {
-        if (flow == null || flow.length == 0) {
-            return null;
-        }
-
-        try {
-            final ErrorHandler errorHandler = new LoggingXmlParserErrorHandler("Flow Configuration", logger);
-            final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
-            documentProvider.setSchema(schema);
-            documentProvider.setNamespaceAware(true);
-            documentProvider.setErrorHandler(errorHandler);
-
-            return documentProvider.parse(new ByteArrayInputStream(flow));
-        } catch (final ProcessingException e) {
-            throw new FingerprintException("Flow Parsing failed", e);
-        }
-    }
-
-    private StringBuilder addFlowControllerFingerprint(final StringBuilder builder, final Element flowControllerElem, final FlowController controller, final FlowEncodingVersion encodingVersion) {
-        // registries
-        final Element registriesElement = DomUtils.getChild(flowControllerElem, "registries");
-        if (registriesElement == null) {
-            builder.append("NO_VALUE");
-        } else {
-            final List<Element> flowRegistryElems = DomUtils.getChildElementsByTagName(registriesElement, "flowRegistry");
-            if (flowRegistryElems.isEmpty()) {
-                builder.append("NO_VALUE");
-            } else {
-                final List<FlowRegistryClientDTO> registryClientDtos = new ArrayList<>();
-                for (final Element flowRegistryElement : flowRegistryElems) {
-                    registryClientDtos.add(FlowFromDOMFactory.getFlowRegistryClient(flowRegistryElement, encryptor, encodingVersion));
-                }
-
-                registryClientDtos.sort(Comparator.comparing(FlowRegistryClientDTO::getId));
-
-                for (final FlowRegistryClientDTO registryClientDto : registryClientDtos) {
-                    addFlowRegistryFingerprint(builder, registryClientDto);
-                }
-            }
-        }
-
-        final Element contextsElement = DomUtils.getChild(flowControllerElem, "parameterContexts");
-        if (contextsElement == null) {
-            builder.append("NO_PARAMETER_CONTEXTS");
-        } else {
-            final List<Element> parameterContextElements = DomUtils.getChildElementsByTagName(contextsElement, "parameterContext");
-            if (parameterContextElements.isEmpty()) {
-                builder.append("NO_PARAMETER_CONTEXTS");
-            } else {
-                orderByChildElement(parameterContextElements, "id");
-
-                for (final Element parameterContextElement : parameterContextElements) {
-                    addParameterContext(builder, parameterContextElement);
-                }
-            }
-        }
-
-        // root group
-        final Element rootGroupElem = (Element) DomUtils.getChildNodesByTagName(flowControllerElem, "rootGroup").item(0);
-        addProcessGroupFingerprint(builder, rootGroupElem, encodingVersion);
-
-        final Element controllerServicesElem = DomUtils.getChild(flowControllerElem, "controllerServices");
-        if (controllerServicesElem != null) {
-            final List<ControllerServiceDTO> serviceDtos = new ArrayList<>();
-            for (final Element serviceElem : DomUtils.getChildElementsByTagName(controllerServicesElem, "controllerService")) {
-                final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(serviceElem, encryptor, encodingVersion);
-                serviceDtos.add(dto);
-            }
-
-            Collections.sort(serviceDtos, new Comparator<ControllerServiceDTO>() {
-                @Override
-                public int compare(final ControllerServiceDTO o1, final ControllerServiceDTO o2) {
-                    if (o1 == null && o2 == null) {
-                        return 0;
-                    }
-                    if (o1 == null && o2 != null) {
-                        return 1;
-                    }
-                    if (o1 != null && o2 == null) {
-                        return -1;
-                    }
-
-                    return o1.getId().compareTo(o2.getId());
-                }
-            });
-
-            for (final ControllerServiceDTO dto : serviceDtos) {
-                addControllerServiceFingerprint(builder, dto);
-            }
-        }
-
-        final Element reportingTasksElem = DomUtils.getChild(flowControllerElem, "reportingTasks");
-        if (reportingTasksElem != null) {
-            final List<ReportingTaskDTO> reportingTaskDtos = new ArrayList<>();
-            for (final Element taskElem : DomUtils.getChildElementsByTagName(reportingTasksElem, "reportingTask")) {
-                final ReportingTaskDTO dto = FlowFromDOMFactory.getReportingTask(taskElem, encryptor, encodingVersion);
-                reportingTaskDtos.add(dto);
-            }
-
-            Collections.sort(reportingTaskDtos, new Comparator<ReportingTaskDTO>() {
-                @Override
-                public int compare(final ReportingTaskDTO o1, final ReportingTaskDTO o2) {
-                    if (o1 == null && o2 == null) {
-                        return 0;
-                    }
-                    if (o1 == null && o2 != null) {
-                        return 1;
-                    }
-                    if (o1 != null && o2 == null) {
-                        return -1;
-                    }
-
-                    return o1.getId().compareTo(o2.getId());
-                }
-            });
-
-            for (final ReportingTaskDTO dto : reportingTaskDtos) {
-                addReportingTaskFingerprint(builder, dto);
-            }
-        }
-
-        final Element flowAnalysisRulesElem = DomUtils.getChild(flowControllerElem, "flowAnalysisRules");
-        if (flowAnalysisRulesElem != null) {
-            final List<FlowAnalysisRuleDTO> flowAnalysisRuleDtos = new ArrayList<>();
-            for (final Element ruleElem : DomUtils.getChildElementsByTagName(flowAnalysisRulesElem, "flowAnalysisRule")) {
-                final FlowAnalysisRuleDTO dto = FlowFromDOMFactory.getFlowAnalysisRule(ruleElem, encryptor, encodingVersion);
-                flowAnalysisRuleDtos.add(dto);
-            }
-
-            Collections.sort(flowAnalysisRuleDtos, new Comparator<FlowAnalysisRuleDTO>() {
-                @Override
-                public int compare(final FlowAnalysisRuleDTO o1, final FlowAnalysisRuleDTO o2) {
-                    if (o1 == null && o2 == null) {
-                        return 0;
-                    }
-                    if (o1 == null && o2 != null) {
-                        return 1;
-                    }
-                    if (o1 != null && o2 == null) {
-                        return -1;
-                    }
-
-                    return o1.getId().compareTo(o2.getId());
-                }
-            });
-
-            for (final FlowAnalysisRuleDTO dto : flowAnalysisRuleDtos) {
-                addFlowAnalysisRuleFingerprint(builder, dto);
-            }
-        }
-
-        final Element parameterProvidersElem = DomUtils.getChild(flowControllerElem, "parameterProviders");
-        if (parameterProvidersElem != null) {
-            final List<ParameterProviderDTO> parameterProviderDtos = new ArrayList<>();
-            for (final Element taskElem : DomUtils.getChildElementsByTagName(parameterProvidersElem, "parameterProvider")) {
-                final ParameterProviderDTO dto = FlowFromDOMFactory.getParameterProvider(taskElem, encryptor, encodingVersion);
-                parameterProviderDtos.add(dto);
-            }
-
-            Collections.sort(parameterProviderDtos, Comparator.comparing(ParameterProviderDTO::getId));
-
-            for (final ParameterProviderDTO dto : parameterProviderDtos) {
-                addParameterProviderFingerprint(builder, dto);
-            }
-        }
-
-        return builder;
-    }
-
-    private void orderByChildElement(final List<Element> toSort, final String childTagName) {
-        toSort.sort((a, b) -> {
-            final String valueA = DomUtils.getChildText(a, childTagName);
-            final String valueB = DomUtils.getChildText(b, childTagName);
-            return valueA.compareTo(valueB);
-        });
-    }
-
-    private StringBuilder addParameterContext(final StringBuilder builder, final Element parameterContextElement) {
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "name"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterContextElement, "description"));
-
-        final List<Element> parameterElements = DomUtils.getChildElementsByTagName(parameterContextElement, "parameter");
-        if (parameterElements == null || parameterElements.isEmpty()) {
-            builder.append("NO_PARAMETERS");
-        } else {
-            orderByChildElement(parameterElements, "name");
-
-            for (final Element parameterElement : parameterElements) {
-                addParameter(builder, parameterElement);
-            }
-        }
-
-        final List<Element> inheritedParameterContexts = DomUtils.getChildElementsByTagName(parameterContextElement, "inheritedParameterContextId");
-        if (inheritedParameterContexts == null || inheritedParameterContexts.isEmpty()) {
-            builder.append("NO_INHERITED_PARAMETER_CONTEXT_IDS");
-        } else {
-            for (final Element inheritedParameterContextId : inheritedParameterContexts) {
-                builder.append(inheritedParameterContextId.getTextContent());
-            }
-        }
-        final String parameterProviderId = DomUtils.getChildText(parameterContextElement, "parameterProviderId");
-        builder.append(parameterProviderId == null ? "NO_PARAMETER_PROVIDER_ID" : parameterProviderId);
-        final String parameterGroupName = DomUtils.getChildText(parameterContextElement, "parameterGroupName");
-        builder.append(parameterGroupName == null ? "NO_PARAMETER_GROUP_NAME" : parameterGroupName);
-        final String isSynchronized = DomUtils.getChildText(parameterContextElement, "isSynchronized");
-        builder.append(isSynchronized == null ? "NO_PARAMETER_IS_SYNCHRONIZED" : isSynchronized);
-
-        return builder;
-    }
-
-    private void addParameter(final StringBuilder builder, final Element parameterElement) {
-        Stream.of("name", "description", "sensitive", "provided").forEach(elementName -> appendFirstValue(builder, DomUtils.getChildNodesByTagName(parameterElement, elementName)));
-
-        final String value = DomUtils.getChildText(parameterElement, "value");
-        if (value == null) {
-            builder.append("NO_VALUE");
-            return;
-        }
-
-        // append value
-        if (isEncrypted(value)) {
-            // Get a secure, deterministic, loggable representation of this value
-            builder.append(getLoggableRepresentationOfSensitiveValue(value));
-        } else {
-            builder.append(getValue(value, NO_VALUE));
-        }
-
-    }
-
-    private void addFlowRegistryFingerprint(final StringBuilder builder, final FlowRegistryClientDTO dto) {
-        builder.append(dto.getId());
-        builder.append(dto.getName());
-        builder.append(dto.getDeprecated());
-        builder.append(dto.getUri());
-
-        builder.append(dto.getType());
-        addBundleFingerprint(builder, dto.getBundle());
-
-        // get the temp instance of the FlowRegistryClient 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 FlowRegistryClient of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
-        }
-        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
-    }
-
-    StringBuilder addProcessGroupFingerprint(final StringBuilder builder, final Element processGroupElem, final FlowEncodingVersion encodingVersion) throws FingerprintException {
-        // id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "versionedComponentId"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "parameterContextId"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "flowfileConcurrency"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "flowfileOutboundPolicy"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultFlowFileExpiration"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultBackPressureObjectThreshold"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "defaultBackPressureDataSizeThreshold"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processGroupElem, "logFileSuffix"));
-
-        final Element versionControlInfo = DomUtils.getChild(processGroupElem, "versionControlInformation");
-        if (versionControlInfo == null) {
-            builder.append("NO_VERSION_CONTROL_INFORMATION");
-        } else {
-            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "registryId"));
-            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "bucketId"));
-            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "flowId"));
-            appendFirstValue(builder, DomUtils.getChildNodesByTagName(versionControlInfo, "version"));
-        }
-
-        // processors
-        final List<Element> processorElems = DomUtils.getChildElementsByTagName(processGroupElem, "processor");
-        processorElems.sort(getIdsComparator());
-        for (final Element processorElem : processorElems) {
-            addFlowFileProcessorFingerprint(builder, processorElem);
-        }
-
-        // input ports
-        final NodeList inputPortElems = DomUtils.getChildNodesByTagName(processGroupElem, "inputPort");
-        final List<Element> sortedInputPortElems = sortElements(inputPortElems, getIdsComparator());
-        for (final Element inputPortElem : sortedInputPortElems) {
-            addPortFingerprint(builder, inputPortElem);
-        }
-
-        // labels
-        final NodeList labelElems = DomUtils.getChildNodesByTagName(processGroupElem, "label");
-        final List<Element> sortedLabels = sortElements(labelElems, getIdsComparator());
-        for (final Element labelElem : sortedLabels) {
-            addLabelFingerprint(builder, labelElem);
-        }
-
-        // output ports
-        final NodeList outputPortElems = DomUtils.getChildNodesByTagName(processGroupElem, "outputPort");
-        final List<Element> sortedOutputPortElems = sortElements(outputPortElems, getIdsComparator());
-        for (final Element outputPortElem : sortedOutputPortElems) {
-            addPortFingerprint(builder, outputPortElem);
-        }
-
-        // process groups
-        final NodeList nestedProcessGroupElems = DomUtils.getChildNodesByTagName(processGroupElem, "processGroup");
-        final List<Element> sortedNestedProcessGroupElems = sortElements(nestedProcessGroupElems, getIdsComparator());
-        for (final Element nestedProcessGroupElem : sortedNestedProcessGroupElems) {
-            addProcessGroupFingerprint(builder, nestedProcessGroupElem, encodingVersion);
-        }
-
-        // remote process groups
-        final NodeList remoteProcessGroupElems = DomUtils.getChildNodesByTagName(processGroupElem, "remoteProcessGroup");
-        final List<Element> sortedRemoteProcessGroupElems = sortElements(remoteProcessGroupElems, getIdsComparator());
-        for (final Element remoteProcessGroupElem : sortedRemoteProcessGroupElems) {
-            addRemoteProcessGroupFingerprint(builder, remoteProcessGroupElem);
-        }
-
-        // connections
-        final NodeList connectionElems = DomUtils.getChildNodesByTagName(processGroupElem, "connection");
-        final List<Element> sortedConnectionElems = sortElements(connectionElems, getIdsComparator());
-        for (final Element connectionElem : sortedConnectionElems) {
-            addConnectionFingerprint(builder, connectionElem);
-        }
-
-        // funnel
-        final NodeList funnelElems = DomUtils.getChildNodesByTagName(processGroupElem, "funnel");
-        final List<Element> sortedFunnelElems = sortElements(funnelElems, getIdsComparator());
-        for (final Element funnelElem : sortedFunnelElems) {
-            addFunnelFingerprint(builder, funnelElem);
-        }
-
-        final NodeList controllerServiceElems = DomUtils.getChildNodesByTagName(processGroupElem, "controllerService");
-        final List<Element> sortedControllerServiceElems = sortElements(controllerServiceElems, getIdsComparator());
-        for (final Element controllerServiceElem : sortedControllerServiceElems) {
-            final ControllerServiceDTO dto = FlowFromDOMFactory.getControllerService(controllerServiceElem, encryptor, encodingVersion);
-            addControllerServiceFingerprint(builder, dto);
-        }
-
-        // add variables
-        final NodeList variableElems = DomUtils.getChildNodesByTagName(processGroupElem, "variable");
-        final List<Element> sortedVarList = sortElements(variableElems, getVariableNameComparator());
-        for (final Element varElem : sortedVarList) {
-            addVariableFingerprint(builder, varElem);
-        }
-
-        return builder;
-    }
-
-    private void addVariableFingerprint(final StringBuilder builder, final Element variableElement) {
-        final String variableName = variableElement.getAttribute("name");
-        final String variableValue = variableElement.getAttribute("value");
-        builder.append(variableName).append("=").append(variableValue);
-    }
-
-    private StringBuilder addFlowFileProcessorFingerprint(final StringBuilder builder, final Element processorElem) throws FingerprintException {
-        // id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "versionedComponentId"));
-        // class
-        final NodeList childNodes = DomUtils.getChildNodesByTagName(processorElem, "class");
-        final String className = childNodes.item(0).getTextContent();
-        appendFirstValue(builder, childNodes);
-        // annotation data
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "annotationData"));
-
-        // get the bundle details if possible
-        final BundleDTO bundle = FlowFromDOMFactory.getBundle(DomUtils.getChild(processorElem, "bundle"));
-        addBundleFingerprint(builder, bundle);
-
-        // max concurrent tasks
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "maxConcurrentTasks"));
-        // scheduling period
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "schedulingPeriod"));
-        // penalization period
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "penalizationPeriod"));
-        // yield period
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "yieldPeriod"));
-        // bulletin level
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "bulletinLevel"));
-        // loss tolerant
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "lossTolerant"));
-        // scheduling strategy
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "schedulingStrategy"));
-        // execution node
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "executionNode"));
-        // run duration nanos
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "runDurationNanos"));
-        // retry count
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "retryCount"));
-        // backoff mechanism
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "backoffMechanism"));
-        // max backoff period
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(processorElem, "maxBackoffPeriod"));
-
-        // 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
-        final NodeList propertyElems = DomUtils.getChildNodesByTagName(processorElem, "property");
-        final List<Element> sortedPropertyElems = sortElements(propertyElems, getProcessorPropertiesComparator());
-        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, configurableComponent, propName, propValue);
-        }
-
-        final NodeList autoTerminateElems = DomUtils.getChildNodesByTagName(processorElem, "autoTerminatedRelationship");
-        final List<Element> sortedAutoTerminateElems = sortElements(autoTerminateElems, getElementTextComparator());
-        for (final Element autoTerminateElem : sortedAutoTerminateElems) {
-            builder.append(autoTerminateElem.getTextContent());
-        }
-
-        final NodeList retriedRelationshipsElems = DomUtils.getChildNodesByTagName(processorElem, "retriedRelationships");
-        final List<Element> sortedRetriedRelationshipsElems = sortElements(retriedRelationshipsElems, getElementTextComparator());
-        for (final Element retriedRelationshipElem : sortedRetriedRelationshipsElems) {
-            builder.append(retriedRelationshipElem.getTextContent());
-        }
-
-        return builder;
-    }
-
-    private StringBuilder addPropertyFingerprint(final StringBuilder builder, final ConfigurableComponent component, final String propName, final String propValue) throws FingerprintException {
-        // If we have a component to use, first determine if the value given is the default value for the specified property.
-        // If so, we do not add the property to the fingerprint.
-        // We do this because if a component is updated to add a new property, whenever we connect to the cluster, we have issues because
-        // the Cluster Coordinator's flow comes from disk, where the flow.xml doesn't have the new property but our FlowController does have the new property.
-        // This causes the fingerprints not to match. As a result, we just ignore default values, and this resolves the issue.
-
-        if (component != null) {
-            final PropertyDescriptor descriptor = component.getPropertyDescriptor(propName);
-            if (descriptor != null && propValue != null && propValue.equals(descriptor.getDefaultValue())) {
-                return builder;
-            }
-        }
-
-        // check if there is a value
-        if (propValue == null) {
-            return builder;
-        }
-
-        // append name
-        builder.append(propName).append("=");
-
-        // append value
-        if (isEncrypted(propValue)) {
-            // Get a secure, deterministic, loggable representation of this value
-            builder.append(getLoggableRepresentationOfSensitiveValue(propValue));
-        } else {
-            builder.append(getValue(propValue, NO_VALUE));
-        }
-
-        return builder;
-    }
-
-    /**
-     * Returns a securely-derived, deterministic value from the provided encrypted property
-     * value. This is because the flow fingerprint is displayed in the log if NiFi has
-     * trouble inheriting a flow, so the sensitive value should not be disclosed through the
-     * log. However, the equality or difference of the sensitive value can influence in the
-     * inheritability of the flow, so it cannot be ignored completely.
-     * <p>
-     * The specific derivation process is unimportant as long as it is a salted,
-     * cryptographically-secure hash function with an iteration cost sufficient for password
-     * storage in other applications.
-     *
-     * @param encryptedPropertyValue the encrypted property value
-     * @return a deterministic string value which represents this input but is safe to print in a log
-     */
-    private String getLoggableRepresentationOfSensitiveValue(String encryptedPropertyValue) {
-        final String plaintextValue = decrypt(encryptedPropertyValue);
-        return sensitiveValueEncoder.getEncoded(plaintextValue);
-    }
-
-    private StringBuilder addPortFingerprint(final StringBuilder builder, final Element portElem) throws FingerprintException {
-        // id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "versionedComponentId"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "name"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(portElem, "allowRemoteAccess"));
-
-        // user access control
-        final NodeList userAccessControlNodeList = DomUtils.getChildNodesByTagName(portElem, "userAccessControl");
-        if (userAccessControlNodeList == null || userAccessControlNodeList.getLength() == 0) {
-            builder.append("NO_USER_ACCESS_CONTROL");
-        } else {
-            final List<String> sortedAccessControl = new ArrayList<>();
-            for (int i = 0; i < userAccessControlNodeList.getLength(); i++) {
-                sortedAccessControl.add(userAccessControlNodeList.item(i).getTextContent());
-            }
-            Collections.sort(sortedAccessControl);
-            for (final String user : sortedAccessControl) {
-                builder.append(user);
-            }
-        }
-
-        // group access control
-        final NodeList groupAccessControlNodeList = DomUtils.getChildNodesByTagName(portElem, "groupAccessControl");
-        if (groupAccessControlNodeList == null || groupAccessControlNodeList.getLength() == 0) {
-            builder.append("NO_GROUP_ACCESS_CONTROL");
-        } else {
-            final List<String> sortedAccessControl = new ArrayList<>();
-            for (int i = 0; i < groupAccessControlNodeList.getLength(); i++) {
-                sortedAccessControl.add(groupAccessControlNodeList.item(i).getTextContent());
-            }
-
-            Collections.sort(sortedAccessControl);
-            for (final String user : sortedAccessControl) {
-                builder.append(user);
-            }
-        }
-
-        return builder;
-    }
-
-    private StringBuilder addLabelFingerprint(final StringBuilder builder, final Element labelElem) {
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "versionedComponentId"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(labelElem, "value"));
-        return builder;
-    }
-
-    private StringBuilder addRemoteProcessGroupFingerprint(final StringBuilder builder, final Element remoteProcessGroupElem) throws FingerprintException {
-
-        for (String tagName : new String[]{"id", "versionedComponentId", "urls", "networkInterface", "timeout", "yieldPeriod",
-                "transportProtocol", "proxyHost", "proxyPort", "proxyUser", "proxyPassword"}) {
-            final String value = getFirstValue(DomUtils.getChildNodesByTagName(remoteProcessGroupElem, tagName));
-            if (isEncrypted(value)) {
-                builder.append(getLoggableRepresentationOfSensitiveValue(value));
-            } else {
-                builder.append(value);
-            }
-        }
-
-        final NodeList inputPortList = DomUtils.getChildNodesByTagName(remoteProcessGroupElem, "inputPort");
-        final NodeList outputPortList = DomUtils.getChildNodesByTagName(remoteProcessGroupElem, "outputPort");
-
-        final Comparator<Element> portComparator = new Comparator<Element>() {
-            @Override
-            public int compare(final Element o1, final Element o2) {
-                if (o1 == null && o2 == null) {
-                    return 0;
-                }
-                if (o1 == null) {
-                    return 1;
-                }
-                if (o2 == null) {
-                    return -1;
-                }
-
-                NodeList nameList1 = DomUtils.getChildNodesByTagName(o1, "name");
-                NodeList nameList2 = DomUtils.getChildNodesByTagName(o2, "name");
-
-                if (nameList1.getLength() == 0 && nameList2.getLength() == 0) {
-                    return 0;
-                }
-                if (nameList1.getLength() == 0) {
-                    return 1;
-                }
-                if (nameList2.getLength() == 0) {
-                    return -1;
-                }
-
-                return nameList1.item(0).getTextContent().compareTo(nameList2.item(0).getTextContent());
-            }
-        };
-
-        final List<Element> sortedInputPorts = new ArrayList<>(inputPortList.getLength());
-        for (int i = 0; i < inputPortList.getLength(); i++) {
-            sortedInputPorts.add((Element) inputPortList.item(i));
-        }
-        Collections.sort(sortedInputPorts, portComparator);
-
-        final List<Element> sortedOutputPorts = new ArrayList<>(outputPortList.getLength());
-        for (int i = 0; i < outputPortList.getLength(); i++) {
-            sortedOutputPorts.add((Element) outputPortList.item(i));
-        }
-        Collections.sort(sortedOutputPorts, portComparator);
-
-        for (final Element inputPortElement : sortedInputPorts) {
-            addRemoteGroupPortFingerprint(builder, inputPortElement);
-        }
-
-        for (final Element outputPortElement : sortedOutputPorts) {
-            addRemoteGroupPortFingerprint(builder, outputPortElement);
-        }
-
-        return builder;
-    }
-
-    private StringBuilder addRemoteGroupPortFingerprint(final StringBuilder builder, final Element remoteGroupPortElement) {
-        for (final String childName : new String[]{"id", "targetId", "versionedComponentId", "maxConcurrentTasks", "useCompression", "batchCount", "batchSize", "batchDuration"}) {
-            appendFirstValue(builder, DomUtils.getChildNodesByTagName(remoteGroupPortElement, childName));
-        }
-
-        return builder;
-    }
-
-    private StringBuilder addConnectionFingerprint(final StringBuilder builder, final Element connectionElem) throws FingerprintException {
-        // id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "versionedComponentId"));
-        // source id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceId"));
-        // source group id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceGroupId"));
-        // source type
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "sourceType"));
-        // destination id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationId"));
-        // destination group id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationGroupId"));
-        // destination type
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "destinationType"));
-
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "name"));
-
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "loadBalanceStrategy"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "partitioningAttribute"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(connectionElem, "loadBalanceCompression"));
-
-        // relationships
-        final NodeList relationshipElems = DomUtils.getChildNodesByTagName(connectionElem, "relationship");
-        final List<Element> sortedRelationshipElems = sortElements(relationshipElems, getElementTextComparator());
-        for (final Element relationshipElem : sortedRelationshipElems) {
-            builder.append(getValue(relationshipElem, NO_VALUE));
-        }
-
-        return builder;
-    }
-
-    private StringBuilder addFunnelFingerprint(final StringBuilder builder, final Element funnelElem) throws FingerprintException {
-        // id
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(funnelElem, "id"));
-        appendFirstValue(builder, DomUtils.getChildNodesByTagName(funnelElem, "versionedComponentId"));
-        return builder;
-    }
-
-    private void addControllerServiceFingerprint(final StringBuilder builder, final ControllerServiceDTO dto) {
-        builder.append(dto.getId());
-        builder.append(dto.getVersionedComponentId());
-        builder.append(dto.getType());
-        builder.append(dto.getName());
-
-        addBundleFingerprint(builder, dto.getBundle());
-
-        builder.append(dto.getComments());
-        builder.append(dto.getBulletinLevel());
-        builder.append(dto.getAnnotationData());
-        builder.append(dto.getState());
-
-        // get the temp instance of the ControllerService so that we know the default property values
-        final BundleCoordinate coordinate = getCoordinate(dto.getType(), dto.getBundle());
-        final ConfigurableComponent configurableComponent = extensionManager.getTempComponent(dto.getType(), coordinate);
-        if (configurableComponent == null) {
-            logger.warn("Unable to get ControllerService of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
-        }
-
-        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
-    }
-
-    private void addPropertiesFingerprint(final StringBuilder builder, final ConfigurableComponent component, final Map<String, String> properties) {
-        if (properties == null) {
-            builder.append("NO_PROPERTIES");
-        } else {
-            final SortedMap<String, String> sortedProps = new TreeMap<>(properties);
-            for (final Map.Entry<String, String> entry : sortedProps.entrySet()) {
-                addPropertyFingerprint(builder, component, entry.getKey(), entry.getValue());
-            }
-        }
-    }
-
-    private void addBundleFingerprint(final StringBuilder builder, final BundleDTO bundle) {
-        if (bundle != null) {
-            builder.append(bundle.getGroup());
-            builder.append(bundle.getArtifact());
-            builder.append(bundle.getVersion());
-        } else {
-            builder.append("MISSING_BUNDLE");
-        }
-    }
-
-    private BundleCoordinate getCoordinate(final String type, final BundleDTO dto) {
-        BundleCoordinate coordinate;
-        try {
-            coordinate = BundleUtils.getCompatibleBundle(extensionManager, type, dto);
-        } catch (final IllegalStateException e) {
-            if (dto == null) {
-                coordinate = BundleCoordinate.UNKNOWN_COORDINATE;
-            } else {
-                coordinate = new BundleCoordinate(dto.getGroup(), dto.getArtifact(), dto.getVersion());
-            }
-        }
-        return coordinate;
-    }
-
-    private void addReportingTaskFingerprint(final StringBuilder builder, final ReportingTaskDTO dto) {
-        builder.append(dto.getId());
-        builder.append(dto.getType());
-        builder.append(dto.getName());
-
-        addBundleFingerprint(builder, dto.getBundle());
-
-        builder.append(dto.getComments());
-        builder.append(dto.getSchedulingPeriod());
-        builder.append(dto.getSchedulingStrategy());
-        builder.append(dto.getAnnotationData());
-
-        // 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, configurableComponent, dto.getProperties());
-    }
-
-    private void addFlowAnalysisRuleFingerprint(final StringBuilder builder, final FlowAnalysisRuleDTO dto) {
-        builder.append(dto.getId());
-        builder.append(dto.getType());
-        builder.append(dto.getName());
-
-        addBundleFingerprint(builder, dto.getBundle());
-
-        builder.append(dto.getComments());
-        builder.append(dto.getEnforcementPolicy());
-        builder.append(dto.getState());
-
-        // get the temp instance of the FlowAnalysisRule 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 FlowAnalysisRule of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
-        }
-
-        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
-    }
-
-    private void addParameterProviderFingerprint(final StringBuilder builder, final ParameterProviderDTO dto) {
-        builder.append(dto.getId());
-        builder.append(dto.getType());
-        builder.append(dto.getName());
-
-        addBundleFingerprint(builder, dto.getBundle());
-
-        builder.append(dto.getComments());
-        builder.append(dto.getAnnotationData());
-
-        // get the temp instance of the ParameterProvider 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 ParameterProvider of type {}; its default properties will be fingerprinted instead of being ignored.", dto.getType());
-        }
-
-        addPropertiesFingerprint(builder, configurableComponent, dto.getProperties());
-    }
-
-    private Comparator<Element> getIdsComparator() {
-        return new Comparator<Element>() {
-            @Override
-            public int compare(final Element e1, final Element e2) {
-                // compare using processor ids
-                final String e1Id = getFirstValue(DomUtils.getChildNodesByTagName(e1, "id"));
-                final String e2Id = getFirstValue(DomUtils.getChildNodesByTagName(e2, "id"));
-                return e1Id.compareTo(e2Id);
-            }
-        };
-    }
-
-    private Comparator<Element> getVariableNameComparator() {
-        return new Comparator<Element>() {
-            @Override
-            public int compare(final Element e1, final Element e2) {
-                if (e1 == null && e2 == null) {
-                    return 0;
-                }
-                if (e1 == null) {
-                    return 1;
-                }
-                if (e2 == null) {
-                    return -1;
-                }
-
-                final String varName1 = e1.getAttribute("name");
-                final String varName2 = e2.getAttribute("name");
-                return varName1.compareTo(varName2);
-            }
-        };
-    }
-
-    private Comparator<Element> getProcessorPropertiesComparator() {
-        return new Comparator<Element>() {
-            @Override
-            public int compare(final Element e1, final Element e2) {
-                // combine the property name and value for the first required property
-                final String e1PropName = getFirstValue(DomUtils.getChildNodesByTagName(e1, "name"));
-                String e1PropValue = getFirstValue(DomUtils.getChildNodesByTagName(e1, "value"));
-                if (isEncrypted(e1PropValue)) {
-                    e1PropValue = getLoggableRepresentationOfSensitiveValue(e1PropValue);
-                }
-                final String e1CombinedValue = e1PropName + e1PropValue;
-
-                // combine the property name and value for the second required property
-                final String e2PropName = getFirstValue(DomUtils.getChildNodesByTagName(e2, "name"));
-                String e2PropValue = getFirstValue(DomUtils.getChildNodesByTagName(e2, "value"));
-                if (isEncrypted(e2PropValue)) {
-                    e2PropValue = getLoggableRepresentationOfSensitiveValue(e2PropValue);
-                }
-                final String e2CombinedValue = e2PropName + e2PropValue;
-
-                // compare the combined values
-                return e1CombinedValue.compareTo(e2CombinedValue);
-            }
-        };
-    }
-
-    private Comparator<Element> getElementTextComparator() {
-        return new Comparator<Element>() {
-            @Override
-            public int compare(final Element e1, final Element e2) {
-                if (e2 == null) {
-                    return -1;
-                } else if (e1 == null) {
-                    return 1;
-                }
-
-                return e1.getTextContent().compareTo(e2.getTextContent());
-            }
-        };
-    }
-
-    private List<Element> sortElements(final NodeList nodeList, final Comparator<Element> comparator) {
-
-        final List<Element> result = new ArrayList<>();
-
-        // add node list to sorted list
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            result.add((Element) nodeList.item(i));
-        }
-
-        Collections.sort(result, comparator);
-
-        return result;
-    }
-
-    private String getValue(final Node node) {
-        return getValue(node, NO_VALUE);
-    }
-
-    private String getValue(final Node node, final String defaultValue) {
-        return StringUtils.isBlank(node.getTextContent()) ? defaultValue : node.getTextContent().trim();
-    }
-
-    private String getValue(final String value, final String defaultValue) {
-        return StringUtils.isBlank(value) ? defaultValue : value;
-    }
-
-    private String getFirstValue(final NodeList nodeList) {
-        return getFirstValue(nodeList, NO_VALUE);
-    }
-
-    private String getFirstValue(final NodeList nodeList, final String defaultValue) {
-        return nodeList == null || nodeList.getLength() == 0 ? defaultValue : getValue(nodeList.item(0));
-    }
-
-    private StringBuilder appendFirstValue(final StringBuilder builder, final NodeList nodeList) {
-        return appendFirstValue(builder, nodeList, NO_VALUE);
-    }
-
-    private StringBuilder appendFirstValue(final StringBuilder builder, final NodeList nodeList, final String defaultValue) {
-        return builder.append(getFirstValue(nodeList, defaultValue));
-    }
-
-    private boolean isEncrypted(final String value) {
-        return (value.startsWith(ENCRYPTED_VALUE_PREFIX) && value.endsWith(ENCRYPTED_VALUE_SUFFIX));
-    }
-
-    private String decrypt(final String value) throws FingerprintException {
-        final int decryptStartIdx = ENCRYPTED_VALUE_PREFIX.length();
-        final int decryptEndIdx = value.length() - ENCRYPTED_VALUE_SUFFIX.length();
-        return encryptor.decrypt(value.substring(decryptStartIdx, decryptEndIdx));
-    }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/FlowConfigurationArchiveManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/FlowConfigurationArchiveManager.java
index 1e034e1cf9..a21bbd703d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/FlowConfigurationArchiveManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/FlowConfigurationArchiveManager.java
@@ -78,11 +78,7 @@ public class FlowConfigurationArchiveManager {
         final String archiveDirVal = properties.getFlowConfigurationArchiveDir();
         final Path archiveDirectory;
         if (archiveDirVal == null || archiveDirVal.trim().isEmpty()) {
-            File persistenceFile = properties.getFlowConfigurationJsonFile();
-            if (persistenceFile == null) {
-                persistenceFile = properties.getFlowConfigurationFile();
-            }
-
+            File persistenceFile = properties.getFlowConfigurationFile();
             archiveDirectory = (archiveDirVal == null || archiveDirVal.equals(""))
                 ? persistenceFile.toPath().getParent().resolve("archive") : new File(archiveDirVal).toPath();
         } else {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardFlowConfigurationDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardFlowConfigurationDAO.java
index b39fc5adb8..a327bf8209 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardFlowConfigurationDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardFlowConfigurationDAO.java
@@ -16,18 +16,23 @@
  */
 package org.apache.nifi.persistence;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
 import org.apache.nifi.cluster.protocol.DataFlow;
 import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.FlowSerializationStrategy;
 import org.apache.nifi.controller.MissingBundleException;
 import org.apache.nifi.controller.UninheritableFlowException;
-import org.apache.nifi.controller.XmlFlowSynchronizer;
 import org.apache.nifi.controller.serialization.FlowSerializationException;
 import org.apache.nifi.controller.serialization.FlowSerializer;
 import org.apache.nifi.controller.serialization.FlowSynchronizationException;
 import org.apache.nifi.controller.serialization.FlowSynchronizer;
-import org.apache.nifi.controller.serialization.StandardFlowSerializer;
-import org.apache.nifi.controller.serialization.StandardFlowSynchronizer;
 import org.apache.nifi.controller.serialization.VersionedFlowSerializer;
 import org.apache.nifi.controller.serialization.VersionedFlowSynchronizer;
 import org.apache.nifi.groups.BundleUpdateStrategy;
@@ -38,22 +43,11 @@ import org.apache.nifi.util.file.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.file.Files;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
 public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO {
     private static final Logger LOG = LoggerFactory.getLogger(StandardFlowConfigurationDAO.class);
     private static final String CLUSTER_FLOW_SERIALIZATION_FORMAT = "nifi.cluster.flow.serialization.format";
-    private static final String FLOW_SERIALIZATION_FORMAT_XML = "XML";
+    private static final String FLOW_SERIALIZATION_FORMAT_JSON = "JSON";
 
-    private final File xmlFile;
     private final File jsonFile;
     private final FlowConfigurationArchiveManager archiveManager;
     private final NiFiProperties nifiProperties;
@@ -61,16 +55,12 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
 
     private volatile boolean jsonFileExists;
     private final String clusterFlowSerializationFormat;
-    private final FlowSerializationStrategy serializationStrategy;
 
-    public StandardFlowConfigurationDAO(final NiFiProperties nifiProperties, final ExtensionManager extensionManager,
-                                        final FlowSerializationStrategy serializationStrategy) throws IOException {
+    public StandardFlowConfigurationDAO(final NiFiProperties nifiProperties, final ExtensionManager extensionManager) throws IOException {
         this.nifiProperties = nifiProperties;
-        this.clusterFlowSerializationFormat = nifiProperties.getProperty(CLUSTER_FLOW_SERIALIZATION_FORMAT);
-        this.serializationStrategy = serializationStrategy;
+        this.clusterFlowSerializationFormat = nifiProperties.getProperty(CLUSTER_FLOW_SERIALIZATION_FORMAT, FLOW_SERIALIZATION_FORMAT_JSON);
 
-        xmlFile = nifiProperties.getFlowConfigurationFile();
-        jsonFile = nifiProperties.getFlowConfigurationJsonFile();
+        jsonFile = nifiProperties.getFlowConfigurationFile();
 
         jsonFileExists = jsonFile.length() > 0L;
 
@@ -97,13 +87,10 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
     public synchronized void load(final FlowController controller, final DataFlow dataFlow, final FlowService flowService, final BundleUpdateStrategy bundleUpdateStrategy)
             throws IOException, FlowSerializationException, FlowSynchronizationException, UninheritableFlowException, MissingBundleException {
 
-        final VersionedFlowSynchronizer versionedFlowSynchronizer = new VersionedFlowSynchronizer(extensionManager, nifiProperties.getFlowConfigurationJsonFile(), archiveManager);
-        final XmlFlowSynchronizer xmlFlowSynchronizer = new XmlFlowSynchronizer(nifiProperties, extensionManager);
-        final FlowSynchronizer standardFlowSynchronizer = new StandardFlowSynchronizer(xmlFlowSynchronizer, versionedFlowSynchronizer);
-
+        final FlowSynchronizer standardFlowSynchronizer = new VersionedFlowSynchronizer(extensionManager, nifiProperties.getFlowConfigurationFile(), archiveManager);
         controller.synchronize(standardFlowSynchronizer, dataFlow, flowService, bundleUpdateStrategy);
 
-        if (StandardFlowSynchronizer.isFlowEmpty(dataFlow)) {
+        if (VersionedFlowSynchronizer.isFlowEmpty(dataFlow)) {
             // If the dataflow is empty, we want to save it. We do this because when we start up a brand new cluster with no
             // dataflow, we need to ensure that the flow is consistent across all nodes in the cluster and that upon restart
             // of NiFi, the root group ID does not change. However, we don't always want to save it, because if the flow is
@@ -116,14 +103,7 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
     }
 
     private File getReadableFile() {
-        if (jsonFileExists) {
-            return jsonFile;
-        }
-        if (xmlFile.length() > 0) {
-            return xmlFile;
-        }
-
-        return null;
+        return  jsonFileExists ? jsonFile : null;
     }
 
     @Override
@@ -166,10 +146,10 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
         try {
             // Serialize based on the serialization format configured for cluster communications. If not configured, use JSON.
             final FlowSerializer<?> serializer;
-            if (FLOW_SERIALIZATION_FORMAT_XML.equalsIgnoreCase(clusterFlowSerializationFormat)) {
-                serializer = new StandardFlowSerializer();
-            } else {
+            if (FLOW_SERIALIZATION_FORMAT_JSON.equalsIgnoreCase(clusterFlowSerializationFormat)) {
                 serializer = new VersionedFlowSerializer(extensionManager);
+            } else {
+                throw new IllegalArgumentException("Unknown serialization format");
             }
 
             controller.serialize(serializer, os);
@@ -184,12 +164,8 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
             throw new NullPointerException();
         }
 
-        if (serializationStrategy.writesJson()) {
-            saveJson(controller, archive);
-        }
-        if (serializationStrategy.writesXml()) {
-            saveXml(controller, archive);
-        }
+        saveJson(controller, archive);
+
     }
 
     private void saveJson(final FlowController controller, final boolean archive) throws IOException {
@@ -198,11 +174,6 @@ public final class StandardFlowConfigurationDAO implements FlowConfigurationDAO
         jsonFileExists = true;
     }
 
-    private void saveXml(final FlowController controller, final boolean archive) throws IOException {
-        final FlowSerializer<?> serializer = new StandardFlowSerializer();
-        saveFlow(controller, serializer, xmlFile, archive);
-    }
-
     private void saveFlow(final FlowController controller, final FlowSerializer<?> serializer, final File file, final boolean archive) throws IOException {
         final File tempFile = new File(file.getParentFile(), file.getName() + ".temp.gz");
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/spring/StandardFlowServiceFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/spring/StandardFlowServiceFactoryBean.java
index 87d1d333fa..de85778888 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/spring/StandardFlowServiceFactoryBean.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/spring/StandardFlowServiceFactoryBean.java
@@ -20,7 +20,6 @@ import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.cluster.coordination.ClusterCoordinator;
 import org.apache.nifi.cluster.protocol.impl.NodeProtocolSenderListener;
 import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.FlowSerializationStrategy;
 import org.apache.nifi.controller.StandardFlowService;
 import org.apache.nifi.encrypt.PropertyEncryptor;
 import org.apache.nifi.services.FlowService;
@@ -64,8 +63,7 @@ public class StandardFlowServiceFactoryBean implements FactoryBean, ApplicationC
                     flowController,
                     properties,
                     revisionManager,
-                    authorizer,
-                    FlowSerializationStrategy.WRITE_XML_AND_JSON);
+                    authorizer);
             }
         }
 
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
index 1918e33840..68786fe667 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
@@ -19,39 +19,16 @@ package org.apache.nifi.util;
 import org.apache.commons.io.IOUtils;
 import org.apache.nifi.cluster.protocol.StandardDataFlow;
 import org.apache.nifi.controller.flow.VersionedDataflow;
-import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
 import org.apache.nifi.flow.VersionedPort;
 import org.apache.nifi.flow.VersionedProcessGroup;
-import org.apache.nifi.util.file.FileUtils;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.PositionDTO;
-import org.apache.nifi.xml.processing.ProcessingException;
-import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
-import org.apache.nifi.xml.processing.transform.StandardTransformProvider;
-import org.apache.nifi.xml.processing.transform.TransformProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
 
-import javax.xml.XMLConstants;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
@@ -60,7 +37,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
 
 /**
  * Parses a flow and returns the root group id and root group ports.
@@ -69,16 +45,6 @@ public class FlowParser {
 
     private static final Logger logger = LoggerFactory.getLogger(FlowParser.class);
 
-    private static final String FLOW_XSD = "/FlowConfiguration.xsd";
-    private static final byte XML_FIRST_CHARACTER = '<';
-
-    private final Schema flowSchema;
-
-    public FlowParser() throws SAXException {
-        SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        flowSchema = schemaFactory.newSchema(FlowParser.class.getResource(FLOW_XSD));
-    }
-
     /**
      * Extracts the root group id from the flow configuration file provided in nifi.properties, and extracts
      * the root group input ports and output ports, and their access controls.
@@ -112,61 +78,13 @@ public class FlowParser {
                 return null;
             }
 
-            if (isXml(flowBytes)) {
-                return parseXml(flowBytes);
-            }
-
             return parseJson(flowBytes);
-        } catch (final SAXException | ParserConfigurationException | IOException ex) {
+        } catch (final IOException ex) {
             logger.error("Unable to parse flow {}", flowPath.toAbsolutePath(), ex);
             return null;
         }
     }
 
-    private boolean isXml(final byte[] contents) {
-        if (contents == null || contents.length == 0) {
-            return false;
-        }
-
-        final byte firstByte = contents[0];
-        return firstByte == XML_FIRST_CHARACTER;
-    }
-
-    private FlowInfo parseXml(final byte[] flowBytes) throws ParserConfigurationException, IOException, SAXException {
-        // create validating document builder
-        final ErrorHandler errorHandler = new LoggingXmlParserErrorHandler("Flow Configuration", logger);
-        final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
-        documentProvider.setSchema(flowSchema);
-        documentProvider.setNamespaceAware(true);
-        documentProvider.setErrorHandler(errorHandler);
-
-        // parse the flow
-        final Document document = documentProvider.parse(new ByteArrayInputStream(flowBytes));
-
-        // extract the root group id
-        final Element rootElement = document.getDocumentElement();
-
-        final Element rootGroupElement = (Element) rootElement.getElementsByTagName("rootGroup").item(0);
-        if (rootGroupElement == null) {
-            logger.warn("rootGroup element not found in Flow Configuration file");
-            return null;
-        }
-
-        final Element rootGroupIdElement = (Element) rootGroupElement.getElementsByTagName("id").item(0);
-        if (rootGroupIdElement == null) {
-            logger.warn("id element not found under rootGroup in Flow Configuration file");
-            return null;
-        }
-
-        final String rootGroupId = rootGroupIdElement.getTextContent();
-
-        final List<PortDTO> ports = new ArrayList<>();
-        ports.addAll(getPorts(rootGroupElement, "inputPort"));
-        ports.addAll(getPorts(rootGroupElement, "outputPort"));
-
-        return new FlowInfo(rootGroupId, ports);
-    }
-
     private FlowInfo parseJson(final byte[] flowBytes) {
         final StandardDataFlow standardDataFlow = new StandardDataFlow(flowBytes, new byte[0], null, Collections.emptySet());
         final VersionedDataflow dataflow = standardDataFlow.getVersionedDataflow();
@@ -207,114 +125,4 @@ public class FlowParser {
         dto.setType(port.getType().name());
         return dto;
     }
-
-    /**
-     * Generates a {@link Document} from the flow configuration file provided
-     */
-    public Document parseDocument(final File flowConfigurationFile) {
-        if (flowConfigurationFile == null) {
-            logger.debug("Flow Configuration file was null");
-            return null;
-        }
-
-        // if the flow doesn't exist or is 0 bytes, then return null
-        final Path flowPath = flowConfigurationFile.toPath();
-        try {
-            if (!Files.exists(flowPath) || Files.size(flowPath) == 0) {
-                logger.warn("Flow Configuration does not exist or was empty");
-                return null;
-            }
-        } catch (IOException e) {
-            logger.error("An error occurred determining the size of the Flow Configuration file");
-            return null;
-        }
-
-        // otherwise create the appropriate input streams to read the file
-        try (final InputStream in = Files.newInputStream(flowPath, StandardOpenOption.READ);
-             final InputStream gzipIn = new GZIPInputStream(in)) {
-
-            final byte[] flowBytes = IOUtils.toByteArray(gzipIn);
-            if (flowBytes == null || flowBytes.length == 0) {
-                logger.warn("Could not extract root group id because Flow Configuration File was empty");
-                return null;
-            }
-
-            // create validating document builder
-            final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
-            documentProvider.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
-            documentProvider.setSchema(flowSchema);
-            documentProvider.setNamespaceAware(true);
-            return documentProvider.parse(new ByteArrayInputStream(flowBytes));
-        } catch (final ProcessingException | IOException e) {
-            logger.error("Unable to parse flow {}", flowPath.toAbsolutePath(), e);
-            return null;
-        }
-    }
-
-    /**
-     * Gets the ports that are direct children of the given element.
-     *
-     * @param element the element containing ports
-     * @param type the type of port to find (inputPort or outputPort)
-     * @return a list of PortDTOs representing the found ports
-     */
-    private List<PortDTO> getPorts(final Element element, final String type) {
-        final List<PortDTO> ports = new ArrayList<>();
-
-        // add input ports
-        final List<Element> portNodeList = getChildrenByTagName(element, type);
-        for (final Element portElement : portNodeList) {
-            final PortDTO portDTO = FlowFromDOMFactory.getPort(portElement);
-            portDTO.setType(type);
-            ports.add(portDTO);
-        }
-
-        return  ports;
-    }
-
-    /**
-     * Writes a given XML Flow out to the specified path.
-     *
-     * @param flowDocument flowDocument of the associated XML content to write to disk
-     * @param flowXmlPath  path on disk to write the flow
-     * @throws IOException if there are issues in accessing the target destination for the flow
-     */
-    public void writeFlow(final Document flowDocument, final Path flowXmlPath) throws IOException {
-        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        final Source xmlSource = new DOMSource(flowDocument);
-        final Result outputTarget = new StreamResult(outputStream);
-
-        final TransformProvider transformProvider = new StandardTransformProvider();
-        transformProvider.transform(xmlSource, outputTarget);
-        final InputStream is = new ByteArrayInputStream(outputStream.toByteArray());
-
-        try (final OutputStream output = Files.newOutputStream(flowXmlPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
-             final OutputStream gzipOut = new GZIPOutputStream(output)) {
-            FileUtils.copy(is, gzipOut);
-        }
-    }
-
-    /**
-     * Finds child elements with the given tagName.
-     *
-     * @param element the parent element
-     * @param tagName the child element name to find
-     * @return a list of matching child elements
-     */
-    public static List<Element> getChildrenByTagName(final Element element, final String tagName) {
-        final List<Element> matches = new ArrayList<>();
-        final NodeList nodeList = element.getChildNodes();
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            final Node node = nodeList.item(i);
-            if (!(node instanceof Element)) {
-                continue;
-            }
-
-            final Element child = (Element) nodeList.item(i);
-            if (child.getNodeName().equals(tagName)) {
-                matches.add(child);
-            }
-        }
-        return matches;
-    }
 }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/LoggingXmlParserErrorHandler.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/LoggingXmlParserErrorHandler.java
deleted file mode 100644
index 6c7f7bf529..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/LoggingXmlParserErrorHandler.java
+++ /dev/null
@@ -1,43 +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.util;
-
-import org.slf4j.Logger;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-/**
- * ErrorHandler implementation for Logging XML schema validation errors
- */
-public class LoggingXmlParserErrorHandler extends DefaultHandler {
-
-    private final Logger logger;
-    private final String xmlDocTitle;
-    private static final String MESSAGE_FORMAT = "Schema validation %s parsing %s at line %d, col %d: %s";
-
-    public LoggingXmlParserErrorHandler(String xmlDocTitle, Logger logger) {
-        this.logger = logger;
-        this.xmlDocTitle = xmlDocTitle;
-    }
-
-    @Override
-    public void error(final SAXParseException err) throws SAXParseException {
-        String message = String.format(MESSAGE_FORMAT, "error", xmlDocTitle, err.getLineNumber(),
-                err.getColumnNumber(), err.getMessage());
-        logger.warn(message);
-    }
-}
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
deleted file mode 100644
index 5cc09cc537..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/resources/FlowConfiguration.xsd
+++ /dev/null
@@ -1,607 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0">
-    <xs:element name="flowController" type="FlowControllerType" />
-
-    <xs:complexType name="FlowControllerType">
-        <xs:sequence>
-            <xs:choice>
-                <xs:element name="maxThreadCount" type="xs:positiveInteger"/>
-                <xs:sequence>
-                    <xs:element name="maxTimerDrivenThreadCount" type="xs:positiveInteger"/>
-                    <xs:element name="maxEventDrivenThreadCount" type="xs:positiveInteger"/>
-                </xs:sequence>
-            </xs:choice>
-
-            <xs:element name="registries" type="RegistriesType" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="parameterContexts" type="ParameterContextsType" minOccurs="0" maxOccurs="1" />
-
-            <!-- Groupings of Processors/Ports -->
-            <xs:element name="rootGroup" type="RootProcessGroupType" />
-
-            <!-- This exists for backward compatibility between NiFi 1.x and NiFi 0.x. Any Controller Service that is listed
-            here is assigned to the root group -->
-            <xs:element name="controllerServices" type="ControllerServicesType" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="reportingTasks" type="ReportingTasksType" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="flowAnalysisRules" type="FlowAnalysisRulesType" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="parameterProviders" type="ParameterProvidersType" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-        <xs:attribute name="encoding-version" type="xs:string"/>
-    </xs:complexType>
-
-    <xs:complexType name="RegistriesType">
-        <xs:sequence>
-            <xs:element name="flowRegistry" type="FlowRegistryType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="FlowRegistryType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="url" type="xs:string" />
-            <xs:element name="description" type="xs:string" />
-
-            <!-- "class" is the actual Java class that performs the type of processing desired-->
-            <xs:element name="class" type="NonEmptyStringType"/>
-            <xs:element name="bundle" type="BundleType" />
-
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ParameterContextsType">
-        <xs:sequence>
-            <xs:element name="parameterContext" type="ParameterContextType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ParameterContextType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="inheritedParameterContextId" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="parameterProviderId" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="parameterGroupName" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="isSynchronized" type="xs:boolean" minOccurs="0" maxOccurs="1" />
-            <xs:element name="parameter" type="ParameterType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ParameterType">
-        <xs:sequence>
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="description" type="xs:string" />
-            <xs:element name="sensitive" type="xs:boolean" />
-            <xs:element name="provided" type="xs:boolean" />
-            <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- the processor "id" is a key that should be valid within each flowController-->
-    <xs:complexType name="ProcessorType">
-        <xs:sequence>
-            <!-- The "id" is a name that is tied to the ability for a FlowFile to be recovered in the event
-            of unexpected process termination or execution failure.  The "id" should rarely change and if it
-            must then the database directory should be deleted to be safe.-->
-            <xs:element name="id" type="NonEmptyStringType"/>
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-
-            <!-- The "name" is a nicely displayable description of the processor's duty-->
-            <xs:element name="name" type="NonEmptyStringType"/>
-
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="styles" type="Styles" />
-
-            <!-- The "comment" section allows users to store important context information
-            for this processor.  This information may display in GUI or in logs or
-            whatever presentation the application might have.-->
-            <xs:element name="comment" type="xs:string" minOccurs="0" maxOccurs="1"/>
-
-            <!-- "class" is the actual Java class that performs the type of processing desired-->
-            <xs:element name="class" type="NonEmptyStringType"/>
-            <xs:element name="bundle" type="BundleType" />
-
-            <!-- the number of concurrent tasks for this configured
-            processor that can be executed at any one time. This value can be 0
-            IFF schedulingStrategy is EVENT_DRIVEN -->
-            <xs:element name="maxConcurrentTasks" type="xs:nonNegativeInteger"/>
-
-            <xs:element name="schedulingPeriod" type="NonEmptyStringType"/>
-
-            <xs:element name="penalizationPeriod" type="TimePeriod" />
-
-            <xs:element name="yieldPeriod" type="TimePeriod" />
-
-            <xs:element name="bulletinLevel" type="LogLevel" />
-
-            <!-- whether or not this processor is loss-tolerant -->
-            <xs:element name="lossTolerant" type="xs:boolean" />
-
-            <xs:element name="scheduledState" type="ScheduledState" />
-
-            <!-- "isolated" is deprecated.
-            Was used to determine whether or not this processor runs on the primary node
-            in a clustered environment.  If 'true', then the processor runs on only the
-            primary node.  If 'false' or not present, then the processor runs on all the
-            nodes. -->
-            <xs:element name="isolated" type="xs:boolean" maxOccurs="1" minOccurs="0" />
-
-            <xs:element name="schedulingStrategy" type="SchedulingStrategy" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="executionNode" type="ExecutionNode" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="runDurationNanos" type="xs:long" minOccurs="0" maxOccurs="1" />
-
-            <!-- properties that must be valid for the processor to execute.
-            The valid required properties can be read by looking at this processor's Javadocs-->
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-
-            <!-- Annotation data used for more advanced configuration -->
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-
-            <!-- Indicates that a relationship with the given name can be auto-terminated -->
-            <xs:element name="autoTerminatedRelationship" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
-
-            <xs:element name="retryCount" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="retriedRelationships" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
-
-            <xs:element name="backoffMechanism" type="BackoffMechanism" minOccurs="0" maxOccurs="1" />
-
-            <xs:element name="maxBackoffPeriod" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- The "name" should be a key within each processor-->
-    <xs:complexType name="PropertyType">
-        <xs:sequence>
-            <xs:element name="name" type="NonEmptyStringType"/>
-            <!-- Not present if the value has not been set. -->
-            <xs:element name="value" type="xs:string" minOccurs="0" maxOccurs="1"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:simpleType name="NonEmptyStringType">
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1"/>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="ScheduledState">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="DISABLED"></xs:enumeration>
-            <xs:enumeration value="RUNNING"></xs:enumeration>
-            <xs:enumeration value="STOPPED"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="FlowAnalysisRuleEnforcementPolicy">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="ENFORCE"></xs:enumeration>
-            <xs:enumeration value="WARN"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="FlowAnalysisState">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="ENABLED"></xs:enumeration>
-            <xs:enumeration value="DISABLED"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:complexType name="ProcessGroupType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="flowfileConcurrency" type="FlowFileConcurrencyType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="flowfileOutboundPolicy" type="FlowFileOutboundPolicyType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultFlowFileExpiration" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultBackPressureObjectThreshold" type="xs:long" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultBackPressureDataSizeThreshold" type="xs:string" minOccurs="0" maxOccurs="1" />
-    		<xs:element name="versionControlInformation" type="VersionControlInformation" minOccurs="0" maxOccurs="1" />
-            <xs:element name="logFileSuffix" type="xs:string" minOccurs="0" maxOccurs="1"/>
-
-            <!-- Each "processor" defines the actual dataflow work horses that make dataflow happen-->
-            <xs:element name="processor" type="ProcessorType" minOccurs="0" maxOccurs="unbounded"/>
-
-            <xs:element name="inputPort" type="PublicPortType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="outputPort" type="PublicPortType" minOccurs="0" maxOccurs="unbounded"/>
-
-            <xs:element name="label" type="LabelType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="funnel" type="FunnelType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="processGroup" type="ProcessGroupType" minOccurs="0" maxOccurs="unbounded"	/>
-            <xs:element name="remoteProcessGroup" type="RemoteProcessGroupType" minOccurs="0" maxOccurs="unbounded"	/>
-            <xs:element name="connection" type="ConnectionType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="controllerService" type="ControllerServiceType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="parameterContextId" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:simpleType name="FlowFileConcurrencyType">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="SINGLE_FLOWFILE_PER_NODE" />
-            <xs:enumeration value="SINGLE_BATCH_PER_NODE" />
-            <xs:enumeration value="UNBOUNDED" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="FlowFileOutboundPolicyType">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="STREAM_WHEN_AVAILABLE" />
-            <xs:enumeration value="BATCH_OUTPUT" />
-        </xs:restriction>
-    </xs:simpleType>
-
-
-    <xs:complexType name="VersionControlInformation">
-        <xs:sequence>
-            <xs:element name="registryId" type="NonEmptyStringType" />
-            <xs:element name="bucketId" type="NonEmptyStringType" />
-            <xs:element name="bucketName" type="NonEmptyStringType" />
-            <xs:element name="flowId" type="NonEmptyStringType" />
-            <xs:element name="flowName" type="NonEmptyStringType" />
-            <xs:element name="flowDescription" type="xs:string" />
-            <xs:element name="version" type="NonEmptyStringType" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- Same as ProcessGroupType except:
-         - RootProcessGroupType doesn't have versionControlInformation -->
-    <xs:complexType name="RootProcessGroupType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="flowfileConcurrency" type="FlowFileConcurrencyType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="flowfileOutboundPolicy" type="FlowFileOutboundPolicyType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultFlowFileExpiration" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultBackPressureObjectThreshold" type="xs:long" minOccurs="0" maxOccurs="1" />
-            <xs:element name="defaultBackPressureDataSizeThreshold" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="logFileSuffix" type="xs:string" minOccurs="0" maxOccurs="1"/>
-
-            <!-- Each "processor" defines the actual dataflow work horses that make dataflow happen-->
-            <xs:element name="processor" type="ProcessorType" minOccurs="0" maxOccurs="unbounded"/>
-
-            <xs:element name="inputPort" type="PublicPortType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="outputPort" type="PublicPortType" minOccurs="0" maxOccurs="unbounded"/>
-
-            <xs:element name="label" type="LabelType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="funnel" type="FunnelType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="processGroup" type="ProcessGroupType" minOccurs="0" maxOccurs="unbounded"	/>
-            <xs:element name="remoteProcessGroup" type="RemoteProcessGroupType" minOccurs="0" maxOccurs="unbounded"	/>
-            <xs:element name="connection" type="ConnectionType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="controllerService" type="ControllerServiceType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="parameterContextId" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="FunnelType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="position" type="PositionType" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="LabelType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="size" type="SizeType" />
-            <xs:element name="styles" type="Styles" />
-            <xs:element name="value" type="xs:string" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="RemoteProcessGroupType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="xs:string" />
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="url" type="xs:anyURI" />
-            <xs:element name="urls" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="timeout" type="xs:string" />
-            <xs:element name="yieldPeriod" type="TimePeriod" minOccurs="0" maxOccurs="1" />
-            <xs:element name="transmitting" type="xs:boolean" />
-            <xs:element name="transportProtocol" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="proxyHost" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="proxyPort" type="xs:int" minOccurs="0" maxOccurs="1" />
-            <xs:element name="proxyUser" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="proxyPassword" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="networkInterface" type="xs:string" minOccurs="0" maxOccurs="1" />
-
-            <!-- The input ports and output ports of the remote group may change without our knowledge; however,
-            they are persisted here because on a restart of NiFi, we need to have the Input & Output Ports' IDs
-            and associated names persisted so that we can attempt to connect to these ports -->
-            <xs:element name="inputPort" type="RemoteGroupPortType" minOccurs="0" maxOccurs="unbounded" />
-            <xs:element name="outputPort" type="RemoteGroupPortType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ConnectionType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="xs:string" />
-            <xs:element name="bendPoints" type="BendPointsType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="labelIndex" type="xs:int" minOccurs="0" maxOccurs="1" />
-            <xs:element name="zIndex" type="xs:int" minOccurs="0" maxOccurs="1" />
-            <xs:element name="sourceId" type="NonEmptyStringType" />
-            <xs:element name="sourceGroupId" type="NonEmptyStringType" />
-            <xs:element name="sourceType" type="NonEmptyStringType" />
-            <xs:element name="destinationId" type="NonEmptyStringType" />
-            <xs:element name="destinationGroupId" type="NonEmptyStringType" />
-            <xs:element name="destinationType" type="NonEmptyStringType" />
-            <!-- relationship will be an empty string for Ports. -->
-            <xs:element name="relationship" type="xs:string" minOccurs="1" maxOccurs="unbounded" />
-
-            <!-- "maxWorkQueueSize" is the maximum size this processors work queue should be
-            before other processors are expected (not required) to stop loading new files onto it.-->
-            <xs:element name="maxWorkQueueSize" type="xs:nonNegativeInteger"/>
-
-            <xs:element name="maxWorkQueueDataSize" type="DataSize" minOccurs="0" maxOccurs="1" />
-
-            <!-- "flowFileExpirationMinutes" is the maximum time that a flow file may remain
-            passing through the flow as configured.  If a flow file reaches the
-            configured maximum age the next processor to see this flow file
-            will immediately remove it from the flow.  A value of zero (the default)
-            means that no maximum age will be enforced.-->
-            <xs:element name="flowFileExpiration" type="TimePeriod" minOccurs="0" maxOccurs="1"/>
-
-            <!-- "queuePrioritizerClass" are Java classes that can be used to prioritize the work queues for this
-            processor.  The order of the prioritizers is important.-->
-            <xs:element name="queuePrioritizerClass" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
-
-            <xs:element name="loadBalanceStrategy" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="partitioningAttribute" type="xs:string" minOccurs="0" maxOccurs="1" />
-            <xs:element name="loadBalanceCompression" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="PortType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="position" type="PositionType" />
-            <xs:element name="comments" type="xs:string" />
-            <xs:element name="scheduledState" type="ScheduledState" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="PublicPortType">
-        <xs:complexContent>
-            <xs:extension base="PortType">
-                <xs:sequence>
-                    <xs:element name="maxConcurrentTasks" type="xs:positiveInteger" minOccurs="0" ></xs:element>
-                    <xs:element name="userAccessControl" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
-                    <xs:element name="groupAccessControl" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
-                    <xs:element name="allowRemoteAccess" type="xs:boolean" minOccurs="0" maxOccurs="1" />
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-
-    <xs:complexType name="RemoteGroupPortType">
-        <xs:complexContent>
-            <xs:extension base="PortType">
-                <xs:sequence>
-                    <xs:element name="targetId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-                    <xs:element name="maxConcurrentTasks" type="xs:positiveInteger"></xs:element>
-                    <xs:element name="useCompression" type="xs:boolean"></xs:element>
-                    <xs:element name="batchCount" type="xs:positiveInteger" minOccurs="0" maxOccurs="1" />
-                    <xs:element name="batchSize" type="xs:string" minOccurs="0" maxOccurs="1" />
-                    <xs:element name="batchDuration" type="xs:string" minOccurs="0" maxOccurs="1" />
-                </xs:sequence>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-
-    <xs:complexType name="BundleType">
-        <xs:sequence>
-            <xs:element name="group" type="NonEmptyStringType" />
-            <xs:element name="artifact" type="NonEmptyStringType" />
-            <xs:element name="version" type="NonEmptyStringType" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="PositionType">
-        <xs:attribute name="x" type="xs:double" use="required" />
-        <xs:attribute name="y" type="xs:double" use="required" />
-    </xs:complexType>
-
-    <xs:complexType name="SizeType">
-        <xs:attribute name="width" type="xs:double" use="required" />
-        <xs:attribute name="height" type="xs:double" use="required" />
-    </xs:complexType>
-
-
-    <xs:complexType name="BendPointsType">
-        <xs:sequence>
-            <xs:element name="bendPoint" type="PositionType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="Styles">
-        <xs:sequence>
-            <xs:element name="style" type="Style" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="Style">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" use="required"></xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="TimePeriod">
-        <xs:restriction base="xs:string">
-            <xs:pattern value="\d+\s*(ns|nano|nanos|nanosecond|nanoseconds|ms|milli|millis|millisecond|milliseconds|s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days|w|wk|wks|week|weeks)"></xs:pattern>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="DataSize">
-        <xs:restriction base="xs:string">
-            <xs:pattern value="\d+\s*(B|KB|MB|GB|TB|b|kb|mb|gb|tb)" />
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="LogLevel">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="TRACE"></xs:enumeration>
-            <xs:enumeration value="DEBUG"></xs:enumeration>
-            <xs:enumeration value="INFO"></xs:enumeration>
-            <xs:enumeration value="WARN"></xs:enumeration>
-            <xs:enumeration value="ERROR"></xs:enumeration>
-            <xs:enumeration value="FATAL"></xs:enumeration>
-            <xs:enumeration value="NONE"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="SchedulingStrategy">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="EVENT_DRIVEN"></xs:enumeration>
-            <xs:enumeration value="TIMER_DRIVEN"></xs:enumeration>
-            <xs:enumeration value="PRIMARY_NODE_ONLY"></xs:enumeration>
-            <xs:enumeration value="CRON_DRIVEN"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="BackoffMechanism">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="PENALIZE_FLOWFILE"></xs:enumeration>
-            <xs:enumeration value="YIELD_PROCESSOR"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:simpleType name="ExecutionNode">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="ALL"></xs:enumeration>
-            <xs:enumeration value="PRIMARY"></xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:complexType name="ControllerServicesType">
-        <xs:sequence>
-            <xs:element name="controllerService" type="ControllerServiceType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ControllerServiceType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="versionedComponentId" type="NonEmptyStringType" minOccurs="0" maxOccurs="1" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="bulletinLevel" type="LogLevel" minOccurs="0" maxOccurs="1" />
-            <xs:element name="class" type="NonEmptyStringType" />
-            <xs:element name="bundle" type="BundleType" />
-            <xs:element name="enabled" type="xs:boolean" />
-
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ReportingTasksType">
-        <xs:sequence>
-            <xs:element name="reportingTask" type="ReportingTaskType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ReportingTaskType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="class" type="NonEmptyStringType" />
-            <xs:element name="bundle" type="BundleType" />
-            <xs:element name="schedulingPeriod" type="NonEmptyStringType"/>
-            <xs:element name="scheduledState" type="ScheduledState" />
-            <xs:element name="schedulingStrategy" type="SchedulingStrategy" />
-
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="FlowAnalysisRulesType">
-        <xs:sequence>
-            <xs:element name="flowAnalysisRule" type="FlowAnalysisRuleType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="FlowAnalysisRuleType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="class" type="NonEmptyStringType" />
-            <xs:element name="bundle" type="BundleType" />
-
-            <xs:element name="enforcementPolicy" type="FlowAnalysisRuleEnforcementPolicy"/>
-            <xs:element name="state" type="FlowAnalysisState" />
-
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ParameterProvidersType">
-        <xs:sequence>
-            <xs:element name="parameterProvider" type="ParameterProviderType" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="ParameterProviderType">
-        <xs:sequence>
-            <xs:element name="id" type="NonEmptyStringType" />
-            <xs:element name="name" type="NonEmptyStringType" />
-            <xs:element name="comment" type="xs:string" />
-            <xs:element name="class" type="NonEmptyStringType" />
-            <xs:element name="bundle" type="BundleType" />
-
-            <xs:element name="property" type="PropertyType" minOccurs="0" maxOccurs="unbounded"/>
-            <xs:element name="annotationData" type="xs:string" minOccurs="0" maxOccurs="1" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="SnippetType">
-        <xs:sequence>
-            <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-        <xs:anyAttribute processContents="skip" />
-    </xs:complexType>
-
-</xs:schema>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
index 73992feb97..c3c24a017c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
@@ -20,10 +20,12 @@ import org.apache.commons.io.IOUtils;
 import org.apache.nifi.admin.service.AuditService;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.cluster.protocol.StandardDataFlow;
+import org.apache.nifi.controller.flow.VersionedDataflow;
 import org.apache.nifi.controller.repository.FlowFileEventRepository;
 import org.apache.nifi.controller.serialization.FlowSerializationException;
+import org.apache.nifi.controller.serialization.FlowSerializer;
 import org.apache.nifi.controller.serialization.ScheduledStateLookup;
-import org.apache.nifi.controller.serialization.StandardFlowSerializer;
+import org.apache.nifi.controller.serialization.VersionedFlowSerializer;
 import org.apache.nifi.controller.status.history.StatusHistoryRepository;
 import org.apache.nifi.encrypt.PropertyEncryptor;
 import org.apache.nifi.events.VolatileBulletinRepository;
@@ -39,11 +41,10 @@ import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.revision.RevisionManager;
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
-import org.w3c.dom.Document;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -86,19 +87,18 @@ public class StandardFlowServiceTest {
         extensionManager = mock(ExtensionDiscoveringManager.class);
         flowController = FlowController.createStandaloneInstance(mockFlowFileEventRepository, properties, authorizer, mockAuditService, mockEncryptor,
                                         new VolatileBulletinRepository(), extensionManager, statusHistoryRepository, null);
-        flowService = StandardFlowService.createStandaloneInstance(flowController, properties, revisionManager, authorizer,
-                FlowSerializationStrategy.WRITE_XML_AND_JSON);
+        flowService = StandardFlowService.createStandaloneInstance(flowController, properties, revisionManager, authorizer);
         statusHistoryRepository = mock(StatusHistoryRepository.class);
     }
 
     @Test
     public void testLoadWithFlow() throws IOException {
-        byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml"));
+        byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.json"));
         flowService.load(new StandardDataFlow(flowBytes, null, null, new HashSet<>()));
 
-        StandardFlowSerializer serializer = new StandardFlowSerializer();
+        final FlowSerializer<VersionedDataflow> serializer = new VersionedFlowSerializer(extensionManager);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final Document doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
+        final VersionedDataflow doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
         serializer.serialize(doc, baos);
 
         String expectedFlow = new String(flowBytes).trim();
@@ -118,15 +118,15 @@ public class StandardFlowServiceTest {
 
     @Test
     public void testLoadExistingFlow() throws IOException {
-        byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml"));
+        byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.json"));
         flowService.load(new StandardDataFlow(flowBytes, null, null, new HashSet<>()));
 
-        flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-inheritable.xml"));
+        flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-inheritable.json"));
         flowService.load(new StandardDataFlow(flowBytes, null, null, new HashSet<>()));
 
-        StandardFlowSerializer serializer = new StandardFlowSerializer();
+        final FlowSerializer<VersionedDataflow> serializer = new VersionedFlowSerializer(extensionManager);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        final Document doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
+        final VersionedDataflow doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
         serializer.serialize(doc, baos);
 
         String expectedFlow = new String(flowBytes).trim();
@@ -136,17 +136,17 @@ public class StandardFlowServiceTest {
 
     @Test
     public void testLoadExistingFlowWithUninheritableFlow() throws IOException {
-        byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml"));
+        byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.json"));
         flowService.load(new StandardDataFlow(originalBytes, null, null, new HashSet<>()));
 
         try {
-            byte[] updatedBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-uninheritable.xml"));
+            byte[] updatedBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-uninheritable.json"));
             flowService.load(new StandardDataFlow(updatedBytes, null, null, new HashSet<>()));
             fail("should have thrown " + UninheritableFlowException.class);
         } catch (UninheritableFlowException ufe) {
-            StandardFlowSerializer serializer = new StandardFlowSerializer();
+            final FlowSerializer<VersionedDataflow> serializer = new VersionedFlowSerializer(extensionManager);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            final Document doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
+            final VersionedDataflow doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
             serializer.serialize(doc, baos);
 
             String expectedFlow = new String(originalBytes).trim();
@@ -158,7 +158,7 @@ public class StandardFlowServiceTest {
 
     @Test
     public void testLoadExistingFlowWithCorruptFlow() throws IOException {
-        byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml"));
+        byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.json"));
         flowService.load(new StandardDataFlow(originalBytes, null, null, new HashSet<>()));
 
         try {
@@ -166,9 +166,9 @@ public class StandardFlowServiceTest {
             flowService.load(new StandardDataFlow(updatedBytes, null, null, new HashSet<>()));
             fail("should have thrown " + FlowSerializationException.class);
         } catch (FlowSerializationException ufe) {
-            StandardFlowSerializer serializer = new StandardFlowSerializer();
+            final FlowSerializer<VersionedDataflow> serializer = new VersionedFlowSerializer(extensionManager);
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            final Document doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
+            final VersionedDataflow doc = serializer.transform(flowController, ScheduledStateLookup.IDENTITY_LOOKUP);
             serializer.serialize(doc, baos);
 
             String expectedFlow = new String(originalBytes).trim();
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 6cccd1011a..290f9cfc2f 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
@@ -43,7 +43,6 @@ import org.apache.nifi.controller.repository.FlowFileEventRepository;
 import org.apache.nifi.controller.scheduling.StandardProcessScheduler;
 import org.apache.nifi.controller.serialization.FlowSynchronizationException;
 import org.apache.nifi.controller.serialization.FlowSynchronizer;
-import org.apache.nifi.controller.serialization.StandardFlowSynchronizer;
 import org.apache.nifi.controller.serialization.VersionedFlowSynchronizer;
 import org.apache.nifi.controller.service.ControllerServiceNode;
 import org.apache.nifi.controller.service.ControllerServiceProvider;
@@ -86,8 +85,8 @@ import org.apache.nifi.web.api.dto.PositionDTO;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import java.io.File;
@@ -140,7 +139,7 @@ public class TestFlowController {
     private BulletinRepository bulletinRepo;
     private ExtensionDiscoveringManager extensionManager;
     private StatusHistoryRepository statusHistoryRepository;
-    private FlowSynchronizer standardFlowSynchronizer;
+    private FlowSynchronizer flowSynchronizer;
 
     private static List<String> allIdentifiers;
 
@@ -212,10 +211,8 @@ public class TestFlowController {
                 auditService, encryptor, bulletinRepo, extensionManager, statusHistoryRepository,
                 mock(RuleViolationsManager.class));
 
-        final XmlFlowSynchronizer xmlFlowSynchronizer = new XmlFlowSynchronizer(nifiProperties, extensionManager);
-        final VersionedFlowSynchronizer versionedFlowSynchronizer = new VersionedFlowSynchronizer(extensionManager,
-                nifiProperties.getFlowConfigurationJsonFile(), new FlowConfigurationArchiveManager(nifiProperties));
-        standardFlowSynchronizer = new StandardFlowSynchronizer(xmlFlowSynchronizer, versionedFlowSynchronizer);
+        flowSynchronizer = new VersionedFlowSynchronizer(extensionManager,
+                nifiProperties.getFlowConfigurationFile(), new FlowConfigurationArchiveManager(nifiProperties));
     }
 
     @AfterEach
@@ -247,12 +244,12 @@ public class TestFlowController {
     public void testSynchronizeFlowWithReportingTaskAndProcessorReferencingControllerService() throws IOException {
         // create a mock proposed data flow with the same auth fingerprint as the current authorizer
         final String authFingerprint = authorizer.getFingerprint();
-        final File flowFile = new File("src/test/resources/conf/reporting-task-with-cs-flow-0.7.0.xml");
+        final File flowFile = new File("src/test/resources/conf/reporting-task-with-cs-flow-0.7.0.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         // should be two controller services
         final Set<ControllerServiceNode> controllerServiceNodes = controller.getFlowManager().getAllControllerServices();
@@ -306,12 +303,12 @@ public class TestFlowController {
     public void testSynchronizeFlowWithParameterProviderReferencingControllerService() throws IOException {
         // create a mock proposed data flow with the same auth fingerprint as the current authorizer
         final String authFingerprint = authorizer.getFingerprint();
-        final File flowFile = new File("src/test/resources/conf/parameter-provider-with-cs-flow.xml");
+        final File flowFile = new File("src/test/resources/conf/parameter-provider-with-cs-flow.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         // should be two controller services
         final Set<ControllerServiceNode> controllerServiceNodes = controller.getFlowManager().getAllControllerServices();
@@ -365,12 +362,12 @@ public class TestFlowController {
     public void testSynchronizeFlowWithProcessorReferencingControllerService() throws IOException {
         // create a mock proposed data flow with the same auth fingerprint as the current authorizer
         final String authFingerprint = authorizer.getFingerprint();
-        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.xml");
+        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         try {
             // should be two controller services
@@ -407,31 +404,29 @@ public class TestFlowController {
         final DataFlow proposedDataFlow = mock(DataFlow.class);
         when(proposedDataFlow.getAuthorizerFingerprint()).thenReturn(authFingerprint.getBytes(StandardCharsets.UTF_8));
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         assertEquals(authFingerprint, authorizer.getFingerprint());
     }
 
     @Test
     public void testSynchronizeFlowWhenAuthorizationsAreDifferent() throws IOException {
-        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.xml");
+        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final String authFingerprint = "<authorizations></authorizations>";
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
         controller.initializeFlow();
 
-        assertThrows(UninheritableFlowException.class,
-                () -> controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
         assertNotEquals(authFingerprint, authorizer.getFingerprint());
         purgeFlow();
     }
 
     @Test
     public void testSynchronizeFlowWithInvalidParameterContextReference() throws IOException {
-        final File flowFile = new File("src/test/resources/conf/parameter-context-flow-error.xml");
+        final File flowFile = new File("src/test/resources/conf/parameter-context-flow-error.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final String authFingerprint = "<authorizations></authorizations>";
@@ -439,7 +434,7 @@ public class TestFlowController {
 
         assertThrows(FlowSynchronizationException.class,
                 () -> {
-                    controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+                    controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
                     controller.initializeFlow();
                 });
         purgeFlow();
@@ -447,14 +442,14 @@ public class TestFlowController {
 
     @Test
     public void testSynchronizeFlowWithNestedParameterContexts() throws IOException {
-        final File flowFile = new File("src/test/resources/conf/parameter-context-flow.xml");
+        final File flowFile = new File("src/test/resources/conf/parameter-context-flow.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final String authFingerprint = "<authorizations></authorizations>";
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
         try {
-            controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+            controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
             controller.initializeFlow();
 
             ParameterContext parameterContext = controller.getFlowManager().getParameterContextManager().getParameterContext("context");
@@ -469,14 +464,14 @@ public class TestFlowController {
 
     @Test
     public void testCreateParameterContextWithAndWithoutValidation() throws IOException {
-        final File flowFile = new File("src/test/resources/conf/parameter-context-flow.xml");
+        final File flowFile = new File("src/test/resources/conf/parameter-context-flow.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final String authFingerprint = "<authorizations></authorizations>";
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
 
         try {
-            controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+            controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
             controller.initializeFlow();
 
             final Map<String, Parameter> parameters = new HashMap<>();
@@ -520,7 +515,7 @@ public class TestFlowController {
         final DataFlow proposedDataFlow = mock(DataFlow.class);
         when(proposedDataFlow.getAuthorizerFingerprint()).thenReturn(authFingerprint.getBytes(StandardCharsets.UTF_8));
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
         assertNotEquals(authFingerprint, authorizer.getFingerprint());
 
         assertTrue(authorizer.getGroups().isEmpty());
@@ -530,19 +525,19 @@ public class TestFlowController {
 
     @Test
     public void testSynchronizeFlowWhenProposedAuthorizationsAreNull() throws IOException {
-        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.xml");
+        final File flowFile = new File("src/test/resources/conf/processor-with-cs-flow-0.7.0.json");
         final String flow = IOUtils.toString(new FileInputStream(flowFile), StandardCharsets.UTF_8);
 
         final String authFingerprint = "<authorizations></authorizations>";
         final DataFlow proposedDataFlow = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, authFingerprint.getBytes(StandardCharsets.UTF_8), Collections.emptySet());
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         controller.initializeFlow();
 
         final DataFlow dataflowWithNullAuthorizations = new StandardDataFlow(flow.getBytes(StandardCharsets.UTF_8), null, null, Collections.emptySet());
 
         assertThrows(UninheritableFlowException.class,
-                () -> controller.synchronize(standardFlowSynchronizer, dataflowWithNullAuthorizations, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
+                () -> controller.synchronize(flowSynchronizer, dataflowWithNullAuthorizations, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
         purgeFlow();
     }
 
@@ -550,8 +545,8 @@ public class TestFlowController {
     public void testSynchronizeFlowWhenProposedAuthorizationsAreNullAndEmptyFlow() {
         final DataFlow proposedDataFlow = mock(DataFlow.class);
         when(proposedDataFlow.getAuthorizerFingerprint()).thenReturn(null);
-
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        when(proposedDataFlow.getVersionedDataflow()).thenReturn(getVersionedDataflow());
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         assertTrue(authorizer.getGroups().isEmpty());
         assertTrue(authorizer.getUsers().isEmpty());
@@ -588,7 +583,7 @@ public class TestFlowController {
         controller.shutdown(true);
         controller = FlowController.createStandaloneInstance(flowFileEventRepo, nifiProperties, authorizer,
                 auditService, encryptor, bulletinRepo, extensionManager, statusHistoryRepository, null);
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
         assertEquals(authFingerprint, authorizer.getFingerprint());
     }
 
@@ -603,7 +598,7 @@ public class TestFlowController {
 
         UninheritableFlowException uninheritableFlowException =
                 assertThrows(UninheritableFlowException.class,
-                        () -> controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
+                        () -> controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
         assertTrue(uninheritableFlowException.getMessage().contains("Proposed flow has missing components " +
                 "that are not considered missing in the current flow (1,2)"), uninheritableFlowException.getMessage());
     }
@@ -643,7 +638,7 @@ public class TestFlowController {
         when(proposedDataFlow.getMissingComponents()).thenReturn(new HashSet<>());
         UninheritableFlowException uninheritableFlowException =
                 assertThrows(UninheritableFlowException.class,
-                        () -> standardFlowSynchronizer.sync(mockFlowController, proposedDataFlow,
+                        () -> flowSynchronizer.sync(mockFlowController, proposedDataFlow,
                                 mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE));
         assertTrue(uninheritableFlowException.getMessage().contains("Current flow has missing components that are not" +
                         " considered missing in the proposed flow (1,2,3)"), uninheritableFlowException.getMessage());
@@ -654,8 +649,8 @@ public class TestFlowController {
         final LogRepository logRepository = LogRepositoryFactory.getRepository("d89ada5d-35fb-44ff-83f1-4cc00b48b2df");
         logRepository.removeAllObservers();
 
-        syncFlow("src/test/resources/nifi/fingerprint/flow4.xml", standardFlowSynchronizer);
-        syncFlow("src/test/resources/nifi/fingerprint/flow4.xml", standardFlowSynchronizer);
+        syncFlow("src/test/resources/nifi/fingerprint/flow4.json", flowSynchronizer);
+        syncFlow("src/test/resources/nifi/fingerprint/flow4.json", flowSynchronizer);
     }
 
     @Test
@@ -664,14 +659,14 @@ public class TestFlowController {
         logRepository.removeAllObservers();
 
         // first sync should work because we are syncing to an empty flow controller
-        syncFlow("src/test/resources/nifi/fingerprint/flow4.xml", standardFlowSynchronizer);
+        syncFlow("src/test/resources/nifi/fingerprint/flow4.json", flowSynchronizer);
 
         controller.initializeFlow();
 
         // second sync should fail because the bundle of the processor is different
         assertThrows(UninheritableFlowException.class,
-                () -> syncFlow("src/test/resources/nifi/fingerprint/flow4-with-different-bundle.xml",
-                        standardFlowSynchronizer));
+                () -> syncFlow("src/test/resources/nifi/fingerprint/flow4-with-different-bundle.json",
+                        flowSynchronizer));
     }
 
     private void syncFlow(String flowXmlFile, FlowSynchronizer standardFlowSynchronizer) throws IOException {
@@ -686,7 +681,7 @@ public class TestFlowController {
         final byte[] authFingerprintBytes = authFingerprint.getBytes(StandardCharsets.UTF_8);
         final DataFlow proposedDataFlow1 = new StandardDataFlow(flowBytes, null, authFingerprintBytes, Collections.emptySet());
 
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow1, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(standardFlowSynchronizer, proposedDataFlow1, mock(FlowService.class), BundleUpdateStrategy.USE_SPECIFIED_OR_FAIL);
     }
 
     @Test
@@ -1303,10 +1298,7 @@ public class TestFlowController {
                 authFingerprint.getBytes(StandardCharsets.UTF_8),
                 Collections.emptySet());
 
-        // following assertion asserts that VersionedFlowSynchronizer is used
-        assertFalse(proposedDataFlow.isXml());
-
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         // should be an empty dataflow
         final Map<String, Integer> componentCounts = controller.getFlowManager().getComponentCounts();
@@ -1334,10 +1326,7 @@ public class TestFlowController {
                 authFingerprint.getBytes(StandardCharsets.UTF_8),
                 Collections.emptySet());
 
-        // following assertion asserts that VersionedFlowSynchronizer is used
-        assertFalse(proposedDataFlow.isXml());
-
-        controller.synchronize(standardFlowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
+        controller.synchronize(flowSynchronizer, proposedDataFlow, mock(FlowService.class), BundleUpdateStrategy.IGNORE_BUNDLE);
 
         final Map<String, Integer> componentCounts = controller.getFlowManager().getComponentCounts();
 
@@ -1366,6 +1355,14 @@ public class TestFlowController {
     }
 
     private String getNewJsonFlow() throws JsonProcessingException {
+        final VersionedDataflow versionedDataflow = getVersionedDataflow();
+
+        final ObjectMapper mapper = new ObjectMapper();
+        final String jsonString = mapper.writeValueAsString(versionedDataflow);
+        return jsonString;
+    }
+
+    private static VersionedDataflow getVersionedDataflow() {
         final VersionedDataflow versionedDataflow = new VersionedDataflow();
 
         versionedDataflow.setEncodingVersion(new VersionedFlowEncodingVersion(2, 0));
@@ -1398,10 +1395,6 @@ public class TestFlowController {
         rootGroup.setFlowFileConcurrency("UNBOUNDED");
         rootGroup.setComponentType(ComponentType.PROCESS_GROUP);
         versionedDataflow.setRootGroup(rootGroup);
-
-        final ObjectMapper mapper = new ObjectMapper();
-
-        final String jsonString = mapper.writeValueAsString(versionedDataflow);
-        return jsonString;
+        return versionedDataflow;
     }
 }
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/StandardFlowSerializerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/StandardFlowSerializerTest.java
deleted file mode 100644
index 79c3793c77..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/StandardFlowSerializerTest.java
+++ /dev/null
@@ -1,169 +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.controller.serialization;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.nifi.admin.service.AuditService;
-import org.apache.nifi.authorization.AbstractPolicyBasedAuthorizer;
-import org.apache.nifi.authorization.MockPolicyBasedAuthorizer;
-import org.apache.nifi.bundle.Bundle;
-import org.apache.nifi.controller.DummyScheduledProcessor;
-import org.apache.nifi.controller.FlowController;
-import org.apache.nifi.controller.ProcessorNode;
-import org.apache.nifi.controller.repository.FlowFileEventRepository;
-import org.apache.nifi.controller.status.history.StatusHistoryRepository;
-import org.apache.nifi.encrypt.PropertyEncryptor;
-import org.apache.nifi.nar.ExtensionDiscoveringManager;
-import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
-import org.apache.nifi.nar.SystemBundle;
-import org.apache.nifi.parameter.Parameter;
-import org.apache.nifi.parameter.ParameterContext;
-import org.apache.nifi.parameter.ParameterDescriptor;
-import org.apache.nifi.parameter.ParameterReferenceManager;
-import org.apache.nifi.parameter.StandardParameterContext;
-import org.apache.nifi.provenance.MockProvenanceRepository;
... 10653 lines suppressed ...