content: package com.xxl.job.admin.core.trigger;
  
  import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
  import com.xxl.job.admin.core.model.XxlJobGroup;
  import com.xxl.job.admin.core.model.XxlJobInfo;
  import com.xxl.job.admin.core.model.XxlJobLog;
  import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
  import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
  import com.xxl.job.admin.core.util.I18nUtil;
  import com.xxl.job.core.biz.ExecutorBiz;
  import com.xxl.job.core.biz.model.ReturnT;
  import com.xxl.job.core.biz.model.TriggerParam;
  import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
  import com.xxl.job.core.util.IpUtil;
  import com.xxl.job.core.util.ThrowableUtil;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.Date;
  
  /**
   * xxl-job trigger
   * Created by xuxueli on 17/7/13.
   */
  public class XxlJobTrigger {
      private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);
  
      /**
       * trigger job
       *
       * @param jobId
       * @param triggerType
       * @param failRetryCount
       * 			>=0: use this param
       * 			<0: use param from job info config
       * @param executorShardingParam
       * @param executorParam
       *          null: use job param
       *          not null: cover job param
       * @param addressList
       *          null: use executor addressList
       *          not null: cover
       */
      public static void trigger(int jobId,
                                 TriggerTypeEnum triggerType,
                                 int failRetryCount,
                                 String executorShardingParam,
                                 String executorParam,
                                 String addressList) {
  
          // load data
          XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId);
          if (jobInfo == null) {
              logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid，jobId={}", jobId);
              return;
          }
          if (executorParam != null) {
              jobInfo.setExecutorParam(executorParam);
          }
          int finalFailRetryCount = failRetryCount>=0?failRetryCount:jobInfo.getExecutorFailRetryCount();
          XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(jobInfo.getJobGroup());
  
          // cover addressList
          if (addressList!=null && addressList.trim().length()>0) {
              group.setAddressType(1);
              group.setAddressList(addressList.trim());
          }
  
          // sharding param
          int[] shardingParam = null;
          if (executorShardingParam!=null){
              String[] shardingArr = executorShardingParam.split("/");
              if (shardingArr.length==2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) {
                  shardingParam = new int[2];
                  shardingParam[0] = Integer.valueOf(shardingArr[0]);
                  shardingParam[1] = Integer.valueOf(shardingArr[1]);
              }
          }
          if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null)
                  && group.getRegistryList()!=null && !group.getRegistryList().isEmpty()
                  && shardingParam==null) {
              for (int i = 0; i < group.getRegistryList().size(); i++) {
                  processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size());
              }
          } else {
              if (shardingParam == null) {
                  shardingParam = new int[]{0, 1};
              }
              processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]);
          }
  
      }
  
      private static boolean isNumeric(String str){
          try {
              int result = Integer.valueOf(str);
              return true;
          } catch (NumberFormatException e) {
              return false;
          }
      }
  
      /**
       * @param group                     job group, registry list may be empty
       * @param jobInfo
       * @param finalFailRetryCount
       * @param triggerType
       * @param index                     sharding index
       * @param total                     sharding index
       */
      private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount, TriggerTypeEnum triggerType, int index, int total){
  
          // param
          ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION);  // block strategy
          ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null);    // route strategy
          String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==executorRouteStrategyEnum)?String.valueOf(index).concat("/").concat(String.valueOf(total)):null;
  
          // 1、save log-id
          XxlJobLog jobLog = new XxlJobLog();
          jobLog.setJobGroup(jobInfo.getJobGroup());
          jobLog.setJobId(jobInfo.getId());
          jobLog.setTriggerTime(new Date());
          XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog);
          logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
  
          // 2、init trigger-param
          TriggerParam triggerParam = new TriggerParam();
          triggerParam.setJobId(jobInfo.getId());
          triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
          triggerParam.setExecutorParams(jobInfo.getExecutorParam());
          triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
          triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
          triggerParam.setLogId(jobLog.getId());
          triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime());
          triggerParam.setGlueType(jobInfo.getGlueType());
          triggerParam.setGlueSource(jobInfo.getGlueSource());
          triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
          triggerParam.setBroadcastIndex(index);
          triggerParam.setBroadcastTotal(total);
  
          // 3、init address
          String address = null;
          ReturnT<String> routeAddressResult = null;
          if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
              if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) {
                  if (index < group.getRegistryList().size()) {
                      address = group.getRegistryList().get(index);
                  } else {
                      address = group.getRegistryList().get(0);
                  }
              } else {
                  routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList());
                  if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) {
                      address = routeAddressResult.getContent();
                  }
              }
          } else {
              routeAddressResult = new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobconf_trigger_address_empty"));
          }
  
          // 4、trigger remote executor
          ReturnT<String> triggerResult = null;
          if (address != null) {
              triggerResult = runExecutor(triggerParam, address);
          } else {
              triggerResult = new ReturnT<String>(ReturnT.FAIL_CODE, null);
          }
  
          // 5、collection trigger info
          StringBuffer triggerMsgSb = new StringBuffer();
          triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append("：").append(triggerType.getTitle());
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append("：").append(IpUtil.getIp());
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append("：")
                  .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append("：").append(group.getRegistryList());
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append("：").append(executorRouteStrategyEnum.getTitle());
          if (shardingParam != null) {
              triggerMsgSb.append("("+shardingParam+")");
          }
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append("：").append(blockStrategy.getTitle());
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_timeout")).append("：").append(jobInfo.getExecutorTimeout());
          triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append("：").append(finalFailRetryCount);
  
          triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>")
                  .append((routeAddressResult!=null&&routeAddressResult.getMsg()!=null)?routeAddressResult.getMsg()+"<br><br>":"").append(triggerResult.getMsg()!=null?triggerResult.getMsg():"");
  
          // 6、save log trigger-info
          jobLog.setExecutorAddress(address);
          jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
          jobLog.setExecutorParam(jobInfo.getExecutorParam());
          jobLog.setExecutorShardingParam(shardingParam);
          jobLog.setExecutorFailRetryCount(finalFailRetryCount);
          //jobLog.setTriggerTime();
          jobLog.setTriggerCode(triggerResult.getCode());
          jobLog.setTriggerMsg(triggerMsgSb.toString());
          XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(jobLog);
  
          logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
      }
  
      /**
       * run executor
       * @param triggerParam
       * @param address
       * @return
       */
      public static ReturnT<String> runExecutor(TriggerParam triggerParam, String address){
          ReturnT<String> runResult = null;
          try {
              ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
              runResult = executorBiz.run(triggerParam);
          } catch (Exception e) {
              logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
              runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
          }
  
          StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + "：");
          runResultSB.append("<br>address：").append(address);
          runResultSB.append("<br>code：").append(runResult.getCode());
          runResultSB.append("<br>msg：").append(runResult.getMsg());
  
          runResult.setMsg(runResultSB.toString());
          return runResult;
      }
  
  }
  