content: /*
   * Copyright (c) 2024, Alibaba Cloud;
   * Licensed 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 com.aliyun.dataworks.client.command;
  
  import java.io.File;
  import java.io.IOException;
  import java.nio.charset.StandardCharsets;
  import java.util.Map;
  import java.util.Objects;
  import java.util.stream.Stream;
  
  import com.alibaba.fastjson2.JSON;
  
  import com.google.common.base.Joiner;
  import com.google.common.reflect.TypeToken;
  import lombok.extern.slf4j.Slf4j;
  import org.apache.commons.cli.CommandLine;
  import org.apache.commons.cli.CommandLineParser;
  import org.apache.commons.cli.DefaultParser;
  import org.apache.commons.cli.HelpFormatter;
  import org.apache.commons.cli.Options;
  import org.apache.commons.cli.ParseException;
  import org.apache.commons.collections4.MapUtils;
  import org.apache.commons.io.FileUtils;
  
  /**
   * @author 聿剑
   * @date 2022/10/20
   */
  @Slf4j
  public class CommandAppEntrance {
      public static void main(String[] args) throws IOException {
          String currentDir = System.getProperty("currentDir");
          AppType appType = AppType.valueOf(System.getProperty("appType"));
  
          Map<AppType, Map<String, AppMeta>> apps = loadApps(Joiner.on(File.separator).join(currentDir, "conf"), appType);
  
          Options options = new Options();
          options.addRequiredOption("a", "app", true, "app name");
  
          HelpFormatter helpFormatter = new HelpFormatter();
          try {
              CommandLineParser parser = new DefaultParser();
              CommandLine commandLine = parser.parse(options, args, true);
              String appName = commandLine.getOptionValue("a");
  
              if (!apps.get(appType).containsKey(appName)) {
                  throw new RuntimeException("unknown app: " + appName);
              }
  
              CommandApp app = CommandAppFactory.create(appType, appName);
              app.setAppMeta(apps.get(appType).get(appName));
              log.info("start running app {} with args: {}", appName, commandLine.getArgs());
              app.run(commandLine.getArgs());
              log.info("app command success");
          } catch (ParseException e) {
              log.error("app command parse error: {}", e.getMessage());
              String footer = Joiner.on(" ").join("\nAvailable apps: \n", JSON.toJSONString(CommandAppFactory.getApps()));
              helpFormatter.printHelp("Options", "migrationx", options, footer);
          } catch (Exception e) {
              log.error("app command failed: ", e);
              throw new RuntimeException(e);
          }
      }
  
      @SuppressWarnings("unchecked")
      private static Map<AppType, Map<String, AppMeta>> loadApps(String conf, AppType... appTypes) throws IOException {
          File config = new File(conf);
          File appsJson = config;
          if (config.isDirectory()) {
              appsJson = new File(config, "apps.json");
          }
  
          String json = FileUtils.readFileToString(appsJson, StandardCharsets.UTF_8);
          Map<AppType, Map<String, AppMeta>> apps = JSON.parseObject(json, new TypeToken<Map<AppType, Map<String, AppMeta>>>() {}.getType());
          MapUtils.emptyIfNull(apps).forEach((appType, map) -> MapUtils.emptyIfNull(map).forEach((appName, appMeta) -> {
              if (appTypes != null && Stream.of(appTypes).noneMatch(t -> Objects.equals(t, appType))) {
                  log.info("skip load app type: {}, appType needs load: {}", appType, appTypes);
                  return;
              }
  
              try {
                  appMeta.setName(appName);
                  appMeta.setType(appType);
                  log.info("register command app type: {}, name: {}, class: {}", appType, appName, appMeta.getAppClass());
                  CommandAppFactory.register(appType, appName, appMeta.getAppClass());
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }));
  
          log.info("apps map: {}", JSON.toJSONString(apps));
          return apps;
      }
  }
  