diff --git a/src/main/java/org/apache/nifi/components/connector/Connector.java b/src/main/java/org/apache/nifi/components/connector/Connector.java index 36d2998..c1f696a 100644 --- a/src/main/java/org/apache/nifi/components/connector/Connector.java +++ b/src/main/java/org/apache/nifi/components/connector/Connector.java @@ -22,6 +22,7 @@ import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.connector.components.FlowContext; import org.apache.nifi.flow.VersionedExternalFlow; +import org.apache.nifi.migration.ConnectorPropertyConfiguration; import java.util.List; import java.util.Map; @@ -245,4 +246,21 @@ public interface Connector { * @return a Future that will be completed when the draining is complete */ CompletableFuture drainFlowFiles(FlowContext flowContext); + + /** + * Migrates an old property configuration to a new one, allowing properties and {@link ConfigurationStep}s to be + * renamed, removed, or added while preserving values. Invoked whenever the Connector is restored from a previous + * configuration (e.g., on restart) for the active and working configurations independently. + * + *

+ * Distinct from + * {@link org.apache.nifi.components.connector.migration.MigratableConnector#migrateConfiguration(org.apache.nifi.components.connector.migration.ConnectorMigrationContext)}, + * which copies configuration from a separate source flow; this method evolves the persisted names of the + * Connector's own configuration. + *

+ * + * @param config the current property configuration, scoped per configuration step + */ + default void migrateProperties(ConnectorPropertyConfiguration config) { + } } diff --git a/src/main/java/org/apache/nifi/migration/ConnectorPropertyConfiguration.java b/src/main/java/org/apache/nifi/migration/ConnectorPropertyConfiguration.java new file mode 100644 index 0000000..db7720b --- /dev/null +++ b/src/main/java/org/apache/nifi/migration/ConnectorPropertyConfiguration.java @@ -0,0 +1,80 @@ +/* + * 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.migration; + +import org.apache.nifi.components.connector.ConfigurationStep; + +import java.util.Set; + +/** + * Entry point for a {@link org.apache.nifi.components.connector.Connector} to migrate its persisted property + * configuration on restore. Because a Connector's properties are organized into named {@link ConfigurationStep}s, + * migration is scoped per step: this interface exposes step-level operations directly and yields a + * {@link ConnectorStepPropertyConfiguration} for per-step property changes via {@link #forStep(String)}. + * + *

+ * Implementation Note: This API is experimental and subject to change between minor releases. + *

+ */ +public interface ConnectorPropertyConfiguration { + + /** + * @return the names of all configuration steps currently known to this configuration + */ + Set getStepNames(); + + /** + * @param stepName the name of the configuration step + * @return true if this configuration contains the given step + */ + boolean hasStep(String stepName); + + /** + * Renames an existing configuration step, preserving all of its properties and their underlying value references. + * + * @param oldStepName the current step name + * @param newStepName the new step name + * @return true if the step was renamed; false if no step exists with {@code oldStepName} + * @throws IllegalStateException if a step already exists with {@code newStepName} + */ + boolean renameStep(String oldStepName, String newStepName); + + /** + * Removes the configuration step with the given name and all of its properties, if it exists. + * + * @param stepName the name of the step to remove + * @return true if the step was removed; false if the step did not exist + */ + boolean removeStep(String stepName); + + /** + * Returns a step-scoped view of this configuration. The view is usable even when no step currently exists with the + * given name; the step is registered on the first property write. Retrieval alone does not register a step. + * + * @param stepName the name of the configuration step + * @return a step-scoped configuration view + */ + ConnectorStepPropertyConfiguration forStep(String stepName); + + /** + * Convenience overload of {@link #forStep(String)} accepting a {@link ConfigurationStep}. + */ + default ConnectorStepPropertyConfiguration forStep(final ConfigurationStep step) { + return forStep(step.getName()); + } +} diff --git a/src/main/java/org/apache/nifi/migration/ConnectorStepPropertyConfiguration.java b/src/main/java/org/apache/nifi/migration/ConnectorStepPropertyConfiguration.java new file mode 100644 index 0000000..f2f1bee --- /dev/null +++ b/src/main/java/org/apache/nifi/migration/ConnectorStepPropertyConfiguration.java @@ -0,0 +1,153 @@ +/* + * 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.migration; + +import org.apache.nifi.components.connector.ConnectorPropertyDescriptor; +import org.apache.nifi.components.connector.ConnectorValueReference; + +import java.util.Map; +import java.util.Optional; + +/** + * Step-scoped view of a {@link ConnectorPropertyConfiguration}. All operations apply to the step returned by + * {@link #getStepName()}. Rename operations preserve the underlying {@link ConnectorValueReference} subtype (e.g. a + * {@link org.apache.nifi.components.connector.SecretReference} stays a + * {@link org.apache.nifi.components.connector.SecretReference}); use + * {@link #setValueReference(String, ConnectorValueReference)} to change the subtype. + * + *

+ * Implementation Note: This API is experimental and subject to change between minor releases. + *

+ */ +public interface ConnectorStepPropertyConfiguration { + + /** + * @return the name of the configuration step this view is scoped to + */ + String getStepName(); + + /** + * Renames an existing property, preserving its underlying {@link ConnectorValueReference}. + * + * @param propertyName the current property name + * @param newName the new property name + * @return true if the property was renamed; false if it did not exist + */ + boolean renameProperty(String propertyName, String newName); + + /** + * Removes the property with the given name, if it exists. No-op otherwise. + * + * @param propertyName the property name + * @return true if the property was removed; false if it did not exist + */ + boolean removeProperty(String propertyName); + + /** + * @param propertyName the property name + * @return true if this step has an entry for the property, including when its value reference is null + */ + boolean hasProperty(String propertyName); + + /** + * @param propertyName the property name + * @return true if the property is set to a non-null value + */ + boolean isPropertySet(String propertyName); + + /** + * Convenience for {@code setValueReference(propertyName, new StringLiteralValue(propertyValue))}. + */ + void setProperty(String propertyName, String propertyValue); + + /** + * Sets the given property to the given {@link ConnectorValueReference}, or removes it when {@code valueReference} + * is null. + */ + void setValueReference(String propertyName, ConnectorValueReference valueReference); + + /** + * Returns the string value when the underlying reference is a + * {@link org.apache.nifi.components.connector.StringLiteralValue}. Empty when the property is absent, its + * {@link org.apache.nifi.components.connector.StringLiteralValue} carries a null value, or the reference is a + * different subtype (e.g. {@link org.apache.nifi.components.connector.AssetReference} or + * {@link org.apache.nifi.components.connector.SecretReference}); use {@link #getValueReference(String)} for the + * typed view. + */ + Optional getPropertyValue(String propertyName); + + /** + * @return the underlying {@link ConnectorValueReference} regardless of subtype, or empty when the property is + * absent or the reference is null + */ + Optional getValueReference(String propertyName); + + /** + * @return the string-literal properties in this step; properties whose values are of other subtypes are omitted + * (use {@link #getValueReferences()} for the full typed view) + */ + Map getProperties(); + + /** + * @return every property in this step keyed by name, exposing the underlying {@link ConnectorValueReference} + */ + Map getValueReferences(); + + /** + * Convenience overload of {@link #hasProperty(String)} accepting a {@link ConnectorPropertyDescriptor}. + */ + default boolean hasProperty(final ConnectorPropertyDescriptor descriptor) { + return hasProperty(descriptor.getName()); + } + + /** + * Convenience overload of {@link #isPropertySet(String)} accepting a {@link ConnectorPropertyDescriptor}. + */ + default boolean isPropertySet(final ConnectorPropertyDescriptor descriptor) { + return isPropertySet(descriptor.getName()); + } + + /** + * Convenience overload of {@link #setProperty(String, String)} accepting a {@link ConnectorPropertyDescriptor}. + */ + default void setProperty(final ConnectorPropertyDescriptor descriptor, final String propertyValue) { + setProperty(descriptor.getName(), propertyValue); + } + + /** + * Convenience overload of {@link #setValueReference(String, ConnectorValueReference)} accepting a + * {@link ConnectorPropertyDescriptor}. + */ + default void setValueReference(final ConnectorPropertyDescriptor descriptor, final ConnectorValueReference valueReference) { + setValueReference(descriptor.getName(), valueReference); + } + + /** + * Convenience overload of {@link #getPropertyValue(String)} accepting a {@link ConnectorPropertyDescriptor}. + */ + default Optional getPropertyValue(final ConnectorPropertyDescriptor descriptor) { + return getPropertyValue(descriptor.getName()); + } + + /** + * Convenience overload of {@link #getValueReference(String)} accepting a {@link ConnectorPropertyDescriptor}. + */ + default Optional getValueReference(final ConnectorPropertyDescriptor descriptor) { + return getValueReference(descriptor.getName()); + } +}