You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by jh...@apache.org on 2026/05/01 02:23:12 UTC

(ozone) 02/02: Add ContainerStateManagerInvoker

This is an automated email from the ASF dual-hosted git repository.

Russole pushed a commit to branch HDDS-15053
in repository https://gitbox.apache.org/repos/asf/ozone.git

commit ff56ce6a01ece61b4faac178218ff34aa779a97c
Author: Russole <85...@gmail.com>
AuthorDate: Fri May 1 10:17:40 2026 +0800

    Add ContainerStateManagerInvoker
---
 .../hdds/scm/container/ContainerStateManager.java  |   5 +
 .../scm/container/ContainerStateManagerImpl.java   |   3 +-
 .../ha/invoker/ContainerStateManagerInvoker.java   | 328 +++++++++++++++++++++
 .../scm/ha/invoker/ScmInvokerCodeGenerator.java    | 218 ++++++++++++--
 4 files changed, 522 insertions(+), 32 deletions(-)

diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
index 9e31e21822b..fa282396a3e 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
@@ -28,6 +28,7 @@
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationType;
 import org.apache.hadoop.hdds.protocol.proto.SCMRatisProtocol.RequestType;
 import org.apache.hadoop.hdds.scm.ha.SCMHandler;
+import org.apache.hadoop.hdds.scm.ha.invoker.ScmInvokerCodeGenerator;
 import org.apache.hadoop.hdds.scm.metadata.Replicate;
 import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
 import org.apache.hadoop.hdds.utils.db.Table;
@@ -236,4 +237,8 @@ default RequestType getType() {
   @Replicate
   void updateContainerInfo(HddsProtos.ContainerInfoProto containerInfo)
       throws IOException;
+
+  static void main(String[] args) {
+    ScmInvokerCodeGenerator.generate(ContainerStateManager.class, true);
+  }
 }
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
index 7b50dfceb7b..80a9725fac9 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
@@ -58,6 +58,7 @@
 import org.apache.hadoop.hdds.scm.container.states.ContainerStateMap;
 import org.apache.hadoop.hdds.scm.ha.ExecutionUtil;
 import org.apache.hadoop.hdds.scm.ha.SCMRatisServer;
+import org.apache.hadoop.hdds.scm.ha.invoker.ContainerStateManagerInvoker;
 import org.apache.hadoop.hdds.scm.metadata.DBTransactionBuffer;
 import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
 import org.apache.hadoop.hdds.scm.pipeline.PipelineManager;
@@ -653,7 +654,7 @@ public ContainerStateManager build() throws IOException {
           conf, pipelineMgr, table, transactionBuffer,
           containerReplicaPendingOps);
 
-      return scmRatisServer.getProxyHandler(ContainerStateManager.class, csm);
+      return scmRatisServer.getProxyHandler(new ContainerStateManagerInvoker(csm, scmRatisServer));
     }
 
   }
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
new file mode 100644
index 00000000000..12cc3785d28
--- /dev/null
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
@@ -0,0 +1,328 @@
+/*
+ * 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.hadoop.hdds.scm.ha.invoker;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Set;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ContainerInfoProto;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleEvent;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationType;
+import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.container.ContainerInfo;
+import org.apache.hadoop.hdds.scm.container.ContainerReplica;
+import org.apache.hadoop.hdds.scm.container.ContainerStateManager;
+import org.apache.hadoop.hdds.scm.ha.SCMRatisResponse;
+import org.apache.hadoop.hdds.scm.ha.SCMRatisServer;
+import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.ozone.common.statemachine.InvalidStateTransitionException;
+import org.apache.ratis.protocol.Message;
+
+/** Code generated for {@link ContainerStateManager}.  Do not modify. */
+public class ContainerStateManagerInvoker extends ScmInvoker<ContainerStateManager> {
+  enum ReplicateMethod implements NameAndParameterTypes {
+    addContainer(new Class<?>[][] {
+        null,
+        new Class<?>[] {ContainerInfoProto.class}
+    }),
+    removeContainer(new Class<?>[][] {
+        null,
+        new Class<?>[] {HddsProtos.ContainerID.class}
+    }),
+    transitionDeletingOrDeletedToTargetState(new Class<?>[][] {
+        null,
+        null,
+        new Class<?>[] {HddsProtos.ContainerID.class, LifeCycleState.class}
+    }),
+    updateContainerInfo(new Class<?>[][] {
+        null,
+        new Class<?>[] {ContainerInfoProto.class}
+    }),
+    updateContainerStateWithSequenceId(new Class<?>[][] {
+        null,
+        null,
+        null,
+        new Class<?>[] {HddsProtos.ContainerID.class, LifeCycleEvent.class, Long.class}
+    });
+
+    private final Class<?>[][] parameterTypes;
+
+    ReplicateMethod(Class<?>[][] parameterTypes) {
+      this.parameterTypes = parameterTypes;
+    }
+
+    @Override
+    public Class<?>[] getParameterTypes(int numArgs) {
+      return parameterTypes[numArgs];
+    }
+  }
+
+  public ContainerStateManagerInvoker(ContainerStateManager impl, SCMRatisServer ratis) {
+    super(impl, ContainerStateManagerInvoker::newProxy, ratis);
+  }
+
+  @Override
+  public Class<ContainerStateManager> getApi() {
+    return ContainerStateManager.class;
+  }
+
+  static ContainerStateManager newProxy(ScmInvoker<ContainerStateManager> invoker) {
+    return new ContainerStateManager() {
+
+      @Override
+      public void addContainer(ContainerInfoProto arg0) throws IOException {
+        final Object[] args = {arg0};
+        invoker.invokeReplicateDirect(ReplicateMethod.addContainer, args);
+      }
+
+      @Override
+      public boolean contains(ContainerID arg0) {
+        return invoker.getImpl().contains(arg0);
+      }
+
+      @Override
+      public ContainerInfo getContainer(ContainerID arg0) {
+        return invoker.getImpl().getContainer(arg0);
+      }
+
+      @Override
+      public int getContainerCount(LifeCycleState arg0) {
+        return invoker.getImpl().getContainerCount(arg0);
+      }
+
+      @Override
+      public List<ContainerID> getContainerIDs(LifeCycleState arg0, ContainerID arg1, int arg2) {
+        return invoker.getImpl().getContainerIDs(arg0, arg1, arg2);
+      }
+
+      @Override
+      public List<ContainerInfo> getContainerInfos(ReplicationType arg0) {
+        return invoker.getImpl().getContainerInfos(arg0);
+      }
+
+      @Override
+      public List<ContainerInfo> getContainerInfos(LifeCycleState arg0) {
+        return invoker.getImpl().getContainerInfos(arg0);
+      }
+
+      @Override
+      public List<ContainerInfo> getContainerInfos(ContainerID arg0, int arg1) {
+        return invoker.getImpl().getContainerInfos(arg0, arg1);
+      }
+
+      @Override
+      public List<ContainerInfo> getContainerInfos(LifeCycleState arg0, ContainerID arg1, int arg2) {
+        return invoker.getImpl().getContainerInfos(arg0, arg1, arg2);
+      }
+
+      @Override
+      public Set<ContainerReplica> getContainerReplicas(ContainerID arg0) {
+        return invoker.getImpl().getContainerReplicas(arg0);
+      }
+
+      @Override
+      public ContainerInfo getMatchingContainer(long arg0, String arg1, PipelineID arg2, NavigableSet arg3) {
+        return invoker.getImpl().getMatchingContainer(arg0, arg1, arg2, arg3);
+      }
+
+      @Override
+      public void reinitialize(Table arg0) throws IOException {
+        invoker.getImpl().reinitialize(arg0);
+      }
+
+      @Override
+      public void removeContainer(HddsProtos.ContainerID arg0) throws IOException {
+        final Object[] args = {arg0};
+        invoker.invokeReplicateDirect(ReplicateMethod.removeContainer, args);
+      }
+
+      @Override
+      public void removeContainerReplica(ContainerReplica arg0) {
+        invoker.getImpl().removeContainerReplica(arg0);
+      }
+
+      @Override
+      public void transitionDeletingOrDeletedToTargetState(HddsProtos.ContainerID arg0, LifeCycleState arg1) throws
+          IOException {
+        final Object[] args = {arg0, arg1};
+        invoker.invokeReplicateDirect(ReplicateMethod.transitionDeletingOrDeletedToTargetState, args);
+      }
+
+      @Override
+      public void updateContainerInfo(ContainerInfoProto arg0) throws IOException {
+        final Object[] args = {arg0};
+        invoker.invokeReplicateDirect(ReplicateMethod.updateContainerInfo, args);
+      }
+
+      @Override
+      public void updateContainerReplica(ContainerReplica arg0) {
+        invoker.getImpl().updateContainerReplica(arg0);
+      }
+
+      @Override
+      public void updateContainerStateWithSequenceId(HddsProtos.ContainerID arg0, LifeCycleEvent arg1, Long arg2) throws
+          IOException, InvalidStateTransitionException {
+        final Object[] args = {arg0, arg1, arg2};
+        invoker.invokeReplicateDirect(ReplicateMethod.updateContainerStateWithSequenceId, args);
+      }
+
+      @Override
+      public void updateDeleteTransactionId(Map arg0) throws IOException {
+        invoker.getImpl().updateDeleteTransactionId(arg0);
+      }
+    };
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Message invokeLocal(String methodName, Object[] p) throws Exception {
+    final Class<?> returnType;
+    final Object returnValue;
+    switch (methodName) {
+    case "addContainer":
+      final ContainerInfoProto arg0 = p.length > 0 ? (ContainerInfoProto) p[0] : null;
+      getImpl().addContainer(arg0);
+      return Message.EMPTY;
+
+    case "contains":
+      final ContainerID arg1 = p.length > 0 ? (ContainerID) p[0] : null;
+      returnType = boolean.class;
+      returnValue = getImpl().contains(arg1);
+      break;
+
+    case "getContainer":
+      final ContainerID arg2 = p.length > 0 ? (ContainerID) p[0] : null;
+      returnType = ContainerInfo.class;
+      returnValue = getImpl().getContainer(arg2);
+      break;
+
+    case "getContainerCount":
+      final LifeCycleState arg3 = p.length > 0 ? (LifeCycleState) p[0] : null;
+      returnType = int.class;
+      returnValue = getImpl().getContainerCount(arg3);
+      break;
+
+    case "getContainerIDs":
+      final LifeCycleState arg4 = p.length > 0 ? (LifeCycleState) p[0] : null;
+      final ContainerID arg5 = p.length > 1 ? (ContainerID) p[1] : null;
+      final int arg6 = p.length > 2 ? (int) p[2] : 0;
+      returnType = List.class;
+      returnValue = getImpl().getContainerIDs(arg4, arg5, arg6);
+      break;
+
+    case "getContainerInfos":
+      if (p.length == 1 && (p[0] == null || ReplicationType.class.isInstance(p[0]))) {
+        final ReplicationType arg7 = (ReplicationType) p[0];
+        returnType = List.class;
+        returnValue = getImpl().getContainerInfos(arg7);
+        break;
+      }
+      if (p.length == 1 && (p[0] == null || LifeCycleState.class.isInstance(p[0]))) {
+        final LifeCycleState arg8 = (LifeCycleState) p[0];
+        returnType = List.class;
+        returnValue = getImpl().getContainerInfos(arg8);
+        break;
+      }
+      if (p.length == 2 && (p[0] == null || ContainerID.class.isInstance(p[0])) && p[1] instanceof Integer) {
+        final ContainerID arg9 = (ContainerID) p[0];
+        final int arg10 = (int) p[1];
+        returnType = List.class;
+        returnValue = getImpl().getContainerInfos(arg9, arg10);
+        break;
+      }
+      if (p.length == 3 && (p[0] == null || LifeCycleState.class.isInstance(p[0])) && (p[1] == null ||
+          ContainerID.class.isInstance(p[1])) && p[2] instanceof Integer) {
+        final LifeCycleState arg11 = (LifeCycleState) p[0];
+        final ContainerID arg12 = (ContainerID) p[1];
+        final int arg13 = (int) p[2];
+        returnType = List.class;
+        returnValue = getImpl().getContainerInfos(arg11, arg12, arg13);
+        break;
+      }
+      throw new IllegalArgumentException("Method not found: " + methodName + " in ContainerStateManager");
+
+    case "getContainerReplicas":
+      final ContainerID arg14 = p.length > 0 ? (ContainerID) p[0] : null;
+      returnType = Set.class;
+      returnValue = getImpl().getContainerReplicas(arg14);
+      break;
+
+    case "getMatchingContainer":
+      final long arg15 = p.length > 0 ? (long) p[0] : 0L;
+      final String arg16 = p.length > 1 ? (String) p[1] : null;
+      final PipelineID arg17 = p.length > 2 ? (PipelineID) p[2] : null;
+      final NavigableSet arg18 = p.length > 3 ? (NavigableSet) p[3] : null;
+      returnType = ContainerInfo.class;
+      returnValue = getImpl().getMatchingContainer(arg15, arg16, arg17, arg18);
+      break;
+
+    case "reinitialize":
+      final Table arg19 = p.length > 0 ? (Table) p[0] : null;
+      getImpl().reinitialize(arg19);
+      return Message.EMPTY;
+
+    case "removeContainer":
+      final HddsProtos.ContainerID arg20 = p.length > 0 ? (HddsProtos.ContainerID) p[0] : null;
+      getImpl().removeContainer(arg20);
+      return Message.EMPTY;
+
+    case "removeContainerReplica":
+      final ContainerReplica arg21 = p.length > 0 ? (ContainerReplica) p[0] : null;
+      getImpl().removeContainerReplica(arg21);
+      return Message.EMPTY;
+
+    case "transitionDeletingOrDeletedToTargetState":
+      final HddsProtos.ContainerID arg22 = p.length > 0 ? (HddsProtos.ContainerID) p[0] : null;
+      final LifeCycleState arg23 = p.length > 1 ? (LifeCycleState) p[1] : null;
+      getImpl().transitionDeletingOrDeletedToTargetState(arg22, arg23);
+      return Message.EMPTY;
+
+    case "updateContainerInfo":
+      final ContainerInfoProto arg24 = p.length > 0 ? (ContainerInfoProto) p[0] : null;
+      getImpl().updateContainerInfo(arg24);
+      return Message.EMPTY;
+
+    case "updateContainerReplica":
+      final ContainerReplica arg25 = p.length > 0 ? (ContainerReplica) p[0] : null;
+      getImpl().updateContainerReplica(arg25);
+      return Message.EMPTY;
+
+    case "updateContainerStateWithSequenceId":
+      final HddsProtos.ContainerID arg26 = p.length > 0 ? (HddsProtos.ContainerID) p[0] : null;
+      final LifeCycleEvent arg27 = p.length > 1 ? (LifeCycleEvent) p[1] : null;
+      final Long arg28 = p.length > 2 ? (Long) p[2] : null;
+      getImpl().updateContainerStateWithSequenceId(arg26, arg27, arg28);
+      return Message.EMPTY;
+
+    case "updateDeleteTransactionId":
+      final Map arg29 = p.length > 0 ? (Map) p[0] : null;
+      getImpl().updateDeleteTransactionId(arg29);
+      return Message.EMPTY;
+
+    default:
+      throw new IllegalArgumentException("Method not found: " + methodName + " in ContainerStateManager");
+    }
+
+    return SCMRatisResponse.encode(returnValue, returnType);
+  }
+}
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java
index a99364bc99b..a15bd3fa140 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ScmInvokerCodeGenerator.java
@@ -22,7 +22,6 @@
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -38,7 +37,9 @@
 import java.nio.file.StandardOpenOption;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -156,6 +157,39 @@ static String getClassname(Class<?> clazz) {
     return getClassnameBuilder(clazz).toString();
   }
 
+  String getClassnameForApi(Class<?> clazz) {
+    if (clazz.getEnclosingClass() != null
+        && clazz.getEnclosingClass().getSimpleName().endsWith("Protos")
+        && hasSimpleNameConflict(clazz)) {
+      return clazz.getEnclosingClass().getSimpleName() + "." + clazz.getSimpleName();
+    }
+    return getClassname(clazz);
+  }
+
+  boolean hasSimpleNameConflict(Class<?> clazz) {
+    final String simpleName = clazz.getSimpleName();
+    return Arrays.stream(api.getMethods())
+        .flatMap(method -> Arrays.stream(method.getParameterTypes()))
+        .anyMatch(type -> type != clazz && type.getSimpleName().equals(simpleName));
+  }
+
+  String getParameterStringForApi(Class<?>[] types, String[] names) {
+    final StringBuilder b = new StringBuilder();
+    final int n = names != null ? names.length : types.length;
+    for (int i = 0; i < n; i++) {
+      b.append(getClassnameForApi(types[i])).append(' ')
+          .append(names != null ? names[i] : "arg" + i).append(", ");
+    }
+    if (b.length() > 0) {
+      b.setLength(b.length() - 2);
+    }
+    return b.toString();
+  }
+
+  String classesToStringForApi(Class<?>[] classes, String suffix) {
+    return arrayToString(classes, c -> getClassnameForApi(c) + suffix);
+  }
+
   static StringBuilder getClassnameBuilder(Class<?> clazz) {
     final StringBuilder b = new StringBuilder(clazz.getSimpleName());
     for (Class<?> c = clazz.getEnclosingClass(); c != null; c = c.getEnclosingClass()) {
@@ -305,7 +339,7 @@ private void printEnumConstant(List<Method> overrides) {
         if (classes == null) {
           printf("null");
         } else {
-          printf("new Class<?>[] {%s}", classesToString(classes, ".class"));
+          printf("new Class<?>[] {%s}", classesToStringForApi(classes, ".class"));
         }
       }
     }
@@ -342,32 +376,123 @@ void printHeaderMethods() {
     }
   }
 
-  void printCase(Method apiMethod, String actualParameter, AtomicInteger argCount) {
-    printf("case \"%s\":", apiMethod.getName());
+  void printCase(List<Method> apiMethods, String actualParameter, String switchName, AtomicInteger argCount) {
+    printf("case \"%s\":", apiMethods.get(0).getName());
     try (UncheckedAutoCloseable ignore = printScope(false, 1)) {
-      final Parameter[] apiParameters = apiMethod.getParameters();
-      final StringBuilder b = new StringBuilder();
-      for (int i = 0; i < apiParameters.length; i++) {
-        final Parameter p = apiParameters[i];
-        final String classname = getClassname(p.getType());
-        final String arg = "arg" + argCount.getAndIncrement();
-        b.append(arg).append(", ");
-        println("final %s %s = %s.length > %d ? (%s) %s[%d] : null;", classname, arg,
-            actualParameter, i, classname, actualParameter, i);
+      if (apiMethods.size() == 1) {
+        printMethodCall(apiMethods.get(0), actualParameter, argCount, false);
+      } else {
+        for (Method apiMethod : apiMethods) {
+          printf("if (%s)", getParameterMatchCondition(apiMethod, actualParameter));
+          try (UncheckedAutoCloseable ignored = printScope()) {
+            printMethodCall(apiMethod, actualParameter, argCount, true);
+          }
+        }
+        printMethodNotFound(null, switchName);
       }
-      if (b.length() > 0) {
-        b.setLength(b.length() - 2);
+    }
+    println();
+  }
+
+  void printMethodCall(Method apiMethod, String actualParameter, AtomicInteger argCount, boolean exactArgs) {
+    final Parameter[] apiParameters = apiMethod.getParameters();
+    final StringBuilder b = new StringBuilder();
+    for (int i = 0; i < apiParameters.length; i++) {
+      final Parameter p = apiParameters[i];
+      final String classname = getClassnameForApi(p.getType());
+      final String arg = "arg" + argCount.getAndIncrement();
+      b.append(arg).append(", ");
+      if (exactArgs) {
+        println("final %s %s = (%s) %s[%d];", classname, arg, classname, actualParameter, i);
+      } else {
+        println("final %s %s = %s.length > %d ? (%s) %s[%d] : %s;", classname, arg,
+            actualParameter, i, classname, actualParameter, i, getDefaultValue(p.getType()));
       }
-      if (apiMethod.getReturnType() == void.class) {
-        println("getImpl().%s(%s);", apiMethod.getName(), b);
-        println("return Message.EMPTY;");
+    }
+    if (b.length() > 0) {
+      b.setLength(b.length() - 2);
+    }
+    if (apiMethod.getReturnType() == void.class) {
+      println("getImpl().%s(%s);", apiMethod.getName(), b);
+      println("return Message.EMPTY;");
+    } else {
+      println("returnType = %s.class;", getClassname(apiMethod.getReturnType()));
+      println("returnValue = getImpl().%s(%s);", apiMethod.getName(), b);
+      println("break;");
+    }
+  }
+
+  String getParameterMatchCondition(Method method, String actualParameter) {
+    final StringBuilder b = new StringBuilder()
+        .append(actualParameter)
+        .append(".length == ")
+        .append(method.getParameterCount());
+
+    final Class<?>[] parameterTypes = method.getParameterTypes();
+    for (int i = 0; i < parameterTypes.length; i++) {
+      final Class<?> type = parameterTypes[i];
+      final String checkType = getClassnameForApi(type.isPrimitive() ? getBoxedType(type) : type);
+      if (type.isPrimitive()) {
+        b.append(" && ").append(actualParameter).append("[").append(i).append("] instanceof ")
+            .append(checkType);
       } else {
-        println("returnType = %s.class;", getClassname(apiMethod.getReturnType()));
-        println("returnValue = getImpl().%s(%s);", apiMethod.getName(), b);
-        println("break;");
+        b.append(" && (").append(actualParameter).append("[").append(i).append("] == null || ")
+            .append(checkType).append(".class.isInstance(").append(actualParameter).append("[")
+            .append(i).append("]))");
       }
     }
-    println();
+    return b.toString();
+  }
+
+  static Class<?> getBoxedType(Class<?> type) {
+    if (type == boolean.class) {
+      return Boolean.class;
+    } else if (type == byte.class) {
+      return Byte.class;
+    } else if (type == char.class) {
+      return Character.class;
+    } else if (type == short.class) {
+      return Short.class;
+    } else if (type == int.class) {
+      return Integer.class;
+    } else if (type == long.class) {
+      return Long.class;
+    } else if (type == float.class) {
+      return Float.class;
+    } else if (type == double.class) {
+      return Double.class;
+    }
+    return type;
+  }
+
+  static String getDefaultValue(Class<?> type) {
+    if (!type.isPrimitive()) {
+      return "null";
+    } else if (type == boolean.class) {
+      return "false";
+    } else if (type == char.class) {
+      return "'\\0'";
+    } else if (type == long.class) {
+      return "0L";
+    } else if (type == float.class) {
+      return "0F";
+    } else if (type == double.class) {
+      return "0D";
+    }
+    return "0";
+  }
+
+  void printMethodNotFound(String label, String switchName) {
+    if (label != null) {
+      printf("%s:", label);
+      try (UncheckedAutoCloseable ignore = printScope(false, 1)) {
+        println("throw new IllegalArgumentException(\"Method not found: \" + %s + \" in %s\");",
+            switchName, apiName);
+      }
+    } else {
+      println("throw new IllegalArgumentException(\"Method not found: \" + %s + \" in %s\");",
+          switchName, apiName);
+    }
   }
 
   void printSwitch(DeclaredMethod method) {
@@ -375,15 +500,15 @@ void printSwitch(DeclaredMethod method) {
     printf("switch (%s)", switchName);
     try (UncheckedAutoCloseable ignored = printScope(true, 0)) {
       final AtomicInteger argCount = new AtomicInteger(0);
-      for (Method apiMethod : getMethods(false, null)) {
-        printCase(apiMethod, method.getParameterName(1), argCount);
-      }
+      final Map<String, List<Method>> methodsByName = getMethods(false, null).stream()
+          .collect(Collectors.groupingBy(
+              Method::getName, LinkedHashMap::new, Collectors.toList()));
 
-      printf("default:");
-      try (UncheckedAutoCloseable ignore = printScope(false, 1)) {
-        println("throw new IllegalArgumentException(\"Method not found: \" + %s + \" in %s\");",
-            switchName, apiName);
+      for (List<Method> apiMethods : methodsByName.values()) {
+        printCase(apiMethods, method.getParameterName(1), switchName, argCount);
       }
+
+      printMethodNotFound("default", switchName);
     }
   }
 
@@ -413,7 +538,7 @@ void printProxyClassMethod(Method method) {
     printf("public %s %s(%s)%s",
         getReturnTypeString(method),
         method.getName(),
-        getParameterString(method.getParameterTypes(), null),
+        getParameterStringForApi(method.getParameterTypes(), null),
         getThrowsString(method.getExceptionTypes()));
 
     try (UncheckedAutoCloseable ignored = printScope()) {
@@ -464,7 +589,7 @@ public String generateClass() {
   File updateFile(String classString) throws IOException {
     final File java = new File(DIR, invokerClassName + ".java");
     if (!java.isFile()) {
-      throw new FileNotFoundException("Not found: " + java.getAbsolutePath());
+      return createFile(java, classString);
     }
     final File tmp = new File(DIR, invokerClassName + "_tmp.java");
     if (tmp.exists()) {
@@ -537,4 +662,35 @@ String getSignature() {
           getThrowsString(exceptionTypes));
     }
   }
+
+  File createFile(File java, String classString) throws IOException {
+    try (OutputStream outStream = Files.newOutputStream(java.toPath(), StandardOpenOption.CREATE_NEW);
+        PrintWriter out = new PrintWriter(new OutputStreamWriter(outStream, UTF_8), true)) {
+      out.println("/*");
+      out.println(" * Licensed to the Apache Software Foundation (ASF) under one or more");
+      out.println(" * contributor license agreements. See the NOTICE file distributed with");
+      out.println(" * this work for additional information regarding copyright ownership.");
+      out.println(" * The ASF licenses this file to You under the Apache License, Version 2.0");
+      out.println(" * (the \"License\"); you may not use this file except in compliance with");
+      out.println(" * the License. You may obtain a copy of the License at");
+      out.println(" *");
+      out.println(" *      http://www.apache.org/licenses/LICENSE-2.0");
+      out.println(" *");
+      out.println(" * Unless required by applicable law or agreed to in writing, software");
+      out.println(" * distributed under the License is distributed on an \"AS IS\" BASIS,");
+      out.println(" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
+      out.println(" * See the License for the specific language governing permissions and");
+      out.println(" * limitations under the License.");
+      out.println(" */");
+      out.println();
+      out.println("package org.apache.hadoop.hdds.scm.ha.invoker;");
+      out.println();
+      out.println("import org.apache.hadoop.hdds.scm.ha.SCMRatisResponse;");
+      out.println("import org.apache.hadoop.hdds.scm.ha.SCMRatisServer;");
+      out.println("import org.apache.ratis.protocol.Message;");
+      out.println();
+      out.print(classString);
+    }
+    return java;
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org