You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by "markap14 (via GitHub)" <gi...@apache.org> on 2026/10/22 23:52:48 UTC

[PR] NIFI-16493 Added patchState to StateManager and ProcessSession [nifi-api]

markap14 opened a new pull request, #112:
URL: https://github.com/apache/nifi-api/pull/112

   <!-- SPDX-License-Identifier: Apache-2.0 -->
   
   # Summary
   
   [NIFI-16493](https://issues.apache.org/jira/browse/NIFI-16493)
   
   Implements the API portion of [NIP-50](https://issues.apache.org/jira/browse/NIP-50) by adding `patchState(Map<String, String> updatedState, Scope scope)` to `StateManager` and `ProcessSession`. A key with a non-null value is created or overwritten, a key mapped to `null` is removed, and keys not in the map are left unchanged. An empty map does nothing and a `null` map is rejected.
   
   - `StateManager.patchState` has a default implementation that retrieves the current state, applies the changes, and calls `replace` until it succeeds.
   - `ProcessSession.patchState` has no default implementation, so that every session implementation passes the patch through to the framework instead of quietly turning it into a whole-map replacement. `ProcessSession` implementations outside of NiFi will need to add this method.
   - `NopStateManager` overrides the method, since its `getState` returns `null`.
   
   The framework changes are tracked in [NIFI-16494](https://issues.apache.org/jira/browse/NIFI-16494).
   
   # Tracking
   
   Please complete the following tracking steps prior to pull request creation.
   
   ### Issue Tracking
   
   - [x] [Apache NiFi Jira](https://issues.apache.org/jira/browse/NIFI) issue created
   
   ### Pull Request Tracking
   
   - [x] Pull Request title starts with Apache NiFi Jira issue number, such as `NIFI-00000`
   - [x] Pull Request commit message starts with Apache NiFi Jira issue number, as such `NIFI-00000`
   
   ### Pull Request Formatting
   
   - [x] Pull Request based on current revision of the `main` branch
   - [x] Pull Request refers to a feature branch with one commit containing changes
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16493 Added patchState to StateManager and ProcessSession [nifi-api]

Posted by "markap14 (via GitHub)" <gi...@apache.org>.
markap14 commented on code in PR #112:
URL: https://github.com/apache/nifi-api/pull/112#discussion_r4360416654


##########
src/main/java/org/apache/nifi/components/state/StateMap.java:
##########
@@ -48,4 +51,32 @@ public interface StateMap {
      * @return an immutable Map representation of all keys and values for the state of a component.
      */
     Map<String, String> toMap();
+
+    /**
+     * Returns an immutable Map of all keys and values for the state of a component, with the given patches applied. This StateMap is not changed.
+     * <p>
+     * Each key in the given patches with a non-null value is added or overwritten. Each key with a {@code null} value is removed.
+     * Keys that are not in the given patches keep their values from this StateMap.
+     * </p>
+     *
+     * @param patches a map of state keys to their new values. A key that is mapped to {@code null} is removed from the result. The map itself must not be {@code null}.
+     * @return an immutable Map of this state's keys and values with the given patches applied
+     */
+    default Map<String, String> toMap(final Map<String, String> patches) {

Review Comment:
   I actually considered many different options here. I don't like `getPatchedMap()` because I don't like using getters that do more than just return a value. Plus, `getPatchedMap()` sounds like it's going to return a `PatchedMap` rather than a `Map<String, String>`. The `toMap()` already exists to create a `Map<String, String>` so providing an override here that allows applying patches on top made sense to me. I could be convinced if you feel strongly though :) 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16493 Added patchState to StateManager and ProcessSession [nifi-api]

Posted by "exceptionfactory (via GitHub)" <gi...@apache.org>.
exceptionfactory commented on code in PR #112:
URL: https://github.com/apache/nifi-api/pull/112#discussion_r4360907994


##########
src/main/java/org/apache/nifi/components/state/StateMap.java:
##########
@@ -48,4 +51,32 @@ public interface StateMap {
      * @return an immutable Map representation of all keys and values for the state of a component.
      */
     Map<String, String> toMap();
+
+    /**
+     * Returns an immutable Map of all keys and values for the state of a component, with the given patches applied. This StateMap is not changed.
+     * <p>
+     * Each key in the given patches with a non-null value is added or overwritten. Each key with a {@code null} value is removed.
+     * Keys that are not in the given patches keep their values from this StateMap.
+     * </p>
+     *
+     * @param patches a map of state keys to their new values. A key that is mapped to {@code null} is removed from the result. The map itself must not be {@code null}.
+     * @return an immutable Map of this state's keys and values with the given patches applied
+     */
+    default Map<String, String> toMap(final Map<String, String> patches) {

Review Comment:
   Thanks for the reply, that's fair. With that background, keeping the existing naming sounds good



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16493 Added patchState to StateManager and ProcessSession [nifi-api]

Posted by "exceptionfactory (via GitHub)" <gi...@apache.org>.
exceptionfactory commented on code in PR #112:
URL: https://github.com/apache/nifi-api/pull/112#discussion_r4360157602


##########
src/test/java/org/apache/nifi/components/state/TestStateManager.java:
##########
@@ -0,0 +1,135 @@
+/*
+ * 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.state;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestStateManager {

Review Comment:
   The `public` modifier can be removed



##########
src/main/java/org/apache/nifi/components/state/StateMap.java:
##########
@@ -48,4 +51,32 @@ public interface StateMap {
      * @return an immutable Map representation of all keys and values for the state of a component.
      */
     Map<String, String> toMap();
+
+    /**
+     * Returns an immutable Map of all keys and values for the state of a component, with the given patches applied. This StateMap is not changed.
+     * <p>
+     * Each key in the given patches with a non-null value is added or overwritten. Each key with a {@code null} value is removed.
+     * Keys that are not in the given patches keep their values from this StateMap.
+     * </p>
+     *
+     * @param patches a map of state keys to their new values. A key that is mapped to {@code null} is removed from the result. The map itself must not be {@code null}.
+     * @return an immutable Map of this state's keys and values with the given patches applied
+     */
+    default Map<String, String> toMap(final Map<String, String> patches) {
+        Objects.requireNonNull(patches, "Patches required");
+        if (patches.isEmpty()) {
+            return toMap();
+        }
+
+        final Map<String, String> patchedValues = new HashMap<>(toMap());

Review Comment:
   Although not an absolute requirement, using `LinkedHashMap` here may be useful to ensure consistent output for some types of testing



##########
src/test/java/org/apache/nifi/components/state/TestStateManager.java:
##########
@@ -0,0 +1,135 @@
+/*
+ * 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.state;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestStateManager {
+
+    @Test
+    public void testPatchState() throws Exception {
+        final InMemoryStateManager stateManager = new InMemoryStateManager();
+
+        assertThrows(NullPointerException.class, () -> stateManager.patchState(null, Scope.LOCAL));
+        stateManager.patchState(Map.of(), Scope.LOCAL);
+        assertEquals(0, stateManager.replaceCount);
+        assertTrue(stateManager.getState(Scope.LOCAL).getStateVersion().isEmpty());
+
+        final Map<String, String> firstPatch = new HashMap<>();
+        firstPatch.put("a", "1");
+        firstPatch.put("b", null);
+        firstPatch.put("c", "");
+        stateManager.patchState(firstPatch, Scope.LOCAL);
+        final StateMap firstState = stateManager.getState(Scope.LOCAL);
+        assertEquals(Map.of("a", "1", "c", ""), firstState.toMap());
+        assertTrue(firstState.getStateVersion().isPresent());
+
+        final Map<String, String> secondPatch = new HashMap<>();
+        secondPatch.put("a", "2");
+        secondPatch.put("missing", null);
+        stateManager.patchState(secondPatch, Scope.LOCAL);
+        assertEquals(Map.of("a", "2", "c", ""), stateManager.getState(Scope.LOCAL).toMap());
+
+        final Map<String, String> thirdPatch = new HashMap<>();
+        thirdPatch.put("c", null);
+        stateManager.patchState(thirdPatch, Scope.LOCAL);
+        assertEquals(Map.of("a", "2"), stateManager.getState(Scope.LOCAL).toMap());
+        assertEquals(3, stateManager.replaceCount);

Review Comment:
   There are a number of repeated literals that should be moved to static final variables and reused across methods.



##########
src/test/java/org/apache/nifi/components/state/TestStateManager.java:
##########
@@ -0,0 +1,135 @@
+/*
+ * 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.state;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class TestStateManager {
+
+    @Test
+    public void testPatchState() throws Exception {

Review Comment:
   The `public` modifier can be removed from this method and all other methods



##########
src/main/java/org/apache/nifi/components/state/StateMap.java:
##########
@@ -48,4 +51,32 @@ public interface StateMap {
      * @return an immutable Map representation of all keys and values for the state of a component.
      */
     Map<String, String> toMap();
+
+    /**
+     * Returns an immutable Map of all keys and values for the state of a component, with the given patches applied. This StateMap is not changed.
+     * <p>
+     * Each key in the given patches with a non-null value is added or overwritten. Each key with a {@code null} value is removed.
+     * Keys that are not in the given patches keep their values from this StateMap.
+     * </p>
+     *
+     * @param patches a map of state keys to their new values. A key that is mapped to {@code null} is removed from the result. The map itself must not be {@code null}.
+     * @return an immutable Map of this state's keys and values with the given patches applied
+     */
+    default Map<String, String> toMap(final Map<String, String> patches) {

Review Comment:
   What do you think about naming this `getPatchedMap()` to make the behavior a little clearer? There is a symmetry with the existing `toMap()`, so open to options.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] NIFI-16493 Added patchState to StateManager and ProcessSession [nifi-api]

Posted by "markap14 (via GitHub)" <gi...@apache.org>.
markap14 commented on PR #112:
URL: https://github.com/apache/nifi-api/pull/112#issuecomment-6366925182

   [Claude Opus 5.5] Thanks for the review @exceptionfactory. I pushed 23ba1d9 to address the feedback: removed the `public` modifiers from `TestStateManager`, moved the repeated literals in `TestStateManager` into static final constants, and changed `StateMap.toMap(Map)` to copy into a `LinkedHashMap` so the output order is consistent. I left the naming question for `toMap(Map)` alone, since @markap14 replied on that thread; I'll leave that one for the two of you to decide.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@nifi.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org