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;
}