This is an automated email from the ASF dual-hosted git repository. markap14 pushed a commit to branch NIFI-15258 in repository https://gitbox.apache.org/repos/asf/nifi-api.git
commit 7d13e70144afe71452374901d6b1167b8c3a0486 Author: Mark Payne <[email protected]> AuthorDate: Tue Jan 27 09:03:52 2026 -0500 NIFI-15467: Allow Connectors to specify bundle compatability when upd… (#54) * NIFI-15467: Allow Connectors to specify bundle compatability when updating flow * NIFI-15467: Have ComponentBundleLookup return Optional<Bundle> from getLatestBundle instead of a nullable Bundle --- .../components/connector/BundleCompatibility.java | 47 ++++++++++++++++++++++ .../connector/ComponentBundleLookup.java | 36 +++++++++++++++++ .../connector/ConnectorInitializationContext.java | 28 ++++++++++++- ...ocumentationConnectorInitializationContext.java | 18 ++++++++- 4 files changed, 125 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/apache/nifi/components/connector/BundleCompatibility.java b/src/main/java/org/apache/nifi/components/connector/BundleCompatibility.java new file mode 100644 index 0000000..b17eb38 --- /dev/null +++ b/src/main/java/org/apache/nifi/components/connector/BundleCompatibility.java @@ -0,0 +1,47 @@ +/* + * 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.components.connector; + +/** + * Specifies how bundle resolution should be handled when updating a flow with components + * whose specified bundles may not be available in the NiFi instance. + */ +public enum BundleCompatibility { + + /** + * Requires the exact bundle specified in the flow. If the bundle is not available, + * a ghosted component will be created. This is the default behavior. + */ + REQUIRE_EXACT_BUNDLE, + + /** + * If the specified bundle is not available, checks what bundles are available for + * the given component type. If exactly one bundle is available, resolves to that bundle. + * If no bundles or multiple bundles are available, uses the specified bundle and + * creates a ghosted component. + */ + RESOLVE_BUNDLE, + + /** + * If the specified bundle is not available, checks what bundles are available for + * the given component type. If no bundles are available, uses the specified bundle + * and creates a ghosted component. Otherwise, uses the newest available bundle + * based on version comparison. + */ + RESOLVE_NEWEST_BUNDLE +} diff --git a/src/main/java/org/apache/nifi/components/connector/ComponentBundleLookup.java b/src/main/java/org/apache/nifi/components/connector/ComponentBundleLookup.java index 7abe996..84cba63 100644 --- a/src/main/java/org/apache/nifi/components/connector/ComponentBundleLookup.java +++ b/src/main/java/org/apache/nifi/components/connector/ComponentBundleLookup.java @@ -20,6 +20,7 @@ package org.apache.nifi.components.connector; import org.apache.nifi.flow.Bundle; import java.util.List; +import java.util.Optional; public interface ComponentBundleLookup { @@ -30,4 +31,39 @@ public interface ComponentBundleLookup { */ List<Bundle> getAvailableBundles(String componentType); + /** + * Determines the latest bundle available for the given component type based on version comparison. + * + * <p>Version comparison follows these rules:</p> + * <ol> + * <li>Versions are split by dots (e.g., "2.1.0" becomes ["2", "1", "0"]). + * This also supports calendar-date formats (e.g., "2026.01.01").</li> + * <li>Each part is compared numerically when possible; numeric parts are considered + * newer than non-numeric parts (e.g., "2.0.0" > "2.0.next")</li> + * <li>When base versions are equal, qualifiers are compared with the following precedence + * (highest to lowest): + * <ul> + * <li>Release (no qualifier)</li> + * <li>RC (Release Candidate) - e.g., "-RC1", "-RC2"</li> + * <li>M (Milestone) - e.g., "-M1", "-M2"</li> + * <li>Other/unknown qualifiers</li> + * <li>SNAPSHOT</li> + * </ul> + * </li> + * <li>Within the same qualifier type, numeric suffixes are compared + * (e.g., "2.0.0-RC2" > "2.0.0-RC1", "2.0.0-M4" > "2.0.0-M1")</li> + * </ol> + * + * <p>Examples of version ordering (highest to lowest):</p> + * <ul> + * <li>3.0.0 > 2.1.0 > 2.0.0 > 2.0.0-RC2 > 2.0.0-RC1 > 2.0.0-M4 > 2.0.0-M1 > 2.0.0-SNAPSHOT</li> + * <li>2.1.0-SNAPSHOT > 2.0.0 (higher base version wins)</li> + * <li>2026.01.01 > 2025.12.31 (calendar-date format)</li> + * </ul> + * + * @param componentType the component type + * @return an Optional containing the latest available bundle, or empty if no bundles are available + */ + Optional<Bundle> getLatestBundle(String componentType); + } diff --git a/src/main/java/org/apache/nifi/components/connector/ConnectorInitializationContext.java b/src/main/java/org/apache/nifi/components/connector/ConnectorInitializationContext.java index 88880f9..fa422b4 100644 --- a/src/main/java/org/apache/nifi/components/connector/ConnectorInitializationContext.java +++ b/src/main/java/org/apache/nifi/components/connector/ConnectorInitializationContext.java @@ -70,7 +70,6 @@ public interface ConnectorInitializationContext { * <li>Restarting all components</li> * </ul> * - * * <p> * Depending on the changes required in order to update the flow to the provided VersionedProcessGroup, this * could also result in stopping source processors and waiting for queues to drain, etc. @@ -82,9 +81,34 @@ public interface ConnectorInitializationContext { * be started. * </p> * + * <p> + * This method uses the Bundle Compatability strategy of {@link BundleCompatibility#RESOLVE_BUNDLE}. + * </p> + * + * @param flowContext the context of the flow to be updated + * @param versionedExternalFlow the new representation of the flow + */ + default void updateFlow(FlowContext flowContext, VersionedExternalFlow versionedExternalFlow) throws FlowUpdateException { + updateFlow(flowContext, versionedExternalFlow, BundleCompatibility.RESOLVE_BUNDLE); + } + + /** + * <p> + * Updates the Connector's flow to the given VersionedExternalFlow with the specified bundle compatibility strategy. + * This method behaves like {@link #updateFlow(FlowContext, VersionedExternalFlow)} but allows control over how + * component bundles are resolved when the specified bundle is not available. + * </p> + * + * <p> + * Note that if Bundle Compatability is not set to {@link BundleCompatibility#REQUIRE_EXACT_BUNDLE}, this method may update the provided + * VersionedExternalFlow to represent the actual bundles used during the update. + * </p> + * * @param flowContext the context of the flow to be updated * @param versionedExternalFlow the new representation of the flow + * @param bundleCompatability the strategy to use when resolving component bundles + * @throws FlowUpdateException if the flow update fails */ - void updateFlow(FlowContext flowContext, VersionedExternalFlow versionedExternalFlow) throws FlowUpdateException; + void updateFlow(FlowContext flowContext, VersionedExternalFlow versionedExternalFlow, BundleCompatibility bundleCompatability) throws FlowUpdateException; } diff --git a/src/main/java/org/apache/nifi/documentation/init/DocumentationConnectorInitializationContext.java b/src/main/java/org/apache/nifi/documentation/init/DocumentationConnectorInitializationContext.java index 75bc7e0..1eeb802 100644 --- a/src/main/java/org/apache/nifi/documentation/init/DocumentationConnectorInitializationContext.java +++ b/src/main/java/org/apache/nifi/documentation/init/DocumentationConnectorInitializationContext.java @@ -16,14 +16,17 @@ */ package org.apache.nifi.documentation.init; +import org.apache.nifi.components.connector.BundleCompatibility; import org.apache.nifi.components.connector.ComponentBundleLookup; 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.Bundle; import org.apache.nifi.flow.VersionedExternalFlow; import org.apache.nifi.logging.ComponentLog; import java.util.List; +import java.util.Optional; import java.util.UUID; /** @@ -51,11 +54,22 @@ public class DocumentationConnectorInitializationContext implements ConnectorIni @Override public ComponentBundleLookup getComponentBundleLookup() { - return componentType -> List.of(); + return new ComponentBundleLookup() { + @Override + public List<Bundle> getAvailableBundles(final String componentType) { + return List.of(); + } + + @Override + public Optional<Bundle> getLatestBundle(final String componentType) { + return Optional.empty(); + } + }; } @Override - public void updateFlow(final FlowContext flowContext, final VersionedExternalFlow versionedExternalFlow) throws FlowUpdateException { + public void updateFlow(final FlowContext flowContext, final VersionedExternalFlow versionedExternalFlow, + final BundleCompatibility bundleCompatability) throws FlowUpdateException { // No-op for documentation purposes - we don't actually update any flows } }
