pauloricardomg commented on code in PR #369:
URL: https://github.com/apache/cassandra-sidecar/pull/369#discussion_r3574422865


##########
server/src/main/java/org/apache/cassandra/sidecar/configmanagement/ConfigurationPatchApplier.java:
##########
@@ -0,0 +1,491 @@
+/*
+ * 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.cassandra.sidecar.configmanagement;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import io.vertx.core.json.JsonObject;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static 
org.apache.cassandra.sidecar.configmanagement.ConfigurationPatchValidator.CASSANDRA_YAML_SECTION;
+import static 
org.apache.cassandra.sidecar.configmanagement.ConfigurationPatchValidator.EXTRA_JVM_OPTS_SECTION;
+
+/**
+ * Applies validated patch operations to the configuration overlay.
+ *
+ * <p>Paths reference the effective configuration (base + overlay merged),
+ * but mutations target the overlay only. For nested paths within a top-level 
{@code cassandraYaml} key,
+ * the entire top-level key value is copied from the effective config into the 
overlay before applying
+ * the leaf change (copy-siblings strategy).
+ *
+ * <p>All precondition checks are performed before any mutations, ensuring 
atomicity:
+ * either all operations succeed or none are applied.
+ */
+public final class ConfigurationPatchApplier
+{
+    private ConfigurationPatchApplier()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Applies a list of validated patch operations and returns the updated 
overlay.
+     *
+     * @param parsedOps       the validated and parsed operations
+     * @param effectiveConfig the current effective configuration (base + 
overlay merged)
+     * @param currentOverlay  the current overlay (may be empty)
+     * @return the updated overlay with all operations applied
+     * @throws ConfigurationPatchException if any precondition check fails
+     */
+    @NotNull
+    public static CassandraConfigurationOverlay apply(
+            @NotNull List<ConfigurationPatchValidator.ParsedPatchOperation> 
parsedOps,
+            @NotNull CassandraConfigurationOverlay effectiveConfig,
+            @NotNull CassandraConfigurationOverlay currentOverlay)
+    {
+        // Phase 1: Precondition checks (no mutations)
+        for (ConfigurationPatchValidator.ParsedPatchOperation parsed : 
parsedOps)
+        {
+            checkPreconditions(parsed, effectiveConfig, currentOverlay);
+        }
+
+        // Phase 1b: Reject patches that would leave conflicting boolean JVM 
options in the
+        // effective configuration (e.g. adding -XX:-UseG1GC while the base 
already sets -XX:+UseG1GC).
+        // Checking against the effective opts, rather than the overlay alone, 
ensures the stored
+        // overlay and the returned effective configuration stay consistent.
+        checkResultingJvmOptConflicts(parsedOps, 
effectiveConfig.extraJvmOpts());
+
+        // Phase 2: Apply mutations
+        JsonObject updatedYaml = currentOverlay.cassandraYaml().copy();
+        Map<String, String> updatedOpts = new 
LinkedHashMap<>(currentOverlay.extraJvmOpts());
+
+        for (ConfigurationPatchValidator.ParsedPatchOperation parsed : 
parsedOps)
+        {
+            applyMutation(parsed, effectiveConfig, updatedYaml, updatedOpts);
+        }
+
+        return new CassandraConfigurationOverlay(updatedYaml, updatedOpts);
+    }
+
+    private static void 
checkPreconditions(ConfigurationPatchValidator.ParsedPatchOperation parsed,
+                                           CassandraConfigurationOverlay 
effectiveConfig,
+                                           CassandraConfigurationOverlay 
currentOverlay)
+    {
+        if (parsed.section().equals(CASSANDRA_YAML_SECTION))
+        {
+            checkYamlPreconditions(parsed, effectiveConfig.cassandraYaml(), 
currentOverlay.cassandraYaml());
+        }
+        else if (parsed.section().equals(EXTRA_JVM_OPTS_SECTION))
+        {
+            checkJvmOptsPreconditions(parsed, effectiveConfig.extraJvmOpts(), 
currentOverlay.extraJvmOpts());
+        }
+    }
+
+    private static void 
checkYamlPreconditions(ConfigurationPatchValidator.ParsedPatchOperation parsed,
+                                               JsonObject effectiveYaml,
+                                               JsonObject overlayYaml)
+    {
+        ConfigurationPatchOperation op = parsed.operation();
+
+        switch (op.op())
+        {
+            case TEST:
+                checkNestedPathTraversable(effectiveYaml, parsed);
+                Object actualValue = resolveValue(effectiveYaml, 
parsed.topLevelKey(), parsed.nestedSegments());
+                if (actualValue == null)
+                {
+                    throw new ConfigurationPatchException(
+                            "Test failed: path does not exist in effective 
config: '" + op.path() + "'", op);
+                }
+                // Both sides are Vert.x JSON types: resolveValue returns 
JsonObject/JsonArray/scalars,
+                // and op.value() is read from the request via 
JsonObject.getValue (see
+                // ConfigurationPatchHandler), which wraps objects/arrays the 
same way.

Review Comment:
   This will come in upcoming PR for 
[CASSSIDECAR-436](https://issues.apache.org/jira/browse/CASSSIDECAR-436): 
https://github.com/pauloricardomg/cassandra-sidecar/pull/7
   
   I updated the comment to remove this reference on 38b8780



-- 
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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to