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

wuzhiguo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bigtop-manager.git


The following commit(s) were added to refs/heads/main by this push:
     new 16fa4fd0 BIGTOP-4315: Support cluster start/stop/restart commands 
(#138)
16fa4fd0 is described below

commit 16fa4fd0bba82f1c353f52baf01cc2bf1dfc01bc
Author: Zhiguo Wu <[email protected]>
AuthorDate: Fri Jan 3 15:19:43 2025 +0800

    BIGTOP-4315: Support cluster start/stop/restart commands (#138)
---
 .../bigtop/manager/common/enums/Command.java       |  13 +-
 .../factory/cluster/ClusterRestartJobFactory.java  |  48 +++++++
 .../factory/cluster/ClusterStartJobFactory.java    |  48 +++++++
 .../factory/cluster/ClusterStopJobFactory.java     |  48 +++++++
 .../server/command/job/AbstractClusterJob.java     | 139 +++++++++++++++++++++
 .../server/command/job/AbstractServiceJob.java     |  46 ++-----
 .../server/command/job/ClusterRestartJob.java      |  38 ++++++
 .../server/command/job/ClusterStartJob.java        |  36 ++++++
 .../manager/server/command/job/ClusterStopJob.java |  36 ++++++
 .../manager/server/enums/ApiExceptionEnum.java     |   2 +-
 .../manager/server/model/dto/CommandDTO.java       |  16 ---
 .../manager/server/model/req/CommandReq.java       |   8 +-
 .../bigtop/manager/server/utils/StackDAGUtils.java |  65 ++++++++++
 .../bigtop/manager/server/utils/StackUtils.java    |  11 ++
 14 files changed, 485 insertions(+), 69 deletions(-)

diff --git 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
index 4af14bc5..6f9457af 100644
--- 
a/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
+++ 
b/bigtop-manager-common/src/main/java/org/apache/bigtop/manager/common/enums/Command.java
@@ -28,23 +28,18 @@ import lombok.Getter;
 @AllArgsConstructor
 @Getter
 public enum Command {
+    // Available for: Cluster, Host, Service, Component
     ADD("add", "Add"),
-
     REMOVE("remove", "Remove"),
-
     START("start", "Start"),
-
     STOP("stop", "Stop"),
-
-    STATUS("status", "Status"),
-
     RESTART("restart", "Restart"),
 
-    CONFIGURE("configure", "Configure"),
-
+    // Available for: Service, Component
+    STATUS("status", "Status"),
     CHECK("check", "Check"),
-
     CUSTOM("custom", "Custom"),
+    CONFIGURE("configure", "Configure"),
     ;
 
     private final String code;
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterRestartJobFactory.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterRestartJobFactory.java
new file mode 100644
index 00000000..9ad6a2c3
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterRestartJobFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.factory.cluster;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.ClusterRestartJob;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.enums.CommandLevel;
+
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ClusterRestartJobFactory extends AbstractClusterJobFactory {
+
+    @Override
+    public CommandIdentifier getCommandIdentifier() {
+        return new CommandIdentifier(CommandLevel.CLUSTER, Command.RESTART);
+    }
+
+    @Override
+    public Job createJob(JobContext jobContext) {
+        return new ClusterRestartJob(jobContext);
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStartJobFactory.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStartJobFactory.java
new file mode 100644
index 00000000..b1b33515
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStartJobFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.factory.cluster;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.ClusterStartJob;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.enums.CommandLevel;
+
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ClusterStartJobFactory extends AbstractClusterJobFactory {
+
+    @Override
+    public CommandIdentifier getCommandIdentifier() {
+        return new CommandIdentifier(CommandLevel.CLUSTER, Command.START);
+    }
+
+    @Override
+    public Job createJob(JobContext jobContext) {
+        return new ClusterStartJob(jobContext);
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStopJobFactory.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStopJobFactory.java
new file mode 100644
index 00000000..9290040b
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/factory/cluster/ClusterStopJobFactory.java
@@ -0,0 +1,48 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.factory.cluster;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.command.CommandIdentifier;
+import org.apache.bigtop.manager.server.command.job.ClusterStopJob;
+import org.apache.bigtop.manager.server.command.job.Job;
+import org.apache.bigtop.manager.server.command.job.JobContext;
+import org.apache.bigtop.manager.server.enums.CommandLevel;
+
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+public class ClusterStopJobFactory extends AbstractClusterJobFactory {
+
+    @Override
+    public CommandIdentifier getCommandIdentifier() {
+        return new CommandIdentifier(CommandLevel.CLUSTER, Command.STOP);
+    }
+
+    @Override
+    public Job createJob(JobContext jobContext) {
+        return new ClusterStopJob(jobContext);
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractClusterJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractClusterJob.java
new file mode 100644
index 00000000..4787e197
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractClusterJob.java
@@ -0,0 +1,139 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.job;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.dao.po.ComponentPO;
+import org.apache.bigtop.manager.dao.query.ComponentQuery;
+import org.apache.bigtop.manager.dao.repository.ComponentDao;
+import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
+import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
+import org.apache.bigtop.manager.server.command.stage.StageContext;
+import org.apache.bigtop.manager.server.holder.SpringContextHolder;
+import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
+import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
+import org.apache.bigtop.manager.server.utils.StackDAGUtils;
+import org.apache.bigtop.manager.server.utils.StackUtils;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbstractClusterJob extends AbstractJob {
+
+    protected ComponentDao componentDao;
+
+    public AbstractClusterJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
+    @Override
+    protected void injectBeans() {
+        super.injectBeans();
+
+        this.componentDao = SpringContextHolder.getBean(ComponentDao.class);
+    }
+
+    @Override
+    protected void beforeCreateStages() {
+        super.beforeCreateStages();
+    }
+
+    protected StageContext createStageContext(String componentName, 
List<String> hostnames) {
+        StageContext stageContext = 
StageContext.fromCommandDTO(jobContext.getCommandDTO());
+
+        ServiceDTO serviceDTO = 
StackUtils.getServiceDTOByComponentName(componentName);
+        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
+
+        stageContext.setHostnames(hostnames);
+        stageContext.setServiceDTO(serviceDTO);
+        stageContext.setComponentDTO(componentDTO);
+
+        return stageContext;
+    }
+
+    protected void createStartStages() {
+        List<ComponentPO> componentPOList = getComponentPOList();
+        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.START);
+
+        for (String componentCommand : todoList) {
+            String[] split = componentCommand.split("-");
+            String componentName = split[0];
+
+            if (StackUtils.isClientComponent(componentName)) {
+                continue;
+            }
+
+            List<String> hostnames = 
findHostnamesByComponentName(componentPOList, componentName);
+            if (CollectionUtils.isEmpty(hostnames)) {
+                continue;
+            }
+
+            StageContext stageContext = createStageContext(componentName, 
hostnames);
+            stages.add(new ComponentStartStage(stageContext));
+        }
+    }
+
+    protected void createStopStages() {
+        List<ComponentPO> componentPOList = getComponentPOList();
+        List<String> todoList = 
StackDAGUtils.getTodoList(getComponentNames(componentPOList), Command.STOP);
+
+        for (String componentCommand : todoList) {
+            String[] split = componentCommand.split("-");
+            String componentName = split[0];
+
+            if (StackUtils.isClientComponent(componentName)) {
+                continue;
+            }
+
+            List<String> hostnames = 
findHostnamesByComponentName(componentPOList, componentName);
+            if (CollectionUtils.isEmpty(hostnames)) {
+                continue;
+            }
+
+            StageContext stageContext = createStageContext(componentName, 
hostnames);
+            stages.add(new ComponentStopStage(stageContext));
+        }
+    }
+
+    private List<ComponentPO> getComponentPOList() {
+        return componentDao.findByQuery(
+                ComponentQuery.builder().clusterId(clusterPO.getId()).build());
+    }
+
+    private List<String> getComponentNames(List<ComponentPO> componentPOList) {
+        if (componentPOList == null) {
+            return new ArrayList<>();
+        } else {
+            return 
componentPOList.stream().map(ComponentPO::getName).distinct().toList();
+        }
+    }
+
+    private List<String> findHostnamesByComponentName(List<ComponentPO> 
componentPOList, String componentName) {
+        if (componentPOList == null) {
+            return new ArrayList<>();
+        } else {
+            return componentPOList.stream()
+                    .filter(componentPO -> 
componentPO.getName().equals(componentName))
+                    .map(ComponentPO::getHostname)
+                    .toList();
+        }
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
index 8f128f1a..653e55ba 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/AbstractServiceJob.java
@@ -18,7 +18,6 @@
  */
 package org.apache.bigtop.manager.server.command.job;
 
-import org.apache.bigtop.manager.common.constants.ComponentCategories;
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.dao.po.ComponentPO;
 import org.apache.bigtop.manager.dao.query.ComponentQuery;
@@ -34,12 +33,12 @@ import 
org.apache.bigtop.manager.server.command.stage.ComponentConfigureStage;
 import org.apache.bigtop.manager.server.command.stage.ComponentStartStage;
 import org.apache.bigtop.manager.server.command.stage.ComponentStopStage;
 import org.apache.bigtop.manager.server.command.stage.StageContext;
-import org.apache.bigtop.manager.server.exception.ServerException;
 import org.apache.bigtop.manager.server.holder.SpringContextHolder;
 import org.apache.bigtop.manager.server.model.dto.ComponentDTO;
 import org.apache.bigtop.manager.server.model.dto.ComponentHostDTO;
 import org.apache.bigtop.manager.server.model.dto.ServiceDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
+import org.apache.bigtop.manager.server.utils.StackDAGUtils;
 import org.apache.bigtop.manager.server.utils.StackUtils;
 
 import org.apache.commons.collections4.CollectionUtils;
@@ -88,25 +87,6 @@ public abstract class AbstractServiceJob extends AbstractJob 
{
         return stageContext;
     }
 
-    protected List<String> getTodoListForCommand(Command command) {
-        try {
-            List<String> orderedList =
-                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
-            List<String> componentNames = getComponentNames();
-            List<String> componentCommandNames = new 
ArrayList<>(componentNames.stream()
-                    .map(x -> x + "-" + command.name().toUpperCase())
-                    .toList());
-
-            orderedList.retainAll(componentCommandNames);
-            componentCommandNames.removeAll(orderedList);
-            orderedList.addAll(componentCommandNames);
-
-            return orderedList;
-        } catch (Exception e) {
-            throw new ServerException(e);
-        }
-    }
-
     protected List<String> getComponentNames() {
         List<String> serviceNames = getServiceNames();
         ComponentQuery componentQuery = ComponentQuery.builder()
@@ -122,16 +102,6 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
         return 
StackUtils.getServiceDTOByComponentName(componentName).getName();
     }
 
-    protected Boolean isServerComponent(String componentName) {
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-        return 
componentDTO.getCategory().equalsIgnoreCase(ComponentCategories.SERVER);
-    }
-
-    protected Boolean isClientComponent(String componentName) {
-        ComponentDTO componentDTO = StackUtils.getComponentDTO(componentName);
-        return 
componentDTO.getCategory().equalsIgnoreCase(ComponentCategories.CLIENT);
-    }
-
     protected List<String> findHostnamesByComponentName(String componentName) {
         ComponentQuery componentQuery = ComponentQuery.builder()
                 .clusterId(clusterPO.getId())
@@ -151,7 +121,7 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
     }
 
     protected void createAddStages() {
-        List<String> todoList = getTodoListForCommand(Command.ADD);
+        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.ADD);
 
         for (String componentCommand : todoList) {
             String[] split = componentCommand.split("-");
@@ -181,14 +151,14 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
     }
 
     protected void createStartStages() {
-        List<String> todoList = getTodoListForCommand(Command.START);
+        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.START);
 
         for (String componentCommand : todoList) {
             String[] split = componentCommand.split("-");
             String componentName = split[0];
             String serviceName = findServiceNameByComponentName(componentName);
 
-            if (isClientComponent(componentName)) {
+            if (StackUtils.isClientComponent(componentName)) {
                 continue;
             }
 
@@ -203,14 +173,14 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
     }
 
     protected void createStopStages() {
-        List<String> todoList = getTodoListForCommand(Command.STOP);
+        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.STOP);
 
         for (String componentCommand : todoList) {
             String[] split = componentCommand.split("-");
             String componentName = split[0];
             String serviceName = findServiceNameByComponentName(componentName);
 
-            if (isClientComponent(componentName)) {
+            if (StackUtils.isClientComponent(componentName)) {
                 continue;
             }
 
@@ -225,14 +195,14 @@ public abstract class AbstractServiceJob extends 
AbstractJob {
     }
 
     protected void createCheckStages() {
-        List<String> todoList = getTodoListForCommand(Command.CHECK);
+        List<String> todoList = StackDAGUtils.getTodoList(getComponentNames(), 
Command.CHECK);
 
         for (String componentCommand : todoList) {
             String[] split = componentCommand.split("-");
             String componentName = split[0];
             String serviceName = findServiceNameByComponentName(componentName);
 
-            if (isClientComponent(componentName)) {
+            if (StackUtils.isClientComponent(componentName)) {
                 continue;
             }
 
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterRestartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterRestartJob.java
new file mode 100644
index 00000000..53d02c9a
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterRestartJob.java
@@ -0,0 +1,38 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.job;
+
+public class ClusterRestartJob extends AbstractClusterJob {
+
+    public ClusterRestartJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
+    @Override
+    protected void createStages() {
+        super.createStopStages();
+
+        super.createStartStages();
+    }
+
+    @Override
+    public String getName() {
+        return "Restart cluster";
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStartJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStartJob.java
new file mode 100644
index 00000000..39036df2
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStartJob.java
@@ -0,0 +1,36 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.job;
+
+public class ClusterStartJob extends AbstractClusterJob {
+
+    public ClusterStartJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
+    @Override
+    protected void createStages() {
+        super.createStartStages();
+    }
+
+    @Override
+    public String getName() {
+        return "Start cluster";
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStopJob.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStopJob.java
new file mode 100644
index 00000000..843d7a50
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/command/job/ClusterStopJob.java
@@ -0,0 +1,36 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.command.job;
+
+public class ClusterStopJob extends AbstractClusterJob {
+
+    public ClusterStopJob(JobContext jobContext) {
+        super(jobContext);
+    }
+
+    @Override
+    protected void createStages() {
+        super.createStopStages();
+    }
+
+    @Override
+    public String getName() {
+        return "Stop cluster";
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
index 26d432bb..b79531fd 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/enums/ApiExceptionEnum.java
@@ -61,7 +61,7 @@ public enum ApiExceptionEnum {
 
     // Command Exceptions -- 18000 ~ 18999
     COMMAND_NOT_FOUND(18000, LocaleKeys.COMMAND_NOT_FOUND),
-    COMMAND_NOT_SUPPORTED(18000, LocaleKeys.COMMAND_NOT_SUPPORTED),
+    COMMAND_NOT_SUPPORTED(18001, LocaleKeys.COMMAND_NOT_SUPPORTED),
 
     // LLM Exceptions -- 19000 ~ 19999
     PLATFORM_NOT_FOUND(19000, LocaleKeys.PLATFORM_NOT_FOUND),
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/CommandDTO.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/CommandDTO.java
index 5ea67aa0..d0c30213 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/CommandDTO.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/dto/CommandDTO.java
@@ -25,12 +25,9 @@ import 
org.apache.bigtop.manager.server.model.dto.command.ComponentCommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.HostCommandDTO;
 import org.apache.bigtop.manager.server.model.dto.command.ServiceCommandDTO;
 
-import org.apache.commons.text.CaseUtils;
-
 import lombok.Data;
 
 import java.io.Serializable;
-import java.text.MessageFormat;
 import java.util.List;
 
 @Data
@@ -51,17 +48,4 @@ public class CommandDTO implements Serializable {
     private List<ServiceCommandDTO> serviceCommands;
 
     private List<ComponentCommandDTO> componentCommands;
-
-    public String getContext() {
-        if (clusterId == null) {
-            return "Create Cluster";
-        }
-
-        if (command == null) {
-            return MessageFormat.format("{0} for {1}", customCommand, 
commandLevel.toLowerCase());
-        } else {
-            return MessageFormat.format(
-                    "{0} for {1}", CaseUtils.toCamelCase(command.name(), 
true), commandLevel.toLowerCase());
-        }
-    }
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/CommandReq.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/CommandReq.java
index 3194f4c6..7b597ee6 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/CommandReq.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/model/req/CommandReq.java
@@ -32,7 +32,6 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import java.util.List;
 
@@ -52,16 +51,15 @@ public class CommandReq {
     @NotNull @Schema(example = "cluster")
     private CommandLevel commandLevel;
 
-    @NotNull(groups = 
{CommandGroupSequenceProvider.ClusterCommandGroup.class}) @Schema(description = 
"Command details for cluster level command")
+    @Schema(description = "Command details for cluster level command")
     private ClusterCommandReq clusterCommand;
 
-    @NotNull(groups = {CommandGroupSequenceProvider.HostCommandGroup.class}) 
@Schema(description = "Command details for host level command")
+    @Schema(description = "Command details for host level command")
     private List<@Valid HostCommandReq> hostCommands;
 
-    @NotEmpty(groups = 
{CommandGroupSequenceProvider.ServiceCommandGroup.class})
     @Schema(description = "Command details for service level command")
     private List<@Valid ServiceCommandReq> serviceCommands;
 
-    @NotNull(groups = 
{CommandGroupSequenceProvider.ComponentCommandGroup.class}) @Schema(description 
= "Command details for component level command")
+    @Schema(description = "Command details for component level command")
     private List<@Valid ComponentCommandReq> componentCommands;
 }
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
new file mode 100644
index 00000000..994170f2
--- /dev/null
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackDAGUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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
+ *
+ *    https://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.bigtop.manager.server.utils;
+
+import org.apache.bigtop.manager.common.enums.Command;
+import org.apache.bigtop.manager.server.exception.ServerException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StackDAGUtils {
+
+    public static List<String> orderTodoList(List<String> 
componentCommandNames) {
+        try {
+            List<String> orderedList =
+                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
+
+            // Re-order the commands, since order.json does not contain all 
commands,
+            // only contains which has dependencies, we need to add the rest 
to the end.
+            orderedList.retainAll(componentCommandNames);
+            componentCommandNames.removeAll(orderedList);
+            orderedList.addAll(componentCommandNames);
+
+            return orderedList;
+        } catch (Exception e) {
+            throw new ServerException(e);
+        }
+    }
+
+    public static List<String> getTodoList(List<String> componentNames, 
Command command) {
+        try {
+            List<String> orderedList =
+                    StackUtils.DAG.getAllNodesList().isEmpty() ? new 
ArrayList<>() : StackUtils.DAG.topologicalSort();
+            List<String> componentCommandNames = new 
ArrayList<>(componentNames.stream()
+                    .map(x -> x + "-" + command.name().toUpperCase())
+                    .toList());
+
+            // Re-order the commands, since order.json does not contain all 
commands,
+            // only contains which has dependencies, we need to add the rest 
to the end.
+            orderedList.retainAll(componentCommandNames);
+            componentCommandNames.removeAll(orderedList);
+            orderedList.addAll(componentCommandNames);
+
+            return orderedList;
+        } catch (Exception e) {
+            throw new ServerException(e);
+        }
+    }
+}
diff --git 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackUtils.java
 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackUtils.java
index b8e7fba4..7eaad4a1 100644
--- 
a/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackUtils.java
+++ 
b/bigtop-manager-server/src/main/java/org/apache/bigtop/manager/server/utils/StackUtils.java
@@ -18,6 +18,7 @@
  */
 package org.apache.bigtop.manager.server.utils;
 
+import org.apache.bigtop.manager.common.constants.ComponentCategories;
 import org.apache.bigtop.manager.common.enums.Command;
 import org.apache.bigtop.manager.common.utils.CaseUtils;
 import org.apache.bigtop.manager.common.utils.JsonUtils;
@@ -267,4 +268,14 @@ public class StackUtils {
 
         throw new ServerException("Service not found by component name: " + 
componentName);
     }
+
+    public static Boolean isServerComponent(String componentName) {
+        ComponentDTO componentDTO = getComponentDTO(componentName);
+        return 
componentDTO.getCategory().equalsIgnoreCase(ComponentCategories.SERVER);
+    }
+
+    public static Boolean isClientComponent(String componentName) {
+        ComponentDTO componentDTO = getComponentDTO(componentName);
+        return 
componentDTO.getCategory().equalsIgnoreCase(ComponentCategories.CLIENT);
+    }
 }


Reply via email to