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

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


The following commit(s) were added to refs/heads/main by this push:
     new f1e677a  NIFI-15988: Split MigratableConnector's migrate method into 
two methods: migrateConfiguration, migrateState (#92)
f1e677a is described below

commit f1e677a492697e3aaf34b6cc42866fc2d5097d7e
Author: Mark Payne <[email protected]>
AuthorDate: Tue Jun 2 13:10:24 2026 -0400

    NIFI-15988: Split MigratableConnector's migrate method into two methods: 
migrateConfiguration, migrateState (#92)
    
    Signed-off-by: Kevin Doran <[email protected]>
---
 .../migration/ConnectorMigrationContext.java       | 56 ++++++++++++-
 .../connector/migration/MigratableConnector.java   | 93 ++++++++++------------
 2 files changed, 94 insertions(+), 55 deletions(-)

diff --git 
a/src/main/java/org/apache/nifi/components/connector/migration/ConnectorMigrationContext.java
 
b/src/main/java/org/apache/nifi/components/connector/migration/ConnectorMigrationContext.java
index e3ae61e..1594d27 100644
--- 
a/src/main/java/org/apache/nifi/components/connector/migration/ConnectorMigrationContext.java
+++ 
b/src/main/java/org/apache/nifi/components/connector/migration/ConnectorMigrationContext.java
@@ -18,13 +18,29 @@
 package org.apache.nifi.components.connector.migration;
 
 import org.apache.nifi.components.connector.AssetReference;
+import org.apache.nifi.components.connector.ConfigurationStep;
+import org.apache.nifi.components.connector.ConnectorInitializationContext;
 import org.apache.nifi.components.connector.components.FlowContext;
+import org.apache.nifi.flow.VersionedComponentState;
 import org.apache.nifi.flow.VersionedExternalFlow;
 
+import java.util.Map;
+
 /**
- * Context provided to a Connector when evaluating or performing migration 
from a Versioned Process Group export. The
- * source flow exposed through this context is a read-only reference that the 
Connector uses to update its own managed
- * flow; the source flow itself is never installed onto the Connector.
+ * Migration context for a {@link MigratableConnector}.
+ *
+ * <p>
+ * The source flow is read-only and is never installed directly. Write methods 
are phase-scoped:
+ * {@link #setProperties(String, Map)} and {@link #replaceProperties(String, 
Map)} are valid only during
+ * {@link 
MigratableConnector#migrateConfiguration(ConnectorMigrationContext)}, and
+ * {@link #setComponentState(String, VersionedComponentState)} is valid only 
during
+ * {@link MigratableConnector#migrateState(ConnectorMigrationContext)}.
+ * </p>
+ *
+ * <p>
+ * Calling {@link ConnectorInitializationContext#updateFlow(FlowContext, 
VersionedExternalFlow) updateFlow(...)}
+ * through this context throws.
+ * </p>
  */
 public interface ConnectorMigrationContext {
 
@@ -45,8 +61,9 @@ public interface ConnectorMigrationContext {
 
     /**
      * Returns the active flow context for the Connector being migrated.
+     * Calling {@code updateFlow(...)} through this context throws.
      *
-     * @return the active flow context
+     * @return active flow context
      */
     FlowContext getActiveFlowContext();
 
@@ -72,4 +89,35 @@ public interface ConnectorMigrationContext {
      *                               available when the migration source is a 
local Versioned Process Group
      */
     AssetReference copyAssetFromSource(String sourceAssetId);
+
+    /**
+     * Records configuration properties to merge into the named {@link 
ConfigurationStep}.
+     * A {@code null} value removes the property.
+     *
+     * @param stepName configuration step name
+     * @param propertyValues properties to record
+     * @throws IllegalStateException when called outside {@code 
migrateConfiguration(...)}
+     */
+    void setProperties(String stepName, Map<String, String> propertyValues);
+
+    /**
+     * Records configuration properties that replace the named {@link 
ConfigurationStep}.
+     * Properties not included in {@code propertyValues} are removed.
+     *
+     * @param stepName configuration step name
+     * @param propertyValues properties to record
+     * @throws IllegalStateException when called outside {@code 
migrateConfiguration(...)}
+     */
+    void replaceProperties(String stepName, Map<String, String> 
propertyValues);
+
+    /**
+     * Records the {@link VersionedComponentState} for a managed component.
+     * Repeated calls for the same component replace prior recorded state; an 
empty state clears previously recorded state.
+     *
+     * @param managedComponentId managed Processor or Controller Service 
versioned identifier
+     * @param state state to write
+     * @throws IllegalArgumentException when {@code managedComponentId} is 
blank or {@code state} is {@code null}
+     * @throws IllegalStateException when called outside {@code 
migrateState(...)}
+     */
+    void setComponentState(String managedComponentId, VersionedComponentState 
state);
 }
diff --git 
a/src/main/java/org/apache/nifi/components/connector/migration/MigratableConnector.java
 
b/src/main/java/org/apache/nifi/components/connector/migration/MigratableConnector.java
index 4dcdbd8..e5d8463 100644
--- 
a/src/main/java/org/apache/nifi/components/connector/migration/MigratableConnector.java
+++ 
b/src/main/java/org/apache/nifi/components/connector/migration/MigratableConnector.java
@@ -21,72 +21,63 @@ import org.apache.nifi.components.connector.Connector;
 import org.apache.nifi.components.connector.ConnectorInitializationContext;
 import org.apache.nifi.components.connector.FlowUpdateException;
 import org.apache.nifi.components.connector.components.FlowContext;
-import org.apache.nifi.flow.VersionedExternalFlow;
+import org.apache.nifi.flow.VersionedComponentState;
 
 /**
+ * Optional {@link Connector} capability for migration from a source flow.
+ *
+ * <p>
+ * Migration runs in two phases:
+ * </p>
+ * <ol>
+ *     <li>{@link #migrateConfiguration(ConnectorMigrationContext)} records 
configuration changes and copied assets.</li>
+ *     <li>{@link #migrateState(ConnectorMigrationContext)} records component 
{@link VersionedComponentState}.</li>
+ * </ol>
+ *
  * <p>
- * An optional capability interface that may be implemented by a {@link 
Connector} to indicate that it supports
- * being populated from an existing source flow (for example, a Versioned 
Process Group already running on this
- * NiFi instance, or an uploaded flow definition). The framework discovers 
this capability by checking whether a
- * Connector is an instance of {@code MigratableConnector}; Connectors that do 
not implement this interface are
- * never offered as migration targets.
+ * Connectors must not call
+ * {@link ConnectorInitializationContext#updateFlow(FlowContext, 
org.apache.nifi.flow.VersionedExternalFlow)
+ * updateFlow(...)} during migration. The framework applies recorded 
configuration by calling
+ * {@link Connector#applyUpdate(FlowContext, FlowContext) applyUpdate(...)} 
between phases, then writes recorded
+ * state. If any phase fails, migration is rolled back.
  * </p>
  *
- * <b>Implementation Note:</b> This API is currently experimental, as it is 
under very active development. As such,
- * it is subject to change without notice between releases.
+ * <p>
+ * Sensitive values are not included in the source flow and must be configured 
by the user after migration.
+ * </p>
+ *
+ * <p>
+ * <b>Implementation Note:</b> This API is experimental and may change between 
releases.
+ * </p>
  */
 public interface MigratableConnector {
 
     /**
-     * Indicates whether this Connector can be migrated from the source flow 
described by the given context.
-     *
-     * <p>
-     * Implementations should inspect the source flow structure and metadata 
using
-     * {@link ConnectorMigrationContext#getSourceFlow()} and return quickly 
without mutating the Connector or the
-     * source flow. This method must not call {@link 
ConnectorMigrationContext#copyAssetFromSource(String)}.
-     * </p>
+     * Returns whether this Connector supports migration from the source flow 
in the given context.
+     * This method is read-only and must not call context write methods.
      *
-     * @param context the migration context describing the source flow and 
target Connector
-     * @return {@code true} when this Connector can be migrated from the 
provided source flow
+     * @param context migration context
+     * @return {@code true} when migration is supported
      */
     boolean isMigrationSupported(ConnectorMigrationContext context);
 
     /**
-     * Migrates this Connector by updating its own managed flow to mirror the 
configuration, parameters, and component
-     * state captured in the provided source flow. The source flow is a 
reference: it is read, not modified, and is not
-     * installed onto the Connector. The Connector remains the owner of its 
flow and is responsible for translating the
-     * source into its own representation.
-     *
-     * <p>
-     * The framework guarantees the following preconditions when this method 
is invoked:
-     * </p>
-     * <ul>
-     *     <li>The Connector is stopped.</li>
-     *     <li>The Connector has not had any configuration changes applied by 
the user and has not been started.</li>
-     * </ul>
-     *
-     * <p>
-     * Because of these preconditions, the implementation updates the active 
{@link FlowContext} directly rather than
-     * making use of {@code prepareForUpdate} and {@code applyUpdate}. Those 
two lifecycle methods exist to safely
-     * transition a running Connector from one active configuration to 
another; for migration, the Connector is
-     * already required to be in the target-safe state, so the 
working-to-active swap is unnecessary.
-     * </p>
+     * First migration phase. Record configuration changes using
+     * {@link ConnectorMigrationContext#setProperties(String, java.util.Map)} 
or
+     * {@link ConnectorMigrationContext#replaceProperties(String, 
java.util.Map)}, and copy assets as needed.
+     * The framework calls {@link Connector#applyUpdate(FlowContext, 
FlowContext)} after this method returns.
      *
-     * <p>
-     * Implementations are responsible for transforming the source flow, 
updating the active {@link FlowContext}, and
-     * applying any parameter or step configuration changes needed by the 
Connector. Sensitive parameter values are not
-     * present in the source flow and must be left for the user to configure 
after the migration completes.
-     * </p>
-     *
-     * <p>
-     * Connectors that extend {@code AbstractConnector} can typically retain 
their {@link ConnectorInitializationContext}
-     * from {@code initialize(ConnectorInitializationContext)} and call
-     * {@link ConnectorInitializationContext#updateFlow(FlowContext, 
VersionedExternalFlow)} using
-     * {@link ConnectorMigrationContext#getActiveFlowContext()}.
-     * </p>
+     * @param context migration context
+     * @throws FlowUpdateException when migration fails
+     */
+    void migrateConfiguration(ConnectorMigrationContext context) throws 
FlowUpdateException;
+
+    /**
+     * Second migration phase. This method is invoked after the framework 
rebuilds the managed flow from configuration.
+     * Record component state using {@link 
ConnectorMigrationContext#setComponentState(String, VersionedComponentState)}.
      *
-     * @param context the migration context describing the source flow and 
target Connector
-     * @throws FlowUpdateException when the migration cannot be completed 
successfully
+     * @param context migration context
+     * @throws FlowUpdateException when state migration fails
      */
-    void migrate(ConnectorMigrationContext context) throws FlowUpdateException;
+    void migrateState(ConnectorMigrationContext context) throws 
FlowUpdateException;
 }

Reply via email to