diff --git a/escheduler-common/pom.xml b/escheduler-common/pom.xml
new file mode 100644
index 0000000000..a4d84a8074
--- /dev/null
+++ b/escheduler-common/pom.xml
@@ -0,0 +1,380 @@
+
+
+ 4.0.0
+
+ escheduler
+ cn.analysys
+ 1.0.0
+
+ escheduler-common
+ escheduler-common
+ http://maven.apache.org
+ jar
+
+ UTF-8
+
+
+
+ com.alibaba
+ fastjson
+ compile
+
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+ junit
+ junit
+ test
+
+
+
+ commons-configuration
+ commons-configuration
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.apache.curator
+ curator-client
+ 2.12.0
+
+
+ log4j
+ log4j
+
+
+ io.netty
+ netty
+
+
+
+
+ org.apache.commons
+ commons-collections4
+
+
+
+ org.apache.hadoop
+ hadoop-common
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ jdk.tools
+ jdk.tools
+
+
+ servlet-api
+ javax.servlet
+
+
+ javax.servlet
+ servlet-api
+
+
+ log4j
+ log4j
+
+
+ org.apache.curator
+ curator-client
+
+
+
+ commons-configuration
+ commons-configuration
+
+
+ io.grpc
+ grpc-protobuf
+
+
+ io.netty
+ netty
+
+
+ org.codehaus.jackson
+ jackson-core-asl
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+
+
+ com.google.protobuf
+ jackson-mapper-asl
+
+
+ com.google.code.gson
+ gson
+
+
+ org.apache.commons
+ commons-math3
+
+
+ xmlenc
+ xmlenc
+
+
+ commons-net
+ commons-net
+
+
+ org.apache.avro
+ avro
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ jsr305
+ com.google.code.findbugs
+
+
+ javax.servlet.jsp
+ jsp-api
+
+
+
+
+
+ org.apache.hadoop
+ hadoop-client
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ servlet-api
+ javax.servlet
+
+
+ org.codehaus.jackson
+ jackson-jaxrs
+
+
+ org.codehaus.jackson
+ jackson-xc
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+ org.fusesource.leveldbjni
+ leveldbjni-all
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ org.apache.hadoop
+ hadoop-mapreduce-client-shuffle
+
+
+
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+
+ org.apache.hadoop
+ hadoop-hdfs
+
+
+ javax.servlet
+ servlet-api
+
+
+ io.netty
+ netty
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+ xmlenc
+ xmlenc
+
+
+ io.netty
+ netty-all
+
+
+ org.fusesource.leveldbjni
+ leveldbjni-all
+
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.apache.hive
+ hive-jdbc
+
+
+ slf4j-log4j12
+ org.slf4j
+
+
+ org.eclipse.jetty.aggregate
+ jetty-all
+
+
+
+ org.apache.ant
+ ant
+
+
+ io.dropwizard.metrics
+ metrics-json
+
+
+ io.dropwizard.metrics
+ metrics-jvm
+
+
+ com.github.joshelser
+ dropwizard-metrics-hadoop-metrics2-reporter
+
+
+
+ io.netty
+ netty-all
+
+
+ com.google.code.gson
+ gson
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+ io.dropwizard.metrics
+ metrics-core
+
+
+ javax.servlet
+ servlet-api
+
+
+ org.apache.avro
+ avro
+
+
+ org.apache.commons
+ commons-compress
+
+
+ org.apache.curator
+ curator-client
+
+
+ org.apache.hadoop
+ hadoop-auth
+
+
+ org.apache.hadoop
+ hadoop-mapreduce-client-core
+
+
+ org.apache.hadoop
+ hadoop-yarn-api
+
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+ org.codehaus.jackson
+ jackson-jaxrs
+
+
+ org.codehaus.jackson
+ jackson-xc
+
+
+ com.google.protobuf
+ protobuf-java
+
+
+
+ org.json
+ json
+
+
+ log4j-slf4j-impl
+ org.apache.logging.log4j
+
+
+
+
+
+ org.mybatis
+ mybatis
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+ com.github.oshi
+ oshi-core
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/Constants.java b/escheduler-common/src/main/java/cn/escheduler/common/Constants.java
new file mode 100644
index 0000000000..e0e0c399e9
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/Constants.java
@@ -0,0 +1,815 @@
+/*
+ * 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 cn.escheduler.common;
+
+import cn.escheduler.common.utils.OSUtils;
+
+import java.util.regex.Pattern;
+
+/**
+ * Constants
+ */
+public final class Constants {
+
+ /**
+ * zookeeper properties path
+ */
+ public static final String ZOOKEEPER_PROPERTIES_PATH = "zookeeper.properties";
+
+ /**
+ * worker properties path
+ */
+ public static final String WORKER_PROPERTIES_PATH = "worker.properties";
+
+ /**
+ * master properties path
+ */
+ public static final String MASTER_PROPERTIES_PATH = "master.properties";
+
+ /**
+ * hadoop properties path
+ */
+ public static final String HADOOP_PROPERTIES_PATH = "/common/hadoop/hadoop.properties";
+
+ /**
+ * common properties path
+ */
+ public static final String COMMON_PROPERTIES_PATH = "/common/common.properties";
+
+ /**
+ * dao properties path
+ */
+ public static final String DAO_PROPERTIES_PATH = "/dao/data_source.properties";
+
+ /**
+ * fs.defaultFS
+ */
+ public static final String FS_DEFAULTFS = "fs.defaultFS";
+
+ /**
+ * yarn.resourcemanager.ha.rm.idsfs.defaultFS
+ */
+ public static final String YARN_RESOURCEMANAGER_HA_RM_IDS = "yarn.resourcemanager.ha.rm.ids";
+
+ /**
+ * yarn.application.status.address
+ */
+ public static final String YARN_APPLICATION_STATUS_ADDRESS = "yarn.application.status.address";
+
+ /**
+ * spring.redis.maxIdle
+ */
+ public static final String SPRING_REDIS_MAXIDLE = "spring.redis.maxIdle";
+
+ /**
+ * spring.redis.maxTotal
+ */
+ public static final String SPRING_REDIS_MAXTOTAL = "spring.redis.maxTotal";
+
+ /**
+ * spring.redis.host
+ */
+ public static final String SPRING_REDIS_HOST = "spring.redis.host";
+
+ /**
+ * spring.redis.port
+ */
+ public static final String SPRING_REDIS_PORT = "spring.redis.port";
+
+ /**
+ * hdfs configuration
+ * data.store2hdfs.basepath
+ */
+ public static final String DATA_STORE_2_HDFS_BASEPATH = "data.store2hdfs.basepath";
+
+ /**
+ * data.basedir.path
+ */
+ public static final String DATA_BASEDIR_PATH = "data.basedir.path";
+
+ /**
+ * data.download.basedir.path
+ */
+ public static final String DATA_DOWNLOAD_BASEDIR_PATH = "data.download.basedir.path";
+
+ /**
+ * process.exec.basepath
+ */
+ public static final String PROCESS_EXEC_BASEPATH = "process.exec.basepath";
+
+ /**
+ * escheduler.env.path
+ */
+ public static final String ESCHEDULER_ENV_PATH = "escheduler.env.path";
+
+ /**
+ * escheduler.env.py
+ */
+ public static final String ESCHEDULER_ENV_PY = "escheduler.env.py";
+
+ /**
+ * resource.view.suffixs
+ */
+ public static final String RESOURCE_VIEW_SUFFIXS = "resource.view.suffixs";
+
+ /**
+ * development.state
+ */
+ public static final String DEVELOPMENT_STATE = "development.state";
+
+ /**
+ * hdfs.startup.state
+ */
+ public static final String HDFS_STARTUP_STATE = "hdfs.startup.state";
+
+ /**
+ * zookeeper quorum
+ */
+ public static final String ZOOKEEPER_QUORUM = "zookeeper.quorum";
+
+ /**
+ * MasterServer directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_MASTERS = "zookeeper.escheduler.masters";
+
+ /**
+ * WorkerServer directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_WORKERS = "zookeeper.escheduler.workers";
+
+ /**
+ * all servers directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_DEAD_SERVERS = "zookeeper.escheduler.dead.servers";
+
+ /**
+ * MasterServer lock directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_LOCK_MASTERS = "zookeeper.escheduler.lock.masters";
+
+ /**
+ * WorkerServer lock directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_LOCK_WORKERS = "zookeeper.escheduler.lock.workers";
+
+ /**
+ * MasterServer failover directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_LOCK_FAILOVER_MASTERS = "zookeeper.escheduler.lock.failover.masters";
+
+ /**
+ * WorkerServer failover directory registered in zookeeper
+ */
+ public static final String ZOOKEEPER_ESCHEDULER_LOCK_FAILOVER_WORKERS = "zookeeper.escheduler.lock.failover.workers";
+
+ /**
+ * need send warn times when master server or worker server failover
+ */
+ public static final int ESCHEDULER_WARN_TIMES_FAILOVER = 3;
+
+ /**
+ * comma ,
+ */
+ public static final String COMMA = ",";
+
+ /**
+ * COLON :
+ */
+ public static final String COLON = ":";
+
+ /**
+ * SINGLE_SLASH /
+ */
+ public static final String SINGLE_SLASH = "/";
+
+ /**
+ * DOUBLE_SLASH //
+ */
+ public static final String DOUBLE_SLASH = "//";
+
+ /**
+ * SEMICOLON ;
+ */
+ public static final String SEMICOLON = ";";
+
+ /**
+ * ZOOKEEPER_SESSION_TIMEOUT
+ */
+ public static final String ZOOKEEPER_SESSION_TIMEOUT = "zookeeper.session.timeout";
+
+ public static final String ZOOKEEPER_CONNECTION_TIMEOUT = "zookeeper.connection.timeout";
+
+ public static final String ZOOKEEPER_RETRY_SLEEP = "zookeeper.retry.sleep";
+
+ public static final String ZOOKEEPER_RETRY_MAXTIME = "zookeeper.retry.maxtime";
+
+
+ public static final String MASTER_HEARTBEAT_INTERVAL = "master.heartbeat.interval";
+
+ public static final String MASTER_EXEC_THREADS = "master.exec.threads";
+
+ public static final String MASTER_EXEC_TASK_THREADS = "master.exec.task.number";
+
+
+ public static final String MASTER_COMMIT_RETRY_TIMES = "master.task.commit.retryTimes";
+
+ public static final String MASTER_COMMIT_RETRY_INTERVAL = "master.task.commit.interval";
+
+
+ public static final String WORKER_EXEC_THREADS = "worker.exec.threads";
+
+ public static final String WORKER_HEARTBEAT_INTERVAL = "worker.heartbeat.interval";
+
+ public static final String WORKER_FETCH_TASK_NUM = "worker.fetch.task.num";
+
+ public static final String WORKER_MAX_CPULOAD_AVG = "worker.max.cpuload.avg";
+
+ public static final String WORKER_RESERVED_MEMORY = "worker.reserved.memory";
+
+ public static final String MASTER_MAX_CPULOAD_AVG = "master.max.cpuload.avg";
+
+ public static final String MASTER_RESERVED_MEMORY = "master.reserved.memory";
+
+
+ /**
+ * escheduler tasks queue
+ */
+ public static final String SCHEDULER_TASKS_QUEUE = "tasks_queue";
+
+ public static final String SCHEDULER_TASKS_KILL = "tasks_kill";
+ public static final String ZOOKEEPER_SCHEDULER_ROOT = "zookeeper.escheduler.root";
+
+ public static final String SCHEDULER_QUEUE_IMPL = "escheduler.queue.impl";
+
+ public static final String SCHEDULER_QUEUE_REDIS_IMPL = "redis";
+
+
+ /**
+ * date format of yyyy-MM-dd HH:mm:ss
+ */
+ public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+ /**
+ * date format of yyyyMMddHHmmss
+ */
+ public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+ /**
+ * http connect time out
+ */
+ public static final int HTTP_CONNECT_TIMEOUT = 60 * 1000;
+
+
+ /**
+ * http connect request time out
+ */
+ public static final int HTTP_CONNECTION_REQUEST_TIMEOUT = 60 * 1000;
+
+ /**
+ * httpclient soceket time out
+ */
+ public static final int SOCKET_TIMEOUT = 60 * 1000;
+
+ /**
+ * http header
+ */
+ public static final String HTTP_HEADER_UNKNOWN = "unKnown";
+
+ /**
+ * http X-Forwarded-For
+ */
+ public static final String HTTP_X_FORWARDED_FOR = "X-Forwarded-For";
+
+ /**
+ * http X-Real-IP
+ */
+ public static final String HTTP_X_REAL_IP = "X-Real-IP";
+
+ /**
+ * UTF-8
+ */
+ public static final String UTF_8 = "UTF-8";
+
+ /**
+ * user name regex
+ */
+ public static final Pattern REGEX_USER_NAME = Pattern.compile("[a-zA-Z0-9]{3,20}");
+
+ /**
+ * email regex
+ */
+ public static final Pattern REGEX_MAIL_NAME = Pattern.compile("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$");
+
+ /**
+ * read permission
+ */
+ public static final int READ_PERMISSION = 2 * 1;
+
+
+ /**
+ * write permission
+ */
+ public static final int WRITE_PERMISSION = 2 * 2;
+
+
+ /**
+ * execute permission
+ */
+ public static final int EXECUTE_PERMISSION = 1;
+
+ /**
+ * default admin permission
+ */
+ public static final int DEFAULT_ADMIN_PERMISSION = 7;
+
+
+ /**
+ * all permissions
+ */
+ public static final int ALL_PERMISSIONS = READ_PERMISSION | WRITE_PERMISSION | EXECUTE_PERMISSION;
+
+ /**
+ * max task timeout
+ */
+ public static final int MAX_TASK_TIMEOUT = 24 * 3600;
+
+
+ /**
+ * heartbeat threads number
+ */
+ public static final int defaulWorkerHeartbeatThreadNum = 5;
+
+ /**
+ * heartbeat interval
+ */
+ public static final int defaultWorkerHeartbeatInterval = 60;
+
+ /**
+ * worker fetch task number
+ */
+ public static final int defaultWorkerFetchTaskNum = 1;
+
+ /**
+ * worker execute threads number
+ */
+ public static final int defaultWorkerExecThreadNum = 10;
+
+ /**
+ * master cpu load
+ */
+ public static final int defaultMasterCpuLoad = Runtime.getRuntime().availableProcessors() * 2;
+
+ /**
+ * master reserved memory
+ */
+ public static final double defaultMasterReservedMemory = OSUtils.totalMemorySize() / 10;
+
+ /**
+ * worker cpu load
+ */
+ public static final int defaultWorkerCpuLoad = Runtime.getRuntime().availableProcessors() * 2;
+
+ /**
+ * worker reserved memory
+ */
+ public static final double defaultWorkerReservedMemory = OSUtils.totalMemorySize() / 10;
+
+
+ /**
+ * master execute threads number
+ */
+ public static final int defaultMasterExecThreadNum = 100;
+
+
+ /**
+ * default master concurrent task execute num
+ */
+ public static final int defaultMasterTaskExecNum = 20;
+
+ /**
+ * default log cache rows num,output when reach the number
+ */
+ public static final int defaultLogRowsNum = 4 * 16;
+
+ /**
+ * log flush interval,output when reach the interval
+ */
+ public static final int defaultLogFlushInterval = 1000;
+
+
+ /**
+ * default master heartbeat thread number
+ */
+ public static final int defaulMasterHeartbeatThreadNum = 5;
+
+
+ /**
+ * default master heartbeat interval
+ */
+ public static final int defaultMasterHeartbeatInterval = 60;
+
+ /**
+ * default master commit retry times
+ */
+ public static final int defaultMasterCommitRetryTimes = 5;
+
+
+ /**
+ * default master commit retry interval
+ */
+ public static final int defaultMasterCommitRetryInterval = 100;
+
+ /**
+ * time unit secong to minutes
+ */
+ public static final int SEC_2_MINUTES_TIME_UNIT = 60;
+
+
+ /***
+ *
+ * rpc port
+ */
+ public static final int RPC_PORT = 50051;
+
+ /**
+ * forbid running task
+ */
+ public static final String FLOWNODE_RUN_FLAG_FORBIDDEN = "FORBIDDEN";
+
+ /**
+ * task record configuration path
+ */
+ public static final String TASK_RECORD_PROPERTIES_PATH = "dao/data_source.properties";
+
+ public static final String TASK_RECORD_URL = "task.record.datasource.url";
+
+ public static final String TASK_RECORD_FLAG = "task.record.flag";
+
+ public static final String TASK_RECORD_USER = "task.record.datasource.username";
+
+ public static final String TASK_RECORD_PWD = "task.record.datasource.password";
+
+ public static final String STATUS = "status";
+
+
+ /**
+ * command parameter keys
+ */
+ public static final String CMDPARAM_RECOVER_PROCESS_ID_STRING = "ProcessInstanceId";
+
+ public static final String CMDPARAM_RECOVERY_START_NODE_STRING = "StartNodeIdList";
+
+ public static final String CMDPARAM_RECOVERY_WAITTING_THREAD = "WaittingThreadInstanceId";
+
+ public static final String CMDPARAM_SUB_PROCESS = "processInstanceId";
+
+ public static final String CMDPARAM_EMPTY_SUB_PROCESS = "0";
+
+ public static final String CMDPARAM_SUB_PROCESS_PARENT_INSTANCE_ID = "parentProcessInstanceId";
+
+ public static final String CMDPARAM_SUB_PROCESS_DEFINE_ID = "processDefinitionId";
+
+ public static final String CMDPARAM_START_NODE_NAMES = "StartNodeNameList";
+
+ /**
+ * complement data start date
+ */
+ public static final String CMDPARAM_COMPLEMENT_DATA_START_DATE = "complementStartDate";
+
+ /**
+ * complement data end date
+ */
+ public static final String CMDPARAM_COMPLEMENT_DATA_END_DATE = "complementEndDate";
+
+ /**
+ * hadoop configuration
+ */
+ public static final String HADOOP_RM_STATE_ACTIVE = "ACTIVE";
+
+ public static final String HADOOP_RM_STATE_STANDBY = "STANDBY";
+
+ public static final String HADOOP_RESOURCE_MANAGER_HTTPADDRESS_PORT = "resource.manager.httpaddress.port";
+
+
+ /**
+ * data source config
+ */
+
+ public static final String SPRING_DATASOURCE_DRIVER_CLASS_NAME = "spring.datasource.driver-class-name";
+
+ public static final String SPRING_DATASOURCE_URL = "spring.datasource.url";
+
+ public static final String SPRING_DATASOURCE_USERNAME = "spring.datasource.username";
+
+ public static final String SPRING_DATASOURCE_PASSWORD = "spring.datasource.password";
+
+ public static final String SPRING_DATASOURCE_VALIDATION_QUERY_TIMEOUT = "spring.datasource.validationQueryTimeout";
+
+ public static final String SPRING_DATASOURCE_INITIAL_SIZE = "spring.datasource.initialSize";
+
+ public static final String SPRING_DATASOURCE_MIN_IDLE = "spring.datasource.minIdle";
+
+ public static final String SPRING_DATASOURCE_MAX_ACTIVE = "spring.datasource.maxActive";
+
+ public static final String SPRING_DATASOURCE_MAX_WAIT = "spring.datasource.maxWait";
+
+ public static final String SPRING_DATASOURCE_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "spring.datasource.timeBetweenEvictionRunsMillis";
+
+ public static final String SPRING_DATASOURCE_TIME_BETWEEN_CONNECT_ERROR_MILLIS = "spring.datasource.timeBetweenConnectErrorMillis";
+
+ public static final String SPRING_DATASOURCE_MIN_EVICTABLE_IDLE_TIME_MILLIS = "spring.datasource.minEvictableIdleTimeMillis";
+
+ public static final String SPRING_DATASOURCE_VALIDATION_QUERY = "spring.datasource.validationQuery";
+
+ public static final String SPRING_DATASOURCE_TEST_WHILE_IDLE = "spring.datasource.testWhileIdle";
+
+ public static final String SPRING_DATASOURCE_TEST_ON_BORROW = "spring.datasource.testOnBorrow";
+
+ public static final String SPRING_DATASOURCE_TEST_ON_RETURN = "spring.datasource.testOnReturn";
+
+ public static final String SPRING_DATASOURCE_POOL_PREPARED_STATEMENTS = "spring.datasource.poolPreparedStatements";
+
+ public static final String SPRING_DATASOURCE_DEFAULT_AUTO_COMMIT = "spring.datasource.defaultAutoCommit";
+
+ public static final String SPRING_DATASOURCE_KEEP_ALIVE = "spring.datasource.keepAlive";
+
+ public static final String SPRING_DATASOURCE_MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE = "spring.datasource.maxPoolPreparedStatementPerConnectionSize";
+
+ public static final String DEVELOPMENT = "development";
+
+ public static final String QUARTZ_PROPERTIES_PATH = "quartz.properties";
+
+ /**
+ * sleep time
+ */
+ public static final int SLEEP_TIME_MILLIS = 1000;
+
+ /**
+ * heartbeat for zk info length
+ */
+ public static final int HEARTBEAT_FOR_ZOOKEEPER_INFO_LENGTH = 6;
+
+
+ /**
+ * hadoop params constant
+ */
+ /**
+ * jar
+ */
+ public static final String JAR = "jar";
+
+ /**
+ * hadoop
+ */
+ public static final String HADOOP = "hadoop";
+
+ /**
+ * -D parameter
+ */
+ public static final String D = "-D";
+
+ /**
+ * -D mapreduce.job.queuename=ququename
+ */
+ public static final String MR_QUEUE = "mapreduce.job.queuename";
+
+
+ /**
+ * jdbc class name
+ */
+ /**
+ * mysql
+ */
+ public static final String JDBC_MYSQL_CLASS_NAME = "com.mysql.jdbc.Driver";
+
+ /**
+ * postgresql
+ */
+ public static final String JDBC_POSTGRESQL_CLASS_NAME = "org.postgresql.Driver";
+
+ /**
+ * postgresql
+ */
+ public static final String JDBC_HIVE_CLASS_NAME = "org.apache.hive.jdbc.HiveDriver";
+
+ /**
+ * postgresql
+ */
+ public static final String JDBC_SPARK_CLASS_NAME = "org.apache.hive.jdbc.HiveDriver";
+
+
+ /**
+ * spark params constant
+ */
+ public static final String MASTER = "--master";
+
+ public static final String DEPLOY_MODE = "--deploy-mode";
+
+ /**
+ * --class CLASS_NAME
+ */
+ public static final String CLASS = "--class";
+
+ /**
+ * --driver-cores NUM
+ */
+ public static final String DRIVER_CORES = "--driver-cores";
+
+ /**
+ * --driver-memory MEM
+ */
+ public static final String DRIVER_MEMORY = "--driver-memory";
+
+ /**
+ * --num-executors NUM
+ */
+ public static final String NUM_EXECUTORS = "--num-executors";
+
+ /**
+ * --executor-cores NUM
+ */
+ public static final String EXECUTOR_CORES = "--executor-cores";
+
+ /**
+ * --executor-memory MEM
+ */
+ public static final String EXECUTOR_MEMORY = "--executor-memory";
+
+
+ /**
+ * --queue QUEUE
+ */
+ public static final String SPARK_QUEUE = "--queue";
+
+
+ /**
+ * exit code success
+ */
+ public static final int EXIT_CODE_SUCCESS = 0;
+
+ /**
+ * exit code kill
+ */
+ public static final int EXIT_CODE_KILL = 137;
+
+ /**
+ * exit code failure
+ */
+ public static final int EXIT_CODE_FAILURE = -1;
+
+ /**
+ * date format of yyyyMMdd
+ */
+ public static final String PARAMETER_FORMAT_DATE = "yyyyMMdd";
+
+ /**
+ * date format of yyyyMMddHHmmss
+ */
+ public static final String PARAMETER_FORMAT_TIME = "yyyyMMddHHmmss";
+
+ /**
+ * system date(yyyyMMddHHmmss)
+ */
+ public static final String PARAMETER_DATETIME = "system.datetime";
+
+ /**
+ * system date(yyyymmdd) today
+ */
+ public static final String PARAMETER_CURRENT_DATE = "system.biz.curdate";
+
+ /**
+ * system date(yyyymmdd) yesterday
+ */
+ public static final String PARAMETER_BUSINESS_DATE = "system.biz.date";
+
+ /**
+ * ACCEPTED
+ */
+ public static final String ACCEPTED = "ACCEPTED";
+
+ /**
+ * SUCCEEDED
+ */
+ public static final String SUCCEEDED = "SUCCEEDED";
+ /**
+ * NEW
+ */
+ public static final String NEW = "NEW";
+ /**
+ * NEW_SAVING
+ */
+ public static final String NEW_SAVING = "NEW_SAVING";
+ /**
+ * SUBMITTED
+ */
+ public static final String SUBMITTED = "SUBMITTED";
+ /**
+ * FAILED
+ */
+ public static final String FAILED = "FAILED";
+ /**
+ * KILLED
+ */
+ public static final String KILLED = "KILLED";
+ /**
+ * RUNNING
+ */
+ public static final String RUNNING = "RUNNING";
+ /**
+ * underline "_"
+ */
+ public static final String UNDERLINE = "_";
+ /**
+ * quartz job prifix
+ */
+ public static final String QUARTZ_JOB_PRIFIX = "job";
+ /**
+ * quartz job group prifix
+ */
+ public static final String QUARTZ_JOB_GROUP_PRIFIX = "jobgroup";
+ /**
+ * projectId
+ */
+ public static final String PROJECT_ID = "projectId";
+ /**
+ * processId
+ */
+ public static final String SCHEDULE_ID = "scheduleId";
+ /**
+ * schedule
+ */
+ public static final String SCHEDULE = "schedule";
+ /**
+ * application regex
+ */
+ public static final String APPLICATION_REGEX = "application_\\d+_\\d+";
+ public static final String PID = "pid";
+ /**
+ * month_begin
+ */
+ public static final String MONTH_BEGIN = "month_begin";
+ /**
+ * add_months
+ */
+ public static final String ADD_MONTHS = "add_months";
+ /**
+ * month_end
+ */
+ public static final String MONTH_END = "month_end";
+ /**
+ * week_begin
+ */
+ public static final String WEEK_BEGIN = "week_begin";
+ /**
+ * week_end
+ */
+ public static final String WEEK_END = "week_end";
+ /**
+ * timestamp
+ */
+ public static final String TIMESTAMP = "timestamp";
+ public static final char SUBTRACT_CHAR = '-';
+ public static final char ADD_CHAR = '+';
+ public static final char MULTIPLY_CHAR = '*';
+ public static final char DIVISION_CHAR = '/';
+ public static final char LEFT_BRACE_CHAR = '(';
+ public static final char RIGHT_BRACE_CHAR = ')';
+ public static final String ADD_STRING = "+";
+ public static final String MULTIPLY_STRING = "*";
+ public static final String DIVISION_STRING = "/";
+ public static final String LEFT_BRACE_STRING = "(";
+ public static final char P = 'P';
+ public static final char N = 'N';
+ public static final String SUBTRACT_STRING = "-";
+ public static final String GLOBAL_PARAMS = "globalParams";
+ public static final String LOCAL_PARAMS = "localParams";
+ public static final String PROCESS_INSTANCE_STATE = "processInstanceState";
+ public static final String TASK_LIST = "taskList";
+ public static final String RWXR_XR_X = "rwxr-xr-x";
+
+ /**
+ * master/worker server use for zk
+ */
+ public static final String MASTER_PREFIX = "master";
+ public static final String WORKER_PREFIX = "worker";
+ public static final String DELETE_ZK_OP = "delete";
+ public static final String ADD_ZK_OP = "add";
+ public static final String ALIAS = "alias";
+ public static final String CONTENT = "content";
+ public static final String DEPENDENT_SPLIT = ":||";
+ public static final String DEPENDENT_ALL = "ALL";
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/IStoppable.java b/escheduler-common/src/main/java/cn/escheduler/common/IStoppable.java
new file mode 100644
index 0000000000..872d63c1d8
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/IStoppable.java
@@ -0,0 +1,29 @@
+/*
+ * 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 cn.escheduler.common;
+
+/**
+ * server stop interface.
+ */
+public interface IStoppable {
+ /**
+ * Stop this service.
+ * @param cause why stopping
+ */
+ public void stop(String cause);
+
+}
\ No newline at end of file
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertStatus.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertStatus.java
new file mode 100644
index 0000000000..6da093ed9a
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertStatus.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * alert status
+ */
+public enum AlertStatus {
+ /**
+ * 0 waiting executed; 1 execute successfully,2 execute failed
+ */
+ WAIT_EXECUTION,EXECUTION_SUCCESS,EXECUTION_FAILURE
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertType.java
new file mode 100644
index 0000000000..1acf2db791
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/AlertType.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * warning message notification method
+ */
+public enum AlertType {
+ /**
+ * 0 email; 1 SMS
+ */
+ EMAIL,SMS
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/CommandType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/CommandType.java
new file mode 100644
index 0000000000..3f83510819
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/CommandType.java
@@ -0,0 +1,40 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * command types
+ */
+public enum CommandType {
+
+ /**
+ * command types
+ * 0 start a new process
+ * 1 start a new process from current nodes
+ * 2 recover tolerance fault work flow
+ * 3 start process from paused task nodes
+ * 4 start process from failure task nodes
+ * 5 complement data
+ * 6 start a new process from scheduler
+ * 7 repeat running a work flow
+ * 8 pause a process
+ * 9 stop a process
+ * 10 recover waiting thread
+ */
+ START_PROCESS, START_CURRENT_TASK_PROCESS, RECOVER_TOLERANCE_FAULT_PROCESS, RECOVER_SUSPENDED_PROCESS,
+ START_FAILURE_TASK_PROCESS,COMPLEMENT_DATA,SCHEDULER, REPEAT_RUNNING,PAUSE,STOP,RECOVER_WAITTING_THREAD;
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/CycleEnum.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/CycleEnum.java
new file mode 100644
index 0000000000..48a9a5c163
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/CycleEnum.java
@@ -0,0 +1,28 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * cycle enums
+ */
+public enum CycleEnum {
+ /**
+ * 0 minute; 1 hour; 2 day; 3 week; 4 month; 5 year;
+ */
+ MINUTE, HOUR, DAY, WEEK, MONTH, YEAR
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/DataType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/DataType.java
new file mode 100644
index 0000000000..0c0e3f323e
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/DataType.java
@@ -0,0 +1,35 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * data types in user define parameter
+ */
+public enum DataType {
+ /**
+ * 0 string
+ * 1 integer
+ * 2 long
+ * 3 float
+ * 4 double
+ * 5 date, "YYYY-MM-DD"
+ * 6 time, "HH:MM:SS"
+ * 7 time stamp
+ * 8 Boolean
+ */
+ VARCHAR,INTEGER,LONG,FLOAT,DOUBLE,DATE,TIME,TIMESTAMP,BOOLEAN
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/DbType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/DbType.java
new file mode 100644
index 0000000000..70f767444f
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/DbType.java
@@ -0,0 +1,30 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * data base types
+ */
+public enum DbType {
+ /**
+ * 0 mysql
+ * 1 postgresql
+ * 2 hive
+ * 3 spark
+ */
+ MYSQL, POSTGRESQL, HIVE, SPARK
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/DependResult.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependResult.java
new file mode 100644
index 0000000000..7a9a9ac7c3
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependResult.java
@@ -0,0 +1,31 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * depend result
+ */
+public enum DependResult {
+
+
+ /**
+ * 0 success
+ * 1 waiting
+ * 2 failed
+ */
+ SUCCESS, WAITING, FAILED
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/DependStrategy.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependStrategy.java
new file mode 100644
index 0000000000..c485351462
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependStrategy.java
@@ -0,0 +1,29 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * depend strategy
+ */
+public enum DependStrategy {
+
+ /**
+ * 0 none,1 all success 2 all failed 3 one success 4 one failed
+ */
+ NONE, ALL_SUCCESS, ALL_FAILED, ONE_SUCCESS, ONE_FAILED
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/DependentRelation.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependentRelation.java
new file mode 100644
index 0000000000..f95059f201
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/DependentRelation.java
@@ -0,0 +1,25 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * dependent relation: and or
+ */
+public enum DependentRelation {
+
+ AND,OR;
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/Direct.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/Direct.java
new file mode 100644
index 0000000000..c7d8afc006
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/Direct.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * parameter of stored procedure
+ */
+public enum Direct {
+ /**
+ * 0 in; 1 out;
+ */
+ IN,OUT
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/ExecutionStatus.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/ExecutionStatus.java
new file mode 100644
index 0000000000..e2a727636d
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/ExecutionStatus.java
@@ -0,0 +1,101 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+
+/**
+ * runing status for work flow and task nodes
+ *
+ */
+public enum ExecutionStatus {
+
+ /**
+ * status:
+ * 0 submit success
+ * 1 running
+ * 2 ready pause
+ * 3 pause
+ * 4 ready stop
+ * 5 stop
+ * 6 failure
+ * 7 success
+ * 8 need fault tolerance
+ * 9 kill
+ * 10 waiting thread
+ * 11 waiting depend node complete
+ */
+ SUBMITTED_SUCCESS,RUNNING_EXEUTION,READY_PAUSE,PAUSE,READY_STOP,STOP,FAILURE,SUCCESS,
+ NEED_FAULT_TOLERANCE,KILL,WAITTING_THREAD,WAITTING_DEPEND;
+
+
+ /**
+ * status is success
+ * @return
+ */
+ public boolean typeIsSuccess(){
+ return this == SUCCESS;
+ }
+
+ /**
+ * status is failure
+ * @return
+ */
+ public boolean typeIsFailure(){
+ return this == FAILURE || this == NEED_FAULT_TOLERANCE;
+ }
+
+ /**
+ * status is finished
+ * @return
+ */
+ public boolean typeIsFinished(){
+
+ return typeIsSuccess() || typeIsFailure() || typeIsCancel() || typeIsPause()
+ || typeIsWaittingThread();
+ }
+
+ /**
+ * status is waiting thread
+ * @return
+ */
+ public boolean typeIsWaittingThread(){
+ return this == WAITTING_THREAD;
+ }
+
+ /**
+ * status is pause
+ * @return
+ */
+ public boolean typeIsPause(){
+ return this == PAUSE;
+ }
+
+ /**
+ * status is running
+ * @return
+ */
+ public boolean typeIsRunning(){
+ return this == RUNNING_EXEUTION || this == WAITTING_DEPEND;
+ }
+
+ /**
+ * status is cancel
+ */
+ public boolean typeIsCancel(){ return this == KILL || this == STOP ;}
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/FailureStrategy.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/FailureStrategy.java
new file mode 100644
index 0000000000..3862d41537
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/FailureStrategy.java
@@ -0,0 +1,30 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * failure policy when some task node failed.
+ */
+public enum FailureStrategy {
+
+ /**
+ * 0 ending process when some tasks failed.
+ * 1 continue running when some tasks failed.
+ **/
+ END, CONTINUE;
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/Flag.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/Flag.java
new file mode 100644
index 0000000000..25af24ff68
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/Flag.java
@@ -0,0 +1,33 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * have_script
+ * have_file
+ * can_retry
+ * have_arr_variables
+ * have_map_variables
+ * have_alert
+ */
+public enum Flag {
+ /**
+ * 0 no
+ * 1 yes
+ */
+ NO,YES
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/Priority.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/Priority.java
new file mode 100644
index 0000000000..3aa1f22539
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/Priority.java
@@ -0,0 +1,31 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * define process and task priority
+ */
+public enum Priority {
+ /**
+ * 0 highest priority
+ * 1 higher priority
+ * 2 medium priority
+ * 3 lower priority
+ * 4 lowest priority
+ */
+ HIGHEST,HIGH,MEDIUM,LOW,LOWEST
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/ProgramType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/ProgramType.java
new file mode 100644
index 0000000000..1754f652f8
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/ProgramType.java
@@ -0,0 +1,30 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+
+/**
+ * support program types
+ */
+public enum ProgramType {
+ /**
+ * 0 JAVA,1 SCALA,2 PYTHON
+ */
+ JAVA,
+ SCALA,
+ PYTHON
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/ReleaseState.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/ReleaseState.java
new file mode 100644
index 0000000000..47a5680de6
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/ReleaseState.java
@@ -0,0 +1,40 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * process define release state
+ */
+public enum ReleaseState {
+
+ /**
+ * 0 offline
+ * 1 on line
+ */
+ OFFLINE,ONLINE;
+
+
+ public static ReleaseState getEnum(int value){
+ for (ReleaseState e:ReleaseState.values()) {
+ if(e.ordinal() == value) {
+ return e;
+ }
+ }
+ //For values out of enum scope
+ return null;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/ResourceType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/ResourceType.java
new file mode 100644
index 0000000000..2f1dcdde65
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/ResourceType.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * resource type
+ */
+public enum ResourceType {
+ /**
+ * 0 file, 1 udf
+ */
+ FILE,UDF
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/RunMode.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/RunMode.java
new file mode 100644
index 0000000000..09a13ef8d3
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/RunMode.java
@@ -0,0 +1,28 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * complement data run mode
+ */
+public enum RunMode {
+ /**
+ * 0 serial run
+ * 1 parallel run
+ * */
+ RUN_MODE_SERIAL, RUN_MODE_PARALLEL
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/SelfDependStrategy.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/SelfDependStrategy.java
new file mode 100644
index 0000000000..c5935bdc6e
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/SelfDependStrategy.java
@@ -0,0 +1,29 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * self depency strategy
+ */
+public enum SelfDependStrategy {
+
+ /**
+ * 0 donot depend the last cycle;
+ * 1 depend the last cycle
+ **/
+ NO_DEP_PRE, DEP_PRE
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/ShowType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/ShowType.java
new file mode 100644
index 0000000000..d7ee0e51af
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/ShowType.java
@@ -0,0 +1,34 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * show type for email
+ */
+public enum ShowType {
+ /**
+ * 0 TABLE;
+ * 1 TEXT;
+ * 2 attachment;
+ * 3 TABLE+attachment;
+ */
+ TABLE,
+ TEXT,
+ ATTACHMENT,
+ TABLEATTACHMENT
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskDependType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskDependType.java
new file mode 100644
index 0000000000..9d6a069592
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskDependType.java
@@ -0,0 +1,30 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * task node depend type
+ */
+public enum TaskDependType {
+ /**
+ * 0 run current tasks only
+ * 1 run current tasks and previous tasks
+ * 2 run current tasks and the other tasks that depend on current tasks;
+ */
+ TASK_ONLY, TASK_PRE, TASK_POST;
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskStateType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskStateType.java
new file mode 100644
index 0000000000..678e8e5be8
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskStateType.java
@@ -0,0 +1,67 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * type of task state
+ */
+public enum TaskStateType {
+ /**
+ * 0 waiting running
+ * 1 running
+ * 2 finish
+ * 3 failed
+ * 4 success
+ */
+ WAITTING, RUNNING, FINISH, FAILED, SUCCESS;
+
+
+ /**
+ * convert task state to execute status integer array ;
+ * @param taskStateType
+ * @return
+ */
+ public static int[] convert2ExecutStatusIntArray(TaskStateType taskStateType){
+
+ switch (taskStateType){
+ case SUCCESS:
+ return new int[]{ExecutionStatus.SUCCESS.ordinal()};
+ case FAILED:
+ return new int[]{
+ ExecutionStatus.FAILURE.ordinal(),
+ ExecutionStatus.NEED_FAULT_TOLERANCE.ordinal()};
+ case FINISH:
+ return new int[]{
+ ExecutionStatus.PAUSE.ordinal(),
+ ExecutionStatus.STOP.ordinal()
+ };
+ case RUNNING:
+ return new int[]{ExecutionStatus.SUBMITTED_SUCCESS.ordinal(),
+ ExecutionStatus.RUNNING_EXEUTION.ordinal(),
+ ExecutionStatus.READY_PAUSE.ordinal(),
+ ExecutionStatus.READY_STOP.ordinal()};
+ case WAITTING:
+ return new int[]{
+ ExecutionStatus.SUBMITTED_SUCCESS.ordinal()
+ };
+ default:
+ break;
+ }
+ return null;
+ }
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskTimeoutStrategy.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskTimeoutStrategy.java
new file mode 100644
index 0000000000..c454c98b10
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskTimeoutStrategy.java
@@ -0,0 +1,29 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * task timeout strategy
+ */
+public enum TaskTimeoutStrategy {
+ /**
+ * 0 warn
+ * 1 failed
+ * 2 warn+failed
+ */
+ WARN, FAILED, WARNFAILED
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
new file mode 100644
index 0000000000..64c2e951eb
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
@@ -0,0 +1,34 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * task node type
+ */
+public enum TaskType {
+ /**
+ * 0 SHELL
+ * 1 SQL
+ * 2 SUB_PROCESS
+ * 3 PROCEDURE
+ * 4 MR
+ * 5 SPARK
+ * 6 PYTHON
+ * 7 DEPENDENT
+ */
+ SHELL,SQL, SUB_PROCESS,PROCEDURE,MR,SPARK,PYTHON,DEPENDENT
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/UdfType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/UdfType.java
new file mode 100644
index 0000000000..7114b52f50
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/UdfType.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * UDF type
+ */
+public enum UdfType {
+ /**
+ * 0 hive; 1 spark
+ */
+ HIVE, SPARK
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/UserType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/UserType.java
new file mode 100644
index 0000000000..7f36694295
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/UserType.java
@@ -0,0 +1,28 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * user type
+ */
+public enum UserType {
+ /**
+ * 0 admin user; 1 general user
+ */
+ ADMIN_USER,
+ GENERAL_USER
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/enums/WarningType.java b/escheduler-common/src/main/java/cn/escheduler/common/enums/WarningType.java
new file mode 100644
index 0000000000..9c8e5b3c12
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/enums/WarningType.java
@@ -0,0 +1,31 @@
+/*
+ * 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 cn.escheduler.common.enums;
+
+/**
+ * types for whether to send warning when process ending;
+ */
+public enum WarningType {
+ /**
+ * 0 do not send warning;
+ * 1 send if process success;
+ * 2 send if process failed;
+ * 3 send if process ending;
+ */
+ NONE, SUCCESS, FAILURE, ALL;
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/graph/DAG.java b/escheduler-common/src/main/java/cn/escheduler/common/graph/DAG.java
new file mode 100644
index 0000000000..43fbb26e5a
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/graph/DAG.java
@@ -0,0 +1,519 @@
+/*
+ * 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 cn.escheduler.common.graph;
+
+import cn.escheduler.common.utils.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * analysis of DAG
+ * Node: node
+ * NodeInfo:node description information
+ * EdgeInfo: edge description information
+ */
+public class DAG {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(DAG.class);
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+ /**
+ * node map, key is node, value is node information
+ */
+ private volatile Map nodesMap;
+
+ /**
+ * edge map. key is node of origin;value is Map with key for destination node and value for edge
+ */
+ private volatile Map> edgesMap;
+
+ /**
+ * reversed edge set,key is node of destination, value is Map with key for origin node and value for edge
+ */
+ private volatile Map> reverseEdgesMap;
+
+
+ public DAG() {
+ nodesMap = new HashMap<>();
+ edgesMap = new HashMap<>();
+ reverseEdgesMap = new HashMap<>();
+ }
+
+
+ /**
+ * add node information
+ *
+ * @param node node
+ * @param nodeInfo node information
+ */
+ public void addNode(Node node, NodeInfo nodeInfo) {
+ lock.writeLock().lock();
+
+ try{
+ nodesMap.put(node, nodeInfo);
+ }finally {
+ lock.writeLock().unlock();
+ }
+
+ }
+
+
+ /**
+ * add edge
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @return The result of adding an edge. returns false if the DAG result is a ring result
+ */
+ public boolean addEdge(Node fromNode, Node toNode) {
+ return addEdge(fromNode, toNode, false);
+ }
+
+
+ /**
+ * add edge
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @param createNode whether the node needs to be created if it does not exist
+ * @return The result of adding an edge. returns false if the DAG result is a ring result
+ */
+ private boolean addEdge(Node fromNode, Node toNode, boolean createNode) {
+ return addEdge(fromNode, toNode, null, createNode);
+ }
+
+
+ /**
+ * add edge
+ *
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @param edge edge description
+ * @param createNode whether the node needs to be created if it does not exist
+ * @return The result of adding an edge. returns false if the DAG result is a ring result
+ */
+ public boolean addEdge(Node fromNode, Node toNode, EdgeInfo edge, boolean createNode) {
+ lock.writeLock().lock();
+
+ try{
+
+ // Whether an edge can be successfully added(fromNode -> toNode)
+ if (!isLegalAddEdge(fromNode, toNode, createNode)) {
+ logger.error("serious error: add edge({} -> {}) is invalid, cause cycle!", fromNode, toNode);
+ return false;
+ }
+
+ addNodeIfAbsent(fromNode, null);
+ addNodeIfAbsent(toNode, null);
+
+ addEdge(fromNode, toNode, edge, edgesMap);
+ addEdge(toNode, fromNode, edge, reverseEdgesMap);
+
+ return true;
+ }finally {
+ lock.writeLock().unlock();
+ }
+
+ }
+
+
+ /**
+ * whether this node is contained
+ *
+ * @param node node
+ * @return
+ */
+ public boolean containsNode(Node node) {
+ lock.readLock().lock();
+
+ try{
+ return nodesMap.containsKey(node);
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * whether this edge is contained
+ *
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @return
+ */
+ public boolean containsEdge(Node fromNode, Node toNode) {
+ lock.readLock().lock();
+ try{
+ Map endEdges = edgesMap.get(fromNode);
+ if (endEdges == null) {
+ return false;
+ }
+
+ return endEdges.containsKey(toNode);
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * get node description
+ *
+ * @param node node
+ * @return
+ */
+ public NodeInfo getNode(Node node) {
+ lock.readLock().lock();
+
+ try{
+ return nodesMap.get(node);
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * Get the number of nodes
+ *
+ * @return
+ */
+ public int getNodesCount() {
+ lock.readLock().lock();
+
+ try{
+ return nodesMap.size();
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ /**
+ * Get the number of edges
+ *
+ * @return
+ */
+ public int getEdgesCount() {
+ lock.readLock().lock();
+ try{
+ int count = 0;
+
+ for (Map.Entry> entry : edgesMap.entrySet()) {
+ count += entry.getValue().size();
+ }
+
+ return count;
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * get the start node of DAG
+ *
+ * @return
+ */
+ public Collection getBeginNode() {
+ lock.readLock().lock();
+
+ try{
+ return CollectionUtils.subtract(nodesMap.keySet(), reverseEdgesMap.keySet());
+ }finally {
+ lock.readLock().unlock();
+ }
+
+ }
+
+
+ /**
+ * get the end node of DAG
+ *
+ * @return
+ */
+ public Collection getEndNode() {
+
+ lock.readLock().lock();
+
+ try{
+ return CollectionUtils.subtract(nodesMap.keySet(), edgesMap.keySet());
+ }finally {
+ lock.readLock().unlock();
+ }
+
+ }
+
+
+ /**
+ * Gets all previous nodes of the node
+ *
+ * @param node node id to be calculated
+ * @return
+ */
+ public Set getPreviousNodes(Node node) {
+ lock.readLock().lock();
+
+ try{
+ return getNeighborNodes(node, reverseEdgesMap);
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * Get all subsequent nodes of the node
+ *
+ * @param node node id to be calculated
+ * @return
+ */
+ public Set getSubsequentNodes(Node node) {
+ lock.readLock().lock();
+
+ try{
+ return getNeighborNodes(node, edgesMap);
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * Gets the degree of entry of the node
+ *
+ * @param node node id
+ * @return
+ */
+ public int getIndegree(Node node) {
+ lock.readLock().lock();
+
+ try{
+ return getPreviousNodes(node).size();
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * whether the graph has a ring
+ *
+ * @return true if has cycle, else return false.
+ */
+ public boolean hasCycle() {
+ lock.readLock().lock();
+ try{
+ return !topologicalSortImpl().getKey();
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * Only DAG has a topological sort
+ * @return topologically sorted results, returns false if the DAG result is a ring result
+ * @throws Exception
+ */
+ public List topologicalSort() throws Exception {
+ lock.readLock().lock();
+
+ try{
+ Map.Entry> entry = topologicalSortImpl();
+
+ if (entry.getKey()) {
+ return entry.getValue();
+ }
+
+ throw new Exception("serious error: graph has cycle ! ");
+ }finally {
+ lock.readLock().unlock();
+ }
+ }
+
+
+ /**
+ * if tho node does not exist,add this node
+ *
+ * @param node node
+ * @param nodeInfo node information
+ */
+ private void addNodeIfAbsent(Node node, NodeInfo nodeInfo) {
+ if (!containsNode(node)) {
+ addNode(node, nodeInfo);
+ }
+ }
+
+
+ /**
+ * add edge
+ *
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @param edge edge description
+ * @param edges edge set
+ */
+ private void addEdge(Node fromNode, Node toNode, EdgeInfo edge, Map> edges) {
+ edges.putIfAbsent(fromNode, new HashMap<>());
+ Map toNodeEdges = edges.get(fromNode);
+ toNodeEdges.put(toNode, edge);
+ }
+
+
+ /**
+ * Whether an edge can be successfully added(fromNode -> toNode)
+ * need to determine whether the DAG has cycle
+ *
+ * @param fromNode node of origin
+ * @param toNode node of destination
+ * @param createNode whether to create a node
+ * @return
+ */
+ private boolean isLegalAddEdge(Node fromNode, Node toNode, boolean createNode) {
+ if (fromNode.equals(toNode)) {
+ logger.error("edge fromNode({}) can't equals toNode({})", fromNode, toNode);
+ return false;
+ }
+
+ if (!createNode) {
+ if (!containsNode(fromNode) || !containsNode(toNode)){
+ logger.error("edge fromNode({}) or toNode({}) is not in vertices map", fromNode, toNode);
+ return false;
+ }
+ }
+
+ // Whether an edge can be successfully added(fromNode -> toNode),need to determine whether the DAG has cycle!
+ int verticesCount = getNodesCount();
+
+ Queue queue = new LinkedList<>();
+
+ queue.add(toNode);
+
+ // if DAG doesn't find fromNode, it's not has cycle!
+ while (!queue.isEmpty() && (--verticesCount > 0)) {
+ Node key = queue.poll();
+
+ for (Node subsequentNode : getSubsequentNodes(key)) {
+ if (subsequentNode.equals(fromNode)) {
+ return false;
+ }
+
+ queue.add(subsequentNode);
+ }
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Get all neighbor nodes of the node
+ *
+ * @param node Node id to be calculated
+ * @param edges neighbor edge information
+ * @return
+ */
+ private Set getNeighborNodes(Node node, final Map> edges) {
+ final Map neighborEdges = edges.get(node);
+
+ if (neighborEdges == null) {
+ return Collections.EMPTY_MAP.keySet();
+ }
+
+ return neighborEdges.keySet();
+ }
+
+
+
+ /**
+ * Determine whether there are ring and topological sorting results
+ *
+ * Directed acyclic graph (DAG) has topological ordering
+ * Breadth First Search:
+ * 1、Traversal of all the vertices in the graph, the degree of entry is 0 vertex into the queue
+ * 2、Poll a vertex in the queue to update its adjacency (minus 1) and queue the adjacency if it is 0 after minus 1
+ * 3、Do step 2 until the queue is empty
+ * If you cannot traverse all the nodes, it means that the current graph is not a directed acyclic graph.
+ * There is no topological sort.
+ *
+ *
+ * @return key Returns the state
+ * if success (acyclic) is true, failure (acyclic) is looped,
+ * and value (possibly one of the topological sort results)
+ */
+ private Map.Entry> topologicalSortImpl() {
+ // node queue with degree of entry 0
+ Queue zeroIndegreeNodeQueue = new LinkedList<>();
+ // save result
+ List topoResultList = new ArrayList<>();
+ // save the node whose degree is not 0
+ Map notZeroIndegreeNodeMap = new HashMap<>();
+
+ // Scan all the vertices and push vertexs with an entry degree of 0 to queue
+ for (Map.Entry vertices : nodesMap.entrySet()) {
+ Node node = vertices.getKey();
+ int inDegree = getIndegree(node);
+
+ if (inDegree == 0) {
+ zeroIndegreeNodeQueue.add(node);
+ topoResultList.add(node);
+ } else {
+ notZeroIndegreeNodeMap.put(node, inDegree);
+ }
+ }
+
+ /**
+ * After scanning, there is no node with 0 degree of entry,
+ * indicating that there is a ring, and return directly
+ */
+ if(zeroIndegreeNodeQueue.isEmpty()){
+ return new AbstractMap.SimpleEntry(false, topoResultList);
+ }
+
+ // The topology algorithm is used to delete nodes with 0 degree of entry and its associated edges
+ while (!zeroIndegreeNodeQueue.isEmpty()) {
+ Node v = zeroIndegreeNodeQueue.poll();
+ // Get the neighbor node
+ Set subsequentNodes = getSubsequentNodes(v);
+
+ for (Node subsequentNode : subsequentNodes) {
+
+ Integer degree = notZeroIndegreeNodeMap.get(subsequentNode);
+
+ if(--degree == 0){
+ topoResultList.add(subsequentNode);
+ zeroIndegreeNodeQueue.add(subsequentNode);
+ notZeroIndegreeNodeMap.remove(subsequentNode);
+ }else{
+ notZeroIndegreeNodeMap.put(subsequentNode, degree);
+ }
+
+ }
+ }
+
+ // if notZeroIndegreeNodeMap is empty,there is no ring!
+ AbstractMap.SimpleEntry resultMap = new AbstractMap.SimpleEntry(notZeroIndegreeNodeMap.size() == 0 , topoResultList);
+ return resultMap;
+
+ }
+
+}
+
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/BaseDataSource.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/BaseDataSource.java
new file mode 100644
index 0000000000..af0624091a
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/BaseDataSource.java
@@ -0,0 +1,100 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+/**
+ * data source base class
+ */
+public abstract class BaseDataSource {
+ /**
+ * user name
+ */
+ private String user;
+
+ /**
+ * user password
+ */
+ private String password;
+
+ /**
+ * data source address
+ */
+ private String address;
+
+ /**
+ * database name
+ */
+ private String database;
+
+ /**
+ * other connection parameters for the data source
+ */
+ private String other;
+
+ /**
+ * test whether the data source can be connected successfully
+ * @throws Exception
+ */
+ public abstract void isConnectable() throws Exception;
+
+ /**
+ * gets the JDBC url for the data source connection
+ * @return
+ */
+ public abstract String getJdbcUrl();
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getDatabase() {
+ return database;
+ }
+
+ public void setDatabase(String database) {
+ this.database = database;
+ }
+
+ public String getOther() {
+ return other;
+ }
+
+ public void setOther(String other) {
+ this.other = other;
+ }
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/DataSourceFactory.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/DataSourceFactory.java
new file mode 100644
index 0000000000..06858fade3
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/DataSourceFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+import cn.escheduler.common.enums.DbType;
+import cn.escheduler.common.utils.JSONUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * produce datasource in this custom defined datasource factory.
+ */
+public class DataSourceFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(DataSourceFactory.class);
+
+ public static BaseDataSource getDatasource(DbType dbType, String parameter) {
+ try {
+ switch (dbType) {
+ case MYSQL:
+ return JSONUtils.parseObject(parameter, MySQLDataSource.class);
+ case POSTGRESQL:
+ return JSONUtils.parseObject(parameter, PostgreDataSource.class);
+ case HIVE:
+ return JSONUtils.parseObject(parameter, HiveDataSource.class);
+ case SPARK:
+ return JSONUtils.parseObject(parameter, SparkDataSource.class);
+ default:
+ return null;
+ }
+ } catch (Exception e) {
+ logger.error("Get datasource object error", e);
+ return null;
+ }
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/HiveDataSource.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/HiveDataSource.java
new file mode 100644
index 0000000000..28e37991d7
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/HiveDataSource.java
@@ -0,0 +1,77 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * data source of hive
+ */
+public class HiveDataSource extends BaseDataSource {
+
+ private static final Logger logger = LoggerFactory.getLogger(HiveDataSource.class);
+
+
+ /**
+ * gets the JDBC url for the data source connection
+ * @return
+ */
+ @Override
+ public String getJdbcUrl() {
+ String jdbcUrl = getAddress();
+ if (jdbcUrl.lastIndexOf("/") != (jdbcUrl.length() - 1)) {
+ jdbcUrl += "/";
+ }
+
+ jdbcUrl += getDatabase();
+
+ if (StringUtils.isNotEmpty(getOther())) {
+ jdbcUrl += ";" + getOther();
+ }
+
+ return jdbcUrl;
+ }
+
+ /**
+ * test whether the data source can be connected successfully
+ * @throws Exception
+ */
+ @Override
+ public void isConnectable() throws Exception {
+ Connection con = null;
+ try {
+ Class.forName("org.apache.hive.jdbc.HiveDriver");
+ con = DriverManager.getConnection(getJdbcUrl(), getUser(), "");
+ } finally {
+ if (con != null) {
+ try {
+ con.close();
+ } catch (SQLException e) {
+ logger.error("Postgre datasource try conn close conn error", e);
+ throw e;
+ }
+ }
+ }
+
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/MySQLDataSource.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/MySQLDataSource.java
new file mode 100644
index 0000000000..62d419e04c
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/MySQLDataSource.java
@@ -0,0 +1,73 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * data source of mySQL
+ */
+public class MySQLDataSource extends BaseDataSource {
+
+ private static final Logger logger = LoggerFactory.getLogger(MySQLDataSource.class);
+
+ /**
+ * gets the JDBC url for the data source connection
+ * @return
+ */
+ @Override
+ public String getJdbcUrl() {
+ String address = getAddress();
+ if (address.lastIndexOf("/") != (address.length() - 1)) {
+ address += "/";
+ }
+ String jdbcUrl = address + getDatabase();
+ if (StringUtils.isNotEmpty(getOther())) {
+ jdbcUrl += "?" + getOther();
+ }
+ return jdbcUrl;
+ }
+
+ /**
+ * test whether the data source can be connected successfully
+ * @throws Exception
+ */
+ @Override
+ public void isConnectable() throws Exception {
+ Connection con = null;
+ try {
+ Class.forName("com.mysql.jdbc.Driver");
+ con = DriverManager.getConnection(getJdbcUrl(), getUser(), getPassword());
+ } finally {
+ if (con != null) {
+ try {
+ con.close();
+ } catch (SQLException e) {
+ logger.error("Mysql datasource try conn close conn error", e);
+ throw e;
+ }
+ }
+ }
+ }
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/PostgreDataSource.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/PostgreDataSource.java
new file mode 100644
index 0000000000..a0c893d6d6
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/PostgreDataSource.java
@@ -0,0 +1,77 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * data source of postgreSQL
+ */
+public class PostgreDataSource extends BaseDataSource {
+
+ private static final Logger logger = LoggerFactory.getLogger(PostgreDataSource.class);
+
+
+ /**
+ * gets the JDBC url for the data source connection
+ * @return
+ */
+ @Override
+ public String getJdbcUrl() {
+ String jdbcUrl = getAddress();
+ if (jdbcUrl.lastIndexOf("/") != (jdbcUrl.length() - 1)) {
+ jdbcUrl += "/";
+ }
+
+ jdbcUrl += getDatabase();
+
+ if (StringUtils.isNotEmpty(getOther())) {
+ jdbcUrl += "?" + getOther();
+ }
+
+ return jdbcUrl;
+ }
+
+ /**
+ * test whether the data source can be connected successfully
+ * @throws Exception
+ */
+ @Override
+ public void isConnectable() throws Exception {
+ Connection con = null;
+ try {
+ Class.forName("org.postgresql.Driver");
+ con = DriverManager.getConnection(getJdbcUrl(), getUser(), getPassword());
+ } finally {
+ if (con != null) {
+ try {
+ con.close();
+ } catch (SQLException e) {
+ logger.error("Postgre datasource try conn close conn error", e);
+ throw e;
+ }
+ }
+ }
+
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/job/db/SparkDataSource.java b/escheduler-common/src/main/java/cn/escheduler/common/job/db/SparkDataSource.java
new file mode 100644
index 0000000000..d9a24eef22
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/job/db/SparkDataSource.java
@@ -0,0 +1,77 @@
+/*
+ * 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 cn.escheduler.common.job.db;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * data source of spark
+ */
+public class SparkDataSource extends BaseDataSource {
+
+ private static final Logger logger = LoggerFactory.getLogger(SparkDataSource.class);
+
+
+ /**
+ * gets the JDBC url for the data source connection
+ * @return
+ */
+ @Override
+ public String getJdbcUrl() {
+ String jdbcUrl = getAddress();
+ if (jdbcUrl.lastIndexOf("/") != (jdbcUrl.length() - 1)) {
+ jdbcUrl += "/";
+ }
+
+ jdbcUrl += getDatabase();
+
+ if (StringUtils.isNotEmpty(getOther())) {
+ jdbcUrl += ";" + getOther();
+ }
+
+ return jdbcUrl;
+ }
+
+ /**
+ * test whether the data source can be connected successfully
+ * @throws Exception
+ */
+ @Override
+ public void isConnectable() throws Exception {
+ Connection con = null;
+ try {
+ Class.forName("org.apache.hive.jdbc.HiveDriver");
+ con = DriverManager.getConnection(getJdbcUrl(), getUser(), "");
+ } finally {
+ if (con != null) {
+ try {
+ con.close();
+ } catch (SQLException e) {
+ logger.error("Spark datasource try conn close conn error", e);
+ throw e;
+ }
+ }
+ }
+
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/model/DateInterval.java b/escheduler-common/src/main/java/cn/escheduler/common/model/DateInterval.java
new file mode 100644
index 0000000000..aaf64325c5
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/model/DateInterval.java
@@ -0,0 +1,62 @@
+/*
+ * 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 cn.escheduler.common.model;
+
+import java.util.Date;
+
+/**
+ * date interval class
+ */
+public class DateInterval {
+
+ private Date startTime;
+
+ private Date endTime;
+
+ public DateInterval(Date beginTime, Date endTime){
+ this.startTime = beginTime;
+ this.endTime = endTime;
+
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ try{
+ DateInterval dateInterval = (DateInterval) obj;
+ return startTime.equals(dateInterval.getStartTime()) &&
+ endTime.equals(dateInterval.getEndTime());
+ }catch (Exception e){
+ return false;
+ }
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/model/DependentItem.java b/escheduler-common/src/main/java/cn/escheduler/common/model/DependentItem.java
new file mode 100644
index 0000000000..117a54db56
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/model/DependentItem.java
@@ -0,0 +1,80 @@
+/*
+ * 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 cn.escheduler.common.model;
+
+import cn.escheduler.common.enums.DependResult;
+
+/**
+ * dependent item
+ */
+public class DependentItem {
+
+ private int definitionId;
+ private String depTasks;
+ private String cycle;
+ private String dateValue;
+ private DependResult dependResult;
+
+
+ public String getKey(){
+ return String.format("%d-%s-%s-%s",
+ getDefinitionId(),
+ getDepTasks(),
+ getCycle(),
+ getDateValue());
+ }
+
+ public int getDefinitionId() {
+ return definitionId;
+ }
+
+ public void setDefinitionId(int definitionId) {
+ this.definitionId = definitionId;
+ }
+
+ public String getDepTasks() {
+ return depTasks;
+ }
+
+ public void setDepTasks(String depTasks) {
+ this.depTasks = depTasks;
+ }
+
+ public String getCycle() {
+ return cycle;
+ }
+
+ public void setCycle(String cycle) {
+ this.cycle = cycle;
+ }
+
+ public String getDateValue() {
+ return dateValue;
+ }
+
+ public void setDateValue(String dateValue) {
+ this.dateValue = dateValue;
+ }
+
+ public DependResult getDependResult() {
+ return dependResult;
+ }
+
+ public void setDependResult(DependResult dependResult) {
+ this.dependResult = dependResult;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/model/DependentTaskModel.java b/escheduler-common/src/main/java/cn/escheduler/common/model/DependentTaskModel.java
new file mode 100644
index 0000000000..b642b2e5b5
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/model/DependentTaskModel.java
@@ -0,0 +1,44 @@
+/*
+ * 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 cn.escheduler.common.model;
+
+import cn.escheduler.common.enums.DependentRelation;
+
+import java.util.List;
+
+public class DependentTaskModel {
+
+
+ private List dependItemList;
+ private DependentRelation relation;
+
+ public List getDependItemList() {
+ return dependItemList;
+ }
+
+ public void setDependItemList(List dependItemList) {
+ this.dependItemList = dependItemList;
+ }
+
+ public DependentRelation getRelation() {
+ return relation;
+ }
+
+ public void setRelation(DependentRelation relation) {
+ this.relation = relation;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNode.java b/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNode.java
new file mode 100644
index 0000000000..fb9ffe1145
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNode.java
@@ -0,0 +1,308 @@
+/*
+ * 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 cn.escheduler.common.model;
+
+import cn.escheduler.common.Constants;
+import cn.escheduler.common.enums.Priority;
+import cn.escheduler.common.enums.TaskTimeoutStrategy;
+import cn.escheduler.common.task.TaskTimeoutParameter;
+import cn.escheduler.common.utils.CollectionUtils;
+import cn.escheduler.common.utils.JSONUtils;
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+
+
+public class TaskNode {
+
+ /**
+ * task node id
+ */
+ private String id;
+
+ /**
+ * task node name
+ */
+ private String name;
+
+ /**
+ * task node description
+ */
+ private String desc;
+
+ /**
+ * task node type
+ */
+ private String type;
+
+ /**
+ * the run flag has two states, NORMAL or FORBIDDEN
+ */
+ private String runFlag;
+
+ /**
+ * the front field
+ */
+ private String loc;
+
+ /**
+ * maximum number of retries
+ */
+ private int maxRetryTimes;
+
+ /**
+ * Unit of retry interval: points
+ */
+ private int retryInterval;
+
+ /**
+ * params information
+ */
+ @JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
+ @JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
+ private String params;
+
+ /**
+ * inner dependency information
+ */
+ @JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
+ @JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
+ private String preTasks;
+
+ /**
+ * users store additional information
+ */
+ @JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
+ @JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
+ private String extras;
+
+ /**
+ * node dependency list
+ */
+ private List depList;
+
+ /**
+ * outer dependency information
+ */
+ @JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
+ @JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
+ private String dependence;
+
+ /**
+ * task instance priority
+ */
+ private Priority taskInstancePriority;
+
+ /**
+ * task time out
+ */
+ @JsonDeserialize(using = JSONUtils.JsonDataDeserializer.class)
+ @JsonSerialize(using = JSONUtils.JsonDataSerializer.class)
+ private String timeout;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getParams() {
+ return params;
+ }
+
+ public void setParams(String params) {
+ this.params = params;
+ }
+
+ public String getPreTasks() {
+ return preTasks;
+ }
+
+ public void setPreTasks(String preTasks) throws IOException {
+ this.preTasks = preTasks;
+ this.depList = JSONUtils.toList(preTasks, String.class);
+ }
+
+ public String getExtras() {
+ return extras;
+ }
+
+ public void setExtras(String extras) {
+ this.extras = extras;
+ }
+
+ public List getDepList() {
+ return depList;
+ }
+
+ public void setDepList(List depList) throws JsonProcessingException {
+ this.depList = depList;
+ this.preTasks = JSONUtils.toJson(depList);
+ }
+
+ public String getLoc() {
+ return loc;
+ }
+
+ public void setLoc(String loc) {
+ this.loc = loc;
+ }
+
+ public String getRunFlag(){
+ return runFlag;
+ }
+
+ public void setRunFlag(String runFlag) {
+ this.runFlag = runFlag;
+ }
+
+ public Boolean isForbidden(){
+ return (StringUtils.isNotEmpty(this.runFlag) &&
+ this.runFlag.equals(Constants.FLOWNODE_RUN_FLAG_FORBIDDEN));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ TaskNode taskNode = (TaskNode) o;
+ return Objects.equals(name, taskNode.name) &&
+ Objects.equals(desc, taskNode.desc) &&
+ Objects.equals(type, taskNode.type) &&
+ Objects.equals(params, taskNode.params) &&
+ Objects.equals(preTasks, taskNode.preTasks) &&
+ Objects.equals(extras, taskNode.extras) &&
+ Objects.equals(runFlag, taskNode.runFlag) &&
+ Objects.equals(dependence, taskNode.dependence) &&
+ CollectionUtils.equalLists(depList, taskNode.depList);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, desc, type, params, preTasks, extras, depList, runFlag);
+ }
+
+ public String getDependence() {
+ return dependence;
+ }
+
+ public void setDependence(String dependence) {
+ this.dependence = dependence;
+ }
+
+ public int getMaxRetryTimes() {
+ return maxRetryTimes;
+ }
+
+ public void setMaxRetryTimes(int maxRetryTimes) {
+ this.maxRetryTimes = maxRetryTimes;
+ }
+
+ public int getRetryInterval() {
+ return retryInterval;
+ }
+
+ public void setRetryInterval(int retryInterval) {
+ this.retryInterval = retryInterval;
+ }
+
+ public Priority getTaskInstancePriority() {
+ return taskInstancePriority;
+ }
+
+ public void setTaskInstancePriority(Priority taskInstancePriority) {
+ this.taskInstancePriority = taskInstancePriority;
+ }
+
+ public String getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(String timeout) {
+ this.timeout = timeout;
+ }
+
+ /**
+ * get task time out parameter
+ * @return
+ */
+ public TaskTimeoutParameter getTaskTimeoutParameter() {
+ if(StringUtils.isNotEmpty(this.getTimeout())){
+ String formatStr = String.format("%s,%s", TaskTimeoutStrategy.WARN.name(), TaskTimeoutStrategy.FAILED.name());
+ String timeout = this.getTimeout().replace(formatStr,TaskTimeoutStrategy.WARNFAILED.name());
+ return JSONObject.parseObject(timeout,TaskTimeoutParameter.class);
+ }
+ return new TaskTimeoutParameter(false);
+ }
+
+ @Override
+ public String toString() {
+ return "TaskNode{" +
+ "id='" + id + '\'' +
+ ", name='" + name + '\'' +
+ ", desc='" + desc + '\'' +
+ ", type='" + type + '\'' +
+ ", runFlag='" + runFlag + '\'' +
+ ", loc='" + loc + '\'' +
+ ", maxRetryTimes=" + maxRetryTimes +
+ ", retryInterval=" + retryInterval +
+ ", params='" + params + '\'' +
+ ", preTasks='" + preTasks + '\'' +
+ ", extras='" + extras + '\'' +
+ ", depList=" + depList +
+ ", dependence='" + dependence + '\'' +
+ ", taskInstancePriority=" + taskInstancePriority +
+ ", timeout='" + timeout + '\'' +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNodeRelation.java b/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNodeRelation.java
new file mode 100644
index 0000000000..979d6d48ee
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/model/TaskNodeRelation.java
@@ -0,0 +1,67 @@
+/*
+ * 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 cn.escheduler.common.model;
+
+public class TaskNodeRelation {
+
+ /**
+ * task start node name
+ */
+ private String startNode;
+
+ /**
+ * task end node name
+ */
+ private String endNode;
+
+ public TaskNodeRelation() {
+ }
+
+ public TaskNodeRelation(String startNode, String endNode) {
+ this.startNode = startNode;
+ this.endNode = endNode;
+ }
+
+ public String getStartNode() {
+ return startNode;
+ }
+
+ public void setStartNode(String startNode) {
+ this.startNode = startNode;
+ }
+
+ public String getEndNode() {
+ return endNode;
+ }
+
+ public void setEndNode(String endNode) {
+ this.endNode = endNode;
+ }
+
+
+ public boolean equals(TaskNodeRelation e){
+ return (e.getStartNode() == this.startNode && e.getEndNode() == this.endNode);
+ }
+
+ @Override
+ public String toString() {
+ return "TaskNodeRelation{" +
+ "startNode='" + startNode + '\'' +
+ ", endNode='" + endNode + '\'' +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/process/ProcessDag.java b/escheduler-common/src/main/java/cn/escheduler/common/process/ProcessDag.java
new file mode 100644
index 0000000000..e88f4a052a
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/process/ProcessDag.java
@@ -0,0 +1,85 @@
+/*
+ * 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 cn.escheduler.common.process;
+
+
+
+import cn.escheduler.common.model.TaskNode;
+import cn.escheduler.common.model.TaskNodeRelation;
+
+import java.util.List;
+
+public class ProcessDag {
+
+ /**
+ * DAG edge list
+ **/
+ private List edges;
+
+ /**
+ * DAG node list
+ */
+ private List nodes;
+
+ /**
+ * getter method
+ *
+ * @return the edges
+ * @see ProcessDag#edges
+ */
+ public List getEdges() {
+ return edges;
+ }
+
+ /**
+ * setter method
+ *
+ * @param edges the edges to set
+ * @see ProcessDag#edges
+ */
+ public void setEdges(List edges) {
+ this.edges = edges;
+ }
+
+ /**
+ * getter method
+ *
+ * @return the nodes
+ * @see ProcessDag#nodes
+ */
+ public List getNodes() {
+ return nodes;
+ }
+
+ /**
+ * setter method
+ *
+ * @param nodes the nodes to set
+ * @see ProcessDag#nodes
+ */
+ public void setNodes(List nodes) {
+ this.nodes = nodes;
+ }
+
+ @Override
+ public String toString() {
+ return "ProcessDag{" +
+ "edges=" + edges +
+ ", nodes=" + nodes +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/process/Property.java b/escheduler-common/src/main/java/cn/escheduler/common/process/Property.java
new file mode 100644
index 0000000000..cf95a5a26c
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/process/Property.java
@@ -0,0 +1,143 @@
+/*
+ * 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 cn.escheduler.common.process;
+
+
+import cn.escheduler.common.enums.DataType;
+import cn.escheduler.common.enums.Direct;
+
+import java.util.Objects;
+
+public class Property {
+ /**
+ * key
+ */
+ private String prop;
+
+ /**
+ * input/output
+ */
+ private Direct direct;
+
+ /**
+ * data type
+ */
+ private DataType type;
+
+ /**
+ * value
+ */
+ private String value;
+
+ public Property() {
+ }
+
+ public Property(String prop,Direct direct,DataType type,String value) {
+ this.prop = prop;
+ this.direct = direct;
+ this.type = type;
+ this.value = value;
+ }
+
+ /**
+ * getter method
+ *
+ * @return the prop
+ * @see Property#prop
+ */
+ public String getProp() {
+ return prop;
+ }
+
+ /**
+ * setter method
+ *
+ * @param prop the prop to set
+ * @see Property#prop
+ */
+ public void setProp(String prop) {
+ this.prop = prop;
+ }
+
+ /**
+ * getter method
+ *
+ * @return the value
+ * @see Property#value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * setter method
+ *
+ * @param value the value to set
+ * @see Property#value
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+
+ public Direct getDirect() {
+ return direct;
+ }
+
+ public void setDirect(Direct direct) {
+ this.direct = direct;
+ }
+
+ public DataType getType() {
+ return type;
+ }
+
+ public void setType(DataType type) {
+ this.type = type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Property property = (Property) o;
+ return Objects.equals(prop, property.prop) &&
+ Objects.equals(value, property.value);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(prop, value);
+ }
+
+ @Override
+ public String toString() {
+ return "Property{" +
+ "prop='" + prop + '\'' +
+ ", direct=" + direct +
+ ", type=" + type +
+ ", value='" + value + '\'' +
+ '}';
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/process/ResourceInfo.java b/escheduler-common/src/main/java/cn/escheduler/common/process/ResourceInfo.java
new file mode 100644
index 0000000000..e6c64756c5
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/process/ResourceInfo.java
@@ -0,0 +1,37 @@
+/*
+ * 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 cn.escheduler.common.process;
+
+/**
+ * resource info
+ */
+public class ResourceInfo {
+ /**
+ * res the name of the resource that was uploaded
+ */
+ private String res;
+
+ public String getRes() {
+ return res;
+ }
+
+ public void setRes(String res) {
+ this.res = res;
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/queue/ITaskQueue.java b/escheduler-common/src/main/java/cn/escheduler/common/queue/ITaskQueue.java
new file mode 100644
index 0000000000..7c01bc4ec2
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/queue/ITaskQueue.java
@@ -0,0 +1,91 @@
+/*
+ * 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 cn.escheduler.common.queue;
+
+import java.util.List;
+import java.util.Set;
+
+public interface ITaskQueue {
+
+ /**
+ * take out all the elements
+ *
+ * this method has deprecated
+ * use checkTaskExists instead
+ *
+ * @param key
+ * @return
+ */
+ @Deprecated
+ List getAllTasks(String key);
+
+ /**
+ * check task exists in the task queue or not
+ *
+ * @param key queue name
+ * @param task ${priority}_${processInstanceId}_${taskId}
+ * @return true if exists in the queue
+ */
+ boolean checkTaskExists(String key, String task);
+
+ /**
+ * add an element to the queue
+ *
+ * @param key queue name
+ * @param value
+ */
+ void add(String key, String value);
+
+ /**
+ * an element pops out of the queue
+ *
+ * @param key queue name
+ * @return
+ */
+ String poll(String key);
+
+
+ /**
+ * add an element to the set
+ *
+ * @param key
+ * @param value
+ */
+ void sadd(String key, String value);
+
+ /**
+ * delete the value corresponding to the key in the set
+ *
+ * @param key
+ * @param value
+ */
+ void srem(String key, String value);
+
+ /**
+ * gets all the elements of the set based on the key
+ *
+ * @param key
+ * @return
+ */
+ Set smembers(String key);
+
+
+ /**
+ * clear the task queue for use by junit tests only
+ */
+ void delete();
+}
\ No newline at end of file
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueFactory.java b/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueFactory.java
new file mode 100644
index 0000000000..c8931064af
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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 cn.escheduler.common.queue;
+
+import cn.escheduler.common.utils.CommonUtils;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * task queue factory
+ */
+public class TaskQueueFactory {
+
+ private static final Logger logger = LoggerFactory.getLogger(TaskQueueFactory.class);
+
+
+ private TaskQueueFactory(){
+
+ }
+
+
+ /**
+ * get instance (singleton)
+ *
+ * @return instance
+ */
+ public static ITaskQueue getTaskQueueInstance() {
+ String queueImplValue = CommonUtils.getQueueImplValue();
+ if (StringUtils.isNotBlank(queueImplValue)) {
+// queueImplValue = StringUtils.trim(queueImplValue);
+
+// if (SCHEDULER_QUEUE_REDIS_IMPL.equals(queueImplValue)) {
+// logger.info("task queue impl use reids ");
+// return TaskQueueRedisImpl.getInstance();
+// } else {
+ logger.info("task queue impl use zookeeper ");
+ return TaskQueueZkImpl.getInstance();
+// }
+ }else{
+ logger.error("property escheduler.queue.impl can't be blank ");
+ System.exit(-1);
+ }
+
+ return null;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueZkImpl.java b/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueZkImpl.java
new file mode 100644
index 0000000000..ec11f6dbe6
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/queue/TaskQueueZkImpl.java
@@ -0,0 +1,365 @@
+/*
+ * 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 cn.escheduler.common.queue;
+
+
+import cn.escheduler.common.Constants;
+import cn.escheduler.common.utils.Bytes;
+import cn.escheduler.common.zk.AbstractZKClient;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.data.Stat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A singleton of a task queue implemented with zookeeper
+ * tasks queue implemention
+ */
+public class TaskQueueZkImpl extends AbstractZKClient implements ITaskQueue {
+
+ private static final Logger logger = LoggerFactory.getLogger(TaskQueueZkImpl.class);
+
+ private static TaskQueueZkImpl instance;
+
+ private TaskQueueZkImpl(){
+ init();
+ }
+
+ public static TaskQueueZkImpl getInstance(){
+ if (null == instance) {
+ synchronized (TaskQueueZkImpl.class) {
+ if(null == instance) {
+ instance = new TaskQueueZkImpl();
+ }
+ }
+ }
+ return instance;
+ }
+
+
+ /**
+ * get all tasks from tasks queue
+ * @param key task queue name
+ * @return
+ */
+ @Deprecated
+ @Override
+ public List getAllTasks(String key) {
+ try {
+ List list = getZkClient().getChildren().forPath(getTasksPath(key));
+
+ return list;
+ } catch (Exception e) {
+ logger.error("get all tasks from tasks queue exception",e);
+ }
+
+ return new ArrayList();
+ }
+
+ /**
+ * check task exists in the task queue or not
+ *
+ * @param key queue name
+ * @param task ${priority}_${processInstanceId}_${taskId}
+ * @return true if exists in the queue
+ */
+ @Override
+ public boolean checkTaskExists(String key, String task) {
+ String taskPath = getTasksPath(key) + Constants.SINGLE_SLASH + task;
+
+ try {
+ Stat stat = zkClient.checkExists().forPath(taskPath);
+
+ if(null == stat){
+ logger.info("check task:{} not exist in task queue",task);
+ return false;
+ }else{
+ logger.info("check task {} exists in task queue ",task);
+ return true;
+ }
+
+ } catch (Exception e) {
+ logger.info(String.format("task {} check exists in task queue exception ", task), e);
+ }
+
+ return false;
+ }
+
+
+ /**
+ * add task to tasks queue
+ *
+ * @param key task queue name
+ * @param value ${priority}_${processInstanceId}_${taskId}
+ */
+ @Override
+ public void add(String key, String value) {
+ try {
+ String taskIdPath = getTasksPath(key) + Constants.SINGLE_SLASH + value;
+ String result = getZkClient().create().withMode(CreateMode.PERSISTENT).forPath(taskIdPath, Bytes.toBytes(value));
+
+// String path = conf.getString(Constants.ZOOKEEPER_SCHEDULER_ROOT) + Constants.SINGLE_SLASH + Constants.SCHEDULER_TASKS_QUEUE + "_add" + Constants.SINGLE_SLASH + value;
+// getZkClient().create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,
+// Bytes.toBytes(value));
+ logger.info("add task : {} to tasks queue , result success",result);
+ } catch (Exception e) {
+ logger.error("add task to tasks queue exception",e);
+ }
+
+ }
+
+
+ /**
+ * An element pops out of the queue
+ * note:
+ * ${processInstancePriority}_${processInstanceId}_${taskInstancePriority}_${taskId}
+ * The tasks with the highest priority are selected by comparing the priorities of the above four levels from high to low.
+ *
+ * 流程实例优先级_流程实例id_任务优先级_任务id high <- low
+ * @param key task queue name
+ * @return the task id to be executed
+ */
+ @Override
+ public String poll(String key) {
+ try{
+ CuratorFramework zk = getZkClient();
+ String tasksQueuePath = getTasksPath(key) + Constants.SINGLE_SLASH;
+ List list = zk.getChildren().forPath(getTasksPath(key));
+
+ if(list != null && list.size() > 0){
+
+ int size = list.size();
+
+ String formatTargetTask = null;
+ String targetTaskKey = null;
+ for (int i = 0; i < size; i++) {
+ String taskDetail = list.get(i);
+ String[] taskDetailArrs = taskDetail.split(Constants.UNDERLINE);
+
+ if(taskDetailArrs.length == 4){
+ //format ${processInstancePriority}_${processInstanceId}_${taskInstancePriority}_${taskId}
+ String formatTask = String.format("%s_%010d_%s_%010d", taskDetailArrs[0], Long.parseLong(taskDetailArrs[1]), taskDetailArrs[2], Long.parseLong(taskDetailArrs[3]));
+ if(i > 0){
+ int result = formatTask.compareTo(formatTargetTask);
+ if(result < 0){
+ formatTargetTask = formatTask;
+ targetTaskKey = taskDetail;
+ }
+ }else{
+ formatTargetTask = formatTask;
+ targetTaskKey = taskDetail;
+ }
+ }else{
+ logger.error("task queue poll error, task detail :{} , please check!", taskDetail);
+ }
+ }
+
+ if(formatTargetTask != null){
+ String taskIdPath = tasksQueuePath + targetTaskKey;
+
+ logger.info("consume task {}", taskIdPath);
+
+ String[] vals = targetTaskKey.split(Constants.UNDERLINE);
+
+ try{
+ zk.delete().forPath(taskIdPath);
+
+// String path = conf.getString(Constants.ZOOKEEPER_SCHEDULER_ROOT) + Constants.SINGLE_SLASH + Constants.SCHEDULER_TASKS_QUEUE + "_remove" + Constants.SINGLE_SLASH + targetTaskKey;
+// getZkClient().create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,
+// Bytes.toBytes(targetTaskKey));
+ }catch(Exception e){
+ logger.error(String.format("delete task:%s from zookeeper fail, task detail: %s exception" ,targetTaskKey, vals[vals.length - 1]) ,e);
+ }
+ logger.info("consume task: {},there still have {} tasks need to be executed", targetTaskKey, size - 1);
+
+ return vals[vals.length - 1];
+ }else{
+ logger.error("should not go here, task queue poll error, please check!");
+ }
+ }
+
+ } catch (Exception e) {
+ logger.error("add task to tasks queue exception",e);
+ }
+ return null;
+ }
+
+
+
+ /**
+ * In order to be compatible with redis implementation
+ *
+ * To be compatible with the redis implementation, add an element to the set
+ * @param key The key is the kill/cancel queue path name
+ * @param value host-taskId The name of the zookeeper node
+ */
+ @Override
+ public void sadd(String key,String value) {
+ try {
+
+ if(value != null && value.trim().length() > 0){
+ String path = getTasksPath(key) + Constants.SINGLE_SLASH;
+ CuratorFramework zk = getZkClient();
+ Stat stat = zk.checkExists().forPath(path + value);
+
+ if(null == stat){
+ String result = zk.create().withMode(CreateMode.PERSISTENT).forPath(path + value,Bytes.toBytes(value));
+ logger.info("add task:{} to tasks set result:{} ",value,result);
+ }else{
+ logger.info("task {} exists in tasks set ",value);
+ }
+
+ }else{
+ logger.warn("add host-taskId:{} to tasks set is empty ",value);
+ }
+
+ } catch (Exception e) {
+ logger.error("add task to tasks set exception",e);
+ }
+ }
+
+
+ /**
+ * delete the value corresponding to the key in the set
+ * @param key The key is the kill/cancel queue path name
+ * @param value host-taskId-taskType The name of the zookeeper node
+ */
+ @Override
+ public void srem(String key, String value) {
+ try{
+ String path = getTasksPath(key) + Constants.SINGLE_SLASH;
+ CuratorFramework zk = getZkClient();
+ Stat stat = zk.checkExists().forPath(path + value);
+
+ if(null != stat){
+ zk.delete().forPath(path + value);
+ logger.info("delete task:{} from tasks set ",value);
+ }else{
+ logger.info("delete task:{} from tasks set fail, there is no this task",value);
+ }
+
+ }catch(Exception e){
+ logger.error(String.format("delete task:" + value + " exception"),e);
+ }
+ }
+
+
+ /**
+ * Gets all the elements of the set based on the key
+ * @param key The key is the kill/cancel queue path name
+ * @return
+ */
+ @Override
+ public Set smembers(String key) {
+
+ Set tasksSet = new HashSet<>();
+
+ try {
+ List list = getZkClient().getChildren().forPath(getTasksPath(key));
+
+ for (String task : list) {
+ tasksSet.add(task);
+ }
+
+ return tasksSet;
+ } catch (Exception e) {
+ logger.error("get all tasks from tasks queue exception",e);
+ }
+
+ return tasksSet;
+ }
+
+
+
+ /**
+ * Init the task queue of zookeeper node
+ */
+ private void init(){
+ try {
+ String tasksQueuePath = getTasksPath(Constants.SCHEDULER_TASKS_QUEUE);
+ String tasksCancelPath = getTasksPath(Constants.SCHEDULER_TASKS_KILL);
+
+ for(String taskQueuePath : new String[]{tasksQueuePath,tasksCancelPath}){
+ if(zkClient.checkExists().forPath(taskQueuePath) == null){
+ // create a persistent parent node
+ zkClient.create().creatingParentContainersIfNeeded()
+ .withMode(CreateMode.PERSISTENT).forPath(taskQueuePath);
+ logger.info("create tasks queue parent node success : {} ",taskQueuePath);
+ }
+ }
+
+ } catch (Exception e) {
+ logger.error("create zk node failure",e);
+ }
+ }
+
+
+ /**
+ * Clear the task queue of zookeeper node
+ */
+ @Override
+ public void delete(){
+ try {
+ String tasksQueuePath = getTasksPath(Constants.SCHEDULER_TASKS_QUEUE);
+ String tasksCancelPath = getTasksPath(Constants.SCHEDULER_TASKS_KILL);
+
+ for(String taskQueuePath : new String[]{tasksQueuePath,tasksCancelPath}){
+ if(zkClient.checkExists().forPath(taskQueuePath) != null){
+
+ List list = zkClient.getChildren().forPath(taskQueuePath);
+
+ for (String task : list) {
+ zkClient.delete().forPath(taskQueuePath + Constants.SINGLE_SLASH + task);
+ logger.info("delete task from tasks queue : {}/{} ",taskQueuePath,task);
+
+ }
+
+ }
+ }
+
+ } catch (Exception e) {
+ logger.error("delete all tasks in tasks queue failure",e);
+ }
+ }
+
+
+ /**
+ * get zookeeper client of CuratorFramework
+ * @return
+ */
+ public CuratorFramework getZkClient() {
+ return zkClient;
+ }
+
+
+ /**
+ * Get the task queue path
+ * @param key task queue name
+ * @return
+ */
+ public String getTasksPath(String key){
+ return conf.getString(Constants.ZOOKEEPER_SCHEDULER_ROOT) + Constants.SINGLE_SLASH + key;
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java b/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java
new file mode 100644
index 0000000000..1250732632
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/shell/AbstractShell.java
@@ -0,0 +1,341 @@
+/*
+ * 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 cn.escheduler.common.shell;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+/**
+ * A base class for running a Unix command.
+ *
+ * AbstractShell can be used to run unix commands like du or
+ * df. It also offers facilities to gate commands by
+ * time-intervals.
+ */
+public abstract class AbstractShell {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractShell.class);
+
+
+
+ /**
+ * Time after which the executing script would be timedout
+ */
+ protected long timeOutInterval = 0L;
+ /**
+ * If or not script timed out
+ */
+ private AtomicBoolean timedOut;
+
+ /**
+ * refresh interval in msec
+ */
+ private long interval;
+
+ /**
+ * last time the command was performed
+ */
+ private long lastTime;
+
+ /**
+ * env for the command execution
+ */
+ private Map environment;
+ private File dir;
+
+ /**
+ * sub process used to execute the command
+ */
+ private Process process;
+ private int exitCode;
+
+ /**
+ * If or not script finished executing
+ */
+ private volatile AtomicBoolean completed;
+
+ public AbstractShell() {
+ this(0L);
+ }
+
+ /**
+ * @param interval the minimum duration to wait before re-executing the
+ * command.
+ */
+ public AbstractShell(long interval ) {
+ this.interval = interval;
+ this.lastTime = (interval<0) ? 0 : -interval;
+ }
+
+
+
+ /**
+ * set the environment for the command
+ * @param env Mapping of environment variables
+ */
+ protected void setEnvironment(Map env) {
+ this.environment = env;
+ }
+
+ /**
+ * set the working directory
+ * @param dir The directory where the command would be executed
+ */
+ protected void setWorkingDirectory(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * check to see if a command needs to be executed and execute if needed
+ */
+ protected void run() throws IOException {
+ if (lastTime + interval > System.currentTimeMillis()) {
+ return;
+ }
+ // reset for next run
+ exitCode = 0;
+ runCommand();
+ }
+
+
+ /**
+ * Run a command actual work
+ */
+ private void runCommand() throws IOException {
+ ProcessBuilder builder = new ProcessBuilder(getExecString());
+ Timer timeOutTimer = null;
+ ShellTimeoutTimerTask timeoutTimerTask = null;
+ timedOut = new AtomicBoolean(false);
+ completed = new AtomicBoolean(false);
+
+ if (environment != null) {
+ builder.environment().putAll(this.environment);
+ }
+ if (dir != null) {
+ builder.directory(this.dir);
+ }
+
+ process = builder.start();
+ ProcessContainer.putProcess(process);
+
+ if (timeOutInterval > 0) {
+ timeOutTimer = new Timer();
+ timeoutTimerTask = new ShellTimeoutTimerTask(
+ this);
+ //One time scheduling.
+ timeOutTimer.schedule(timeoutTimerTask, timeOutInterval);
+ }
+ final BufferedReader errReader =
+ new BufferedReader(new InputStreamReader(process
+ .getErrorStream()));
+ BufferedReader inReader =
+ new BufferedReader(new InputStreamReader(process
+ .getInputStream()));
+ final StringBuffer errMsg = new StringBuffer();
+
+ // read error and input streams as this would free up the buffers
+ // free the error stream buffer
+ Thread errThread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ String line = errReader.readLine();
+ while((line != null) && !isInterrupted()) {
+ errMsg.append(line);
+ errMsg.append(System.getProperty("line.separator"));
+ line = errReader.readLine();
+ }
+ } catch(IOException ioe) {
+ logger.warn("Error reading the error stream", ioe);
+ }
+ }
+ };
+ try {
+ errThread.start();
+ } catch (IllegalStateException ise) { }
+ try {
+ // parse the output
+ parseExecResult(inReader);
+ exitCode = process.waitFor();
+ try {
+ // make sure that the error thread exits
+ errThread.join();
+ } catch (InterruptedException ie) {
+ logger.warn("Interrupted while reading the error stream", ie);
+ }
+ completed.set(true);
+ //the timeout thread handling
+ //taken care in finally block
+ if (exitCode != 0) {
+ throw new ExitCodeException(exitCode, errMsg.toString());
+ }
+ } catch (InterruptedException ie) {
+ throw new IOException(ie.toString());
+ } finally {
+ if ((timeOutTimer!=null) && !timedOut.get()) {
+ timeOutTimer.cancel();
+ }
+ // close the input stream
+ try {
+ inReader.close();
+ } catch (IOException ioe) {
+ logger.warn("Error while closing the input stream", ioe);
+ }
+ if (!completed.get()) {
+ errThread.interrupt();
+ }
+ try {
+ errReader.close();
+ } catch (IOException ioe) {
+ logger.warn("Error while closing the error stream", ioe);
+ }
+ ProcessContainer.removeProcess(process);
+ process.destroy();
+ lastTime = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * return an array containing the command name & its parameters
+ * */
+ protected abstract String[] getExecString();
+
+ /**
+ * Parse the execution result
+ * */
+ protected abstract void parseExecResult(BufferedReader lines)
+ throws IOException;
+
+ /**
+ * get the current sub-process executing the given command
+ * @return process executing the command
+ */
+ public Process getProcess() {
+ return process;
+ }
+
+ /** get the exit code
+ * @return the exit code of the process
+ */
+ public int getExitCode() {
+ return exitCode;
+ }
+
+ /**
+ * Set if the command has timed out.
+ *
+ */
+ private void setTimedOut() {
+ this.timedOut.set(true);
+ }
+
+
+
+ /**
+ * Timer which is used to timeout scripts spawned off by shell.
+ */
+ private static class ShellTimeoutTimerTask extends TimerTask {
+
+ private AbstractShell shell;
+
+ public ShellTimeoutTimerTask(AbstractShell shell) {
+ this.shell = shell;
+ }
+
+ @Override
+ public void run() {
+ Process p = shell.getProcess();
+ try {
+ p.exitValue();
+ } catch (Exception e) {
+ //Process has not terminated.
+ //So check if it has completed
+ //if not just destroy it.
+ if (p != null && !shell.completed.get()) {
+ shell.setTimedOut();
+ p.destroy();
+ }
+ }
+ }
+ }
+
+ /**
+ * This is an IOException with exit code added.
+ */
+ public static class ExitCodeException extends IOException {
+ int exitCode;
+
+ public ExitCodeException(int exitCode, String message) {
+ super(message);
+ this.exitCode = exitCode;
+ }
+
+ public int getExitCode() {
+ return exitCode;
+ }
+ }
+
+ /**
+ * process manage container
+ *
+ */
+ public static class ProcessContainer extends ConcurrentHashMap{
+ private static final ProcessContainer container = new ProcessContainer();
+ private ProcessContainer(){
+ super();
+ }
+ public static final ProcessContainer getInstance(){
+ return container;
+ }
+
+ public static void putProcess(Process process){
+ getInstance().put(process.hashCode(), process);
+ }
+ public static int processSize(){
+ return getInstance().size();
+ }
+
+ public static void removeProcess(Process process){
+ getInstance().remove(process.hashCode());
+ }
+
+ public static void destroyAllProcess(){
+ Set> set = getInstance().entrySet();
+ for (Entry entry : set) {
+ try{
+ entry.getValue().destroy();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ logger.info("close " + set.size() + " executing process tasks");
+ }
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/shell/ShellExecutor.java b/escheduler-common/src/main/java/cn/escheduler/common/shell/ShellExecutor.java
new file mode 100644
index 0000000000..1a23f9655e
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/shell/ShellExecutor.java
@@ -0,0 +1,175 @@
+/*
+ * 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 cn.escheduler.common.shell;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * shell command executor.
+ *
+ * ShellExecutor should be used in cases where the output
+ * of the command needs no explicit parsing and where the command, working
+ * directory and the environment remains unchanged. The output of the command
+ * is stored as-is and is expected to be small.
+ */
+public class ShellExecutor extends AbstractShell {
+
+ private String[] command;
+ private StringBuffer output;
+
+
+ public ShellExecutor(String... execString) {
+ this(execString, null);
+ }
+
+ public ShellExecutor(String[] execString, File dir) {
+ this(execString, dir, null);
+ }
+
+ public ShellExecutor(String[] execString, File dir,
+ Map env) {
+ this(execString, dir, env , 0L);
+ }
+
+ /**
+ * Create a new instance of the ShellExecutor to execute a command.
+ *
+ * @param execString The command to execute with arguments
+ * @param dir If not-null, specifies the directory which should be set
+ * as the current working directory for the command.
+ * If null, the current working directory is not modified.
+ * @param env If not-null, environment of the command will include the
+ * key-value pairs specified in the map. If null, the current
+ * environment is not modified.
+ * @param timeout Specifies the time in milliseconds, after which the
+ * command will be killed and the status marked as timedout.
+ * If 0, the command will not be timed out.
+ */
+ public ShellExecutor(String[] execString, File dir,
+ Map env, long timeout) {
+ command = execString.clone();
+ if (dir != null) {
+ setWorkingDirectory(dir);
+ }
+ if (env != null) {
+ setEnvironment(env);
+ }
+ timeOutInterval = timeout;
+ }
+
+
+ /**
+ * Static method to execute a shell command.
+ * Covers most of the simple cases without requiring the user to implement
+ * the AbstractShell interface.
+ * @param cmd shell command to execute.
+ * @return the output of the executed command.
+ */
+ public static String execCommand(String... cmd) throws IOException {
+ return execCommand(null, cmd, 0L);
+ }
+
+ /**
+ * Static method to execute a shell command.
+ * Covers most of the simple cases without requiring the user to implement
+ * the AbstractShell interface.
+ * @param env the map of environment key=value
+ * @param cmd shell command to execute.
+ * @param timeout time in milliseconds after which script should be marked timeout
+ * @return the output of the executed command.o
+ */
+
+ public static String execCommand(Map env, String[] cmd,
+ long timeout) throws IOException {
+ ShellExecutor exec = new ShellExecutor(cmd, null, env,
+ timeout);
+ exec.execute();
+ return exec.getOutput();
+ }
+
+ /**
+ * Static method to execute a shell command.
+ * Covers most of the simple cases without requiring the user to implement
+ * the AbstractShell interface.
+ * @param env the map of environment key=value
+ * @param cmd shell command to execute.
+ * @return the output of the executed command.
+ */
+ public static String execCommand(Map env, String ... cmd)
+ throws IOException {
+ return execCommand(env, cmd, 0L);
+ }
+
+ /**
+ * Execute the shell command
+ *
+ */
+ public void execute() throws IOException {
+ this.run();
+ }
+
+ @Override
+ protected String[] getExecString() {
+ return command;
+ }
+
+ @Override
+ protected void parseExecResult(BufferedReader lines) throws IOException {
+ output = new StringBuffer();
+ char[] buf = new char[1024];
+ int nRead;
+ String line = "";
+ while ( (nRead = lines.read(buf, 0, buf.length)) > 0 ) {
+ line = new String(buf,0,nRead);
+ }
+ output.append(line);
+ }
+
+ /**
+ *
+ * Get the output of the shell command
+ */
+ public String getOutput() {
+ return (output == null) ? "" : output.toString();
+ }
+
+
+ /**
+ * Returns the commands of this instance.
+ * Arguments with spaces in are presented with quotes round; other
+ * arguments are presented raw
+ *
+ * @return a string representation of the object
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ String[] args = getExecString();
+ for (String s : args) {
+ if (s.indexOf(' ') >= 0) {
+ builder.append('"').append(s).append('"');
+ } else {
+ builder.append(s);
+ }
+ builder.append(' ');
+ }
+ return builder.toString();
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/AbstractParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/AbstractParameters.java
new file mode 100644
index 0000000000..596bfcc87e
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/AbstractParameters.java
@@ -0,0 +1,69 @@
+/*
+ * 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 cn.escheduler.common.task;
+
+import cn.escheduler.common.process.Property;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * job params related class
+ */
+public abstract class AbstractParameters implements IParameters {
+
+ @Override
+ public abstract boolean checkParameters();
+
+ @Override
+ public abstract List getResourceFilesList();
+
+ /**
+ * local parameters
+ */
+ public List localParams;
+
+ /**
+ * get local parameters list
+ * @return
+ */
+ public List getLocalParams() {
+ return localParams;
+ }
+
+ public void setLocalParams(List localParams) {
+ this.localParams = localParams;
+ }
+
+ /**
+ * get local parameters map
+ * @return
+ */
+ public Map getLocalParametersMap() {
+ if (localParams != null) {
+ Map localParametersMaps = new LinkedHashMap<>();
+
+ for (Property property : localParams) {
+ localParametersMaps.put(property.getProp(),property);
+ }
+ return localParametersMaps;
+ }
+ return null;
+ }
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/IParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/IParameters.java
new file mode 100644
index 0000000000..c4dbd6d421
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/IParameters.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
+ *
+ * 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 cn.escheduler.common.task;
+
+import java.util.List;
+
+/**
+ * job params interface
+ */
+public interface IParameters {
+ /**
+ * check parameters is valid
+ *
+ * @return
+ */
+ boolean checkParameters();
+
+ /**
+ * get project resource files list
+ *
+ * @return resource files list
+ */
+ List getResourceFilesList();
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/TaskTimeoutParameter.java b/escheduler-common/src/main/java/cn/escheduler/common/task/TaskTimeoutParameter.java
new file mode 100644
index 0000000000..a2a2fb5f8c
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/TaskTimeoutParameter.java
@@ -0,0 +1,81 @@
+/*
+ * 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 cn.escheduler.common.task;
+
+import cn.escheduler.common.enums.TaskTimeoutStrategy;
+
+/**
+ * task timeout parameter
+ */
+public class TaskTimeoutParameter {
+
+ private boolean enable;
+ /**
+ * task timeout strategy
+ */
+ private TaskTimeoutStrategy strategy;
+ /**
+ * task timeout interval
+ */
+ private int interval;
+
+ public boolean getEnable() {
+ return enable;
+ }
+
+ public void setEnable(boolean enable) {
+ this.enable = enable;
+ }
+
+ public TaskTimeoutStrategy getStrategy() {
+ return strategy;
+ }
+
+ public void setStrategy(TaskTimeoutStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public int getInterval() {
+ return interval;
+ }
+
+ public void setInterval(int interval) {
+ this.interval = interval;
+ }
+
+ public TaskTimeoutParameter() {
+ }
+
+ public TaskTimeoutParameter(boolean enable) {
+ this.enable = enable;
+ }
+
+ public TaskTimeoutParameter(boolean enable, TaskTimeoutStrategy strategy, int interval) {
+ this.enable = enable;
+ this.strategy = strategy;
+ this.interval = interval;
+ }
+
+ @Override
+ public String toString() {
+ return "TaskTimeoutParameter{" +
+ "enable=" + enable +
+ ", strategy=" + strategy +
+ ", interval=" + interval +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/dependent/DependentParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/dependent/DependentParameters.java
new file mode 100644
index 0000000000..87143cdfb8
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/dependent/DependentParameters.java
@@ -0,0 +1,58 @@
+/*
+ * 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 cn.escheduler.common.task.dependent;
+
+import cn.escheduler.common.enums.DependentRelation;
+import cn.escheduler.common.model.DependentTaskModel;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DependentParameters extends AbstractParameters {
+
+ private List dependTaskList;
+ private DependentRelation relation;
+
+
+
+ @Override
+ public boolean checkParameters() {
+ return true;
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ return new ArrayList<>();
+ }
+
+ public List getDependTaskList() {
+ return dependTaskList;
+ }
+
+ public void setDependTaskList(List dependTaskList) {
+ this.dependTaskList = dependTaskList;
+ }
+
+ public DependentRelation getRelation() {
+ return relation;
+ }
+
+ public void setRelation(DependentRelation relation) {
+ this.relation = relation;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/mr/MapreduceParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/mr/MapreduceParameters.java
new file mode 100644
index 0000000000..1839e93929
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/mr/MapreduceParameters.java
@@ -0,0 +1,145 @@
+/*
+ * 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 cn.escheduler.common.task.mr;
+
+import cn.escheduler.common.enums.ProgramType;
+import cn.escheduler.common.process.ResourceInfo;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class MapreduceParameters extends AbstractParameters {
+
+ /**
+ * major jar
+ */
+ private ResourceInfo mainJar;
+
+ /**
+ * major class
+ */
+ private String mainClass;
+
+ /**
+ * arguments
+ */
+ private String mainArgs;
+
+ /**
+ * other arguments
+ */
+ private String others;
+
+ /**
+ * queue
+ */
+ private String queue;
+
+ /**
+ * resource list
+ */
+ private List resourceList;
+
+ /**
+ * program type
+ * 0 JAVA,1 SCALA,2 PYTHON
+ */
+ private ProgramType programType;
+
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public String getMainArgs() {
+ return mainArgs;
+ }
+
+ public void setMainArgs(String mainArgs) {
+ this.mainArgs = mainArgs;
+ }
+
+ public String getOthers() {
+ return others;
+ }
+
+ public void setOthers(String others) {
+ this.others = others;
+ }
+
+ public String getQueue() {
+ return queue;
+ }
+
+ public void setQueue(String queue) {
+ this.queue = queue;
+ }
+
+ public List getResourceList() {
+ return this.resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ public void setMainJar(ResourceInfo mainJar) {
+ this.mainJar = mainJar;
+ }
+
+ public ResourceInfo getMainJar() {
+ return mainJar;
+ }
+
+ public ProgramType getProgramType() {
+ return programType;
+ }
+
+ public void setProgramType(ProgramType programType) {
+ this.programType = programType;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return this.mainJar != null && this.programType != null;
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ if (resourceList != null) {
+ this.resourceList.add(mainJar);
+ return resourceList.stream()
+ .map(p -> p.getRes()).collect(Collectors.toList());
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "mainJar= " + mainJar
+ + "mainClass=" + mainClass
+ + "mainArgs=" + mainArgs
+ + "queue=" + queue
+ + "other mainArgs=" + others
+ ;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/procedure/ProcedureParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/procedure/ProcedureParameters.java
new file mode 100644
index 0000000000..5e84051929
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/procedure/ProcedureParameters.java
@@ -0,0 +1,89 @@
+/*
+ * 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 cn.escheduler.common.task.procedure;
+
+import cn.escheduler.common.task.AbstractParameters;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * procedure parameter
+ */
+public class ProcedureParameters extends AbstractParameters {
+
+ /**
+ * data source type,eg MYSQL, POSTGRES, HIVE ...
+ */
+ private String type;
+
+ /**
+ * data source id
+ */
+ private int datasource;
+
+ /**
+ * procedure name
+ */
+ private String method;
+
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public int getDatasource() {
+ return datasource;
+ }
+
+ public void setDatasource(int datasource) {
+ this.datasource = datasource;
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return datasource != 0 && StringUtils.isNotEmpty(type) && StringUtils.isNotEmpty(method);
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public String toString() {
+ return "ProcessdureParam{" +
+ "type='" + type + '\'' +
+ ", datasource=" + datasource +
+ ", method='" + method + '\'' +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/python/PythonParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/python/PythonParameters.java
new file mode 100644
index 0000000000..601b07b717
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/python/PythonParameters.java
@@ -0,0 +1,67 @@
+/*
+ * 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 cn.escheduler.common.task.python;
+
+
+import cn.escheduler.common.process.ResourceInfo;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class PythonParameters extends AbstractParameters {
+ /**
+ * origin python script
+ */
+ private String rawScript;
+
+ /**
+ * resource list
+ */
+ private List resourceList;
+
+ public String getRawScript() {
+ return rawScript;
+ }
+
+ public void setRawScript(String rawScript) {
+ this.rawScript = rawScript;
+ }
+
+ public List getResourceList() {
+ return resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return rawScript != null && !rawScript.isEmpty();
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ if (resourceList != null) {
+ return resourceList.stream()
+ .map(p -> p.getRes()).collect(Collectors.toList());
+ }
+
+ return null;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/shell/ShellParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/shell/ShellParameters.java
new file mode 100644
index 0000000000..00fbcc114f
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/shell/ShellParameters.java
@@ -0,0 +1,70 @@
+/*
+ * 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 cn.escheduler.common.task.shell;
+
+
+import cn.escheduler.common.process.ResourceInfo;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * shell parameters
+ */
+public class ShellParameters extends AbstractParameters {
+ /**
+ * shell script
+ */
+ private String rawScript;
+
+ /**
+ * resource list
+ */
+ private List resourceList;
+
+ public String getRawScript() {
+ return rawScript;
+ }
+
+ public void setRawScript(String rawScript) {
+ this.rawScript = rawScript;
+ }
+
+ public List getResourceList() {
+ return resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return rawScript != null && !rawScript.isEmpty();
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ if (resourceList != null) {
+ return resourceList.stream()
+ .map(p -> p.getRes()).collect(Collectors.toList());
+ }
+
+ return null;
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/spark/SparkParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/spark/SparkParameters.java
new file mode 100644
index 0000000000..087492b1f2
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/spark/SparkParameters.java
@@ -0,0 +1,220 @@
+/*
+ * 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 cn.escheduler.common.task.spark;
+
+import cn.escheduler.common.enums.ProgramType;
+import cn.escheduler.common.process.ResourceInfo;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * spark parameters
+ */
+public class SparkParameters extends AbstractParameters {
+
+ /**
+ * major jar
+ */
+ private ResourceInfo mainJar;
+
+ /**
+ * major class
+ */
+ private String mainClass;
+
+ /**
+ * deploy mode
+ */
+ private String deployMode;
+
+ /**
+ * arguments
+ */
+ private String mainArgs;
+
+ /**
+ * driver-cores Number of cores used by the driver, only in cluster mode
+ */
+ private int driverCores;
+
+ /**
+ * driver-memory Memory for driver
+ */
+
+ private String driverMemory;
+
+ /**
+ * num-executors Number of executors to launch
+ */
+ private int numExecutors;
+
+ /**
+ * executor-cores Number of cores per executor
+ */
+ private int executorCores;
+
+ /**
+ * Memory per executor
+ */
+ private String executorMemory;
+
+ /**
+ * resource list
+ */
+ private List resourceList;
+
+ /**
+ * The YARN queue to submit to
+ */
+ private String queue;
+
+ /**
+ * other arguments
+ */
+ private String others;
+
+ /**
+ * program type
+ * 0 JAVA,1 SCALA,2 PYTHON
+ */
+ private ProgramType programType;
+
+ public ResourceInfo getMainJar() {
+ return mainJar;
+ }
+
+ public void setMainJar(ResourceInfo mainJar) {
+ this.mainJar = mainJar;
+ }
+
+ public String getMainClass() {
+ return mainClass;
+ }
+
+ public void setMainClass(String mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ public String getDeployMode() {
+ return deployMode;
+ }
+
+ public void setDeployMode(String deployMode) {
+ this.deployMode = deployMode;
+ }
+
+ public String getMainArgs() {
+ return mainArgs;
+ }
+
+ public void setMainArgs(String mainArgs) {
+ this.mainArgs = mainArgs;
+ }
+
+ public int getDriverCores() {
+ return driverCores;
+ }
+
+ public void setDriverCores(int driverCores) {
+ this.driverCores = driverCores;
+ }
+
+ public String getDriverMemory() {
+ return driverMemory;
+ }
+
+ public void setDriverMemory(String driverMemory) {
+ this.driverMemory = driverMemory;
+ }
+
+ public int getNumExecutors() {
+ return numExecutors;
+ }
+
+ public void setNumExecutors(int numExecutors) {
+ this.numExecutors = numExecutors;
+ }
+
+ public int getExecutorCores() {
+ return executorCores;
+ }
+
+ public void setExecutorCores(int executorCores) {
+ this.executorCores = executorCores;
+ }
+
+ public String getExecutorMemory() {
+ return executorMemory;
+ }
+
+ public void setExecutorMemory(String executorMemory) {
+ this.executorMemory = executorMemory;
+ }
+
+
+ public String getQueue() {
+ return queue;
+ }
+
+ public void setQueue(String queue) {
+ this.queue = queue;
+ }
+
+ public List getResourceList() {
+ return resourceList;
+ }
+
+ public void setResourceList(List resourceList) {
+ this.resourceList = resourceList;
+ }
+
+ public String getOthers() {
+ return others;
+ }
+
+ public void setOthers(String others) {
+ this.others = others;
+ }
+
+ public ProgramType getProgramType() {
+ return programType;
+ }
+
+ public void setProgramType(ProgramType programType) {
+ this.programType = programType;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return mainJar != null && programType != null;
+ }
+
+
+ @Override
+ public List getResourceFilesList() {
+ if(resourceList !=null ) {
+ this.resourceList.add(mainJar);
+ return resourceList.stream()
+ .map(p -> p.getRes()).collect(Collectors.toList());
+ }
+ return null;
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlParameters.java
new file mode 100644
index 0000000000..4feb7037f0
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlParameters.java
@@ -0,0 +1,147 @@
+/*
+ * 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 cn.escheduler.common.task.sql;
+
+import cn.escheduler.common.task.AbstractParameters;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Sql/Hql parameter
+ */
+public class SqlParameters extends AbstractParameters {
+ /**
+ * data source type,eg MYSQL, POSTGRES, HIVE ...
+ */
+ private String type;
+
+ /**
+ * datasource id
+ */
+ private int datasource;
+
+ /**
+ * sql
+ */
+ private String sql;
+
+ /**
+ * sql type
+ * 0 query
+ * 1 NON_QUERY
+ */
+ private int sqlType;
+
+ /**
+ * udf list
+ */
+ private String udfs;
+ /**
+ * show type
+ * 0 TABLE
+ * 1 TEXT
+ * 2 attachment
+ * 3 TABLE+attachment
+ */
+ private String showType;
+ /**
+ * SQL connection parameters
+ */
+ private String connParams;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public int getDatasource() {
+ return datasource;
+ }
+
+ public void setDatasource(int datasource) {
+ this.datasource = datasource;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ public String getUdfs() {
+ return udfs;
+ }
+
+ public void setUdfs(String udfs) {
+ this.udfs = udfs;
+ }
+
+ public int getSqlType() {
+ return sqlType;
+ }
+
+ public void setSqlType(int sqlType) {
+ this.sqlType = sqlType;
+ }
+
+ public String getShowType() {
+ return showType;
+ }
+
+ public void setShowType(String showType) {
+ this.showType = showType;
+ }
+
+ public String getConnParams() {
+ return connParams;
+ }
+
+ public void setConnParams(String connParams) {
+ this.connParams = connParams;
+ }
+
+
+ @Override
+ public boolean checkParameters() {
+ return datasource != 0 && StringUtils.isNotEmpty(type) && StringUtils.isNotEmpty(sql);
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ return new ArrayList<>();
+ }
+
+ @Override
+ public String toString() {
+ return "SqlParameters{" +
+ "type='" + type + '\'' +
+ ", datasource=" + datasource +
+ ", sql='" + sql + '\'' +
+ ", sqlType=" + sqlType +
+ ", udfs='" + udfs + '\'' +
+ ", showType='" + showType + '\'' +
+ ", connParams='" + connParams + '\'' +
+ '}';
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlType.java b/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlType.java
new file mode 100644
index 0000000000..3a7a48bfbd
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/sql/SqlType.java
@@ -0,0 +1,27 @@
+/*
+ * 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 cn.escheduler.common.task.sql;
+
+
+public enum SqlType {
+ /**
+ * sql type
+ * 0 query
+ * 1 NON_QUERY
+ */
+ QUERY, NON_QUERY
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/task/subprocess/SubProcessParameters.java b/escheduler-common/src/main/java/cn/escheduler/common/task/subprocess/SubProcessParameters.java
new file mode 100644
index 0000000000..0ad69ca2ef
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/task/subprocess/SubProcessParameters.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
+ *
+ * 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 cn.escheduler.common.task.subprocess;
+import cn.escheduler.common.task.AbstractParameters;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class SubProcessParameters extends AbstractParameters {
+
+ /**
+ * process definition id
+ */
+ private Integer processDefinitionId;
+
+ public void setProcessDefinitionId(Integer processDefinitionId){
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public Integer getProcessDefinitionId(){
+ return this.processDefinitionId;
+ }
+
+ @Override
+ public boolean checkParameters() {
+ return this.processDefinitionId != 0;
+ }
+
+ @Override
+ public List getResourceFilesList() {
+ return new ArrayList<>();
+ }
+}
\ No newline at end of file
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/thread/Stopper.java b/escheduler-common/src/main/java/cn/escheduler/common/thread/Stopper.java
new file mode 100644
index 0000000000..76f31c4a22
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/thread/Stopper.java
@@ -0,0 +1,39 @@
+/*
+ * 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 cn.escheduler.common.thread;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * if the process closes, a signal is placed as true, and all threads get this flag to stop working
+ */
+public class Stopper {
+
+ private static volatile AtomicBoolean signal = new AtomicBoolean(false);
+
+ public static final boolean isStoped(){
+ return signal.get();
+ }
+
+ public static final boolean isRunning(){
+ return !signal.get();
+ }
+
+ public static final void stop(){
+ signal.getAndSet(true);
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java
new file mode 100644
index 0000000000..8329e8c18a
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadPoolExecutors.java
@@ -0,0 +1,310 @@
+/*
+ * 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 cn.escheduler.common.thread;
+
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.PrintWriter;
+import java.lang.management.ThreadInfo;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+
+/**
+ *
+ * thread pool's single instance
+ *
+ */
+public class ThreadPoolExecutors {
+
+ private static final Logger logger = LoggerFactory.getLogger(ThreadPoolExecutors.class);
+ private static Executor executor;
+ private static ThreadPoolExecutors threadPoolExecutors;
+
+ private ThreadPoolExecutors(){}
+
+
+ public static ThreadPoolExecutors getInstance(){
+ return getInstance("thread_pool",0);
+ }
+
+ public static ThreadPoolExecutors getInstance(String name, int maxThreads){
+
+ if (null == threadPoolExecutors) {
+
+ synchronized (ThreadPoolExecutors.class) {
+
+ if(null == threadPoolExecutors) {
+ threadPoolExecutors = new ThreadPoolExecutors();
+ }
+ if(null == executor) {
+ executor = new Executor(null == name? "thread_pool" : name, maxThreads == 0? Runtime.getRuntime().availableProcessors() * 3 : maxThreads);
+ }
+ }
+ }
+
+ return threadPoolExecutors;
+ }
+
+ /**
+ * Executes the given task sometime in the future. The task may execute in a new thread or in an existing pooled thread.
+ * If the task cannot be submitted for execution, either because this executor has been shutdown or because its capacity has been reached,
+ * the task is handled by the current RejectedExecutionHandler.
+ * @param event
+ */
+ public void execute(final Runnable event) {
+ Executor executor = getExecutor();
+ if (executor == null) {
+ logger.error("Cannot execute [" + event + "] because the executor is missing.");
+ } else {
+ executor.execute(event);
+ }
+ }
+
+
+ public Future> submit(Runnable event) {
+ Executor executor = getExecutor();
+ if (executor == null) {
+ logger.error("Cannot submit [" + event + "] because the executor is missing.");
+ } else {
+ return executor.submit(event);
+ }
+
+ return null;
+
+ }
+
+
+ public Future> submit(Callable> task) {
+ Executor executor = getExecutor();
+ if (executor == null) {
+ logger.error("Cannot submit [" + task + "] because the executor is missing.");
+ } else {
+ return executor.submit(task);
+ }
+
+ return null;
+ }
+
+
+
+ public void printStatus() {
+ Executor executor = getExecutor();
+ executor.getStatus().dumpInfo();
+ }
+
+
+ private Executor getExecutor() {
+ return executor;
+ }
+
+
+ public void shutdown() {
+ if (executor != null) {
+ List wasRunning = executor.threadPoolExecutor
+ .shutdownNow();
+ if (!wasRunning.isEmpty()) {
+ logger.info(executor + " had " + wasRunning + " on shutdown");
+ }
+ }
+ }
+
+
+ /**
+ * Executor instance.
+ */
+ private static class Executor {
+ /**
+ * how long to retain excess threads
+ */
+ final long keepAliveTimeInMillis = 1000;
+ /**
+ * the thread pool executor that services the requests
+ */
+ final TrackingThreadPoolExecutor threadPoolExecutor;
+ /**
+ * work queue to use - unbounded queue
+ */
+ final BlockingQueue q = new LinkedBlockingQueue();
+ private final String name;
+ private static final AtomicLong seqids = new AtomicLong(0);
+ private final long id;
+
+ protected Executor(String name, int maxThreads) {
+ this.id = seqids.incrementAndGet();
+ this.name = name;
+ //create the thread pool executor
+ this.threadPoolExecutor = new TrackingThreadPoolExecutor(
+ maxThreads, maxThreads, keepAliveTimeInMillis,
+ TimeUnit.MILLISECONDS, q);
+ // name the threads for this threadpool
+ ThreadFactoryBuilder tfb = new ThreadFactoryBuilder();
+ tfb.setNameFormat(this.name + "-%d");
+ this.threadPoolExecutor.setThreadFactory(tfb.build());
+ }
+
+ /**
+ * Submit the event to the queue for handling.
+ *
+ * @param event
+ */
+ void execute(final Runnable event) {
+ this.threadPoolExecutor.execute(event);
+ }
+
+ Future> submit(Runnable event) {
+ return this.threadPoolExecutor.submit(event);
+ }
+
+ Future> submit(Callable> event) {
+ return this.threadPoolExecutor.submit(event);
+ }
+
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "-" + id + "-" + name;
+ }
+
+ public ExecutorStatus getStatus() {
+ List queuedEvents = Lists.newArrayList();
+ for (Runnable r : q) {
+ queuedEvents.add(r);
+ }
+
+ List running = Lists.newArrayList();
+ for (Map.Entry e : threadPoolExecutor
+ .getRunningTasks().entrySet()) {
+ Runnable r = e.getValue();
+ running.add(new RunningEventStatus(e.getKey(), r));
+ }
+
+ return new ExecutorStatus(this, queuedEvents, running);
+ }
+ }
+
+
+ /**
+ * A subclass of ThreadPoolExecutor that keeps track of the Runnables that
+ * are executing at any given point in time.
+ */
+ static class TrackingThreadPoolExecutor extends ThreadPoolExecutor {
+ private ConcurrentMap running = Maps
+ .newConcurrentMap();
+
+ public TrackingThreadPoolExecutor(int corePoolSize,
+ int maximumPoolSize, long keepAliveTime, TimeUnit unit,
+ BlockingQueue workQueue) {
+ super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
+ }
+
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ super.afterExecute(r, t);
+ running.remove(Thread.currentThread());
+ }
+
+ @Override
+ protected void beforeExecute(Thread t, Runnable r) {
+ Runnable oldPut = running.put(t, r);
+ assert oldPut == null : "inconsistency for thread " + t;
+ super.beforeExecute(t, r);
+ }
+
+ /**
+ * @return a map of the threads currently running tasks inside this
+ * executor. Each key is an active thread, and the value is the
+ * task that is currently running. Note that this is not a
+ * stable snapshot of the map.
+ */
+ public ConcurrentMap getRunningTasks() {
+ return running;
+ }
+ }
+
+
+ /**
+ * A snapshot of the status of a particular executor. This includes the
+ * contents of the executor's pending queue, as well as the threads and
+ * events currently being processed.
+ *
+ * This is a consistent snapshot that is immutable once constructed.
+ */
+ public static class ExecutorStatus {
+ final Executor executor;
+ final List queuedEvents;
+ final List running;
+
+ ExecutorStatus(Executor executor, List queuedEvents,
+ List running) {
+ this.executor = executor;
+ this.queuedEvents = queuedEvents;
+ this.running = running;
+ }
+
+ public void dumpInfo() {
+
+ PrintWriter out = new PrintWriter(System.out);
+
+ out.write("Status for executor: " + executor + "\n");
+ out.write("=======================================\n");
+ out.write(queuedEvents.size() + " events queued, "
+ + running.size() + " running\n");
+ if (!queuedEvents.isEmpty()) {
+ out.write("Queued:\n");
+ for (Runnable e : queuedEvents) {
+ out.write(" " + e + "\n");
+ }
+ out.write("\n");
+ }
+ if (!running.isEmpty()) {
+ out.write("Running:\n");
+ for (RunningEventStatus stat : running) {
+ out.write(" Running on thread '"
+ + stat.threadInfo.getThreadName() + "': "
+ + stat.event + "\n");
+ out.write(ThreadUtils.formatThreadInfo(
+ stat.threadInfo, " "));
+ out.write("\n");
+ }
+ }
+ out.flush();
+ }
+ }
+
+
+ /**
+ * The status of a particular event that is in the middle of being handled
+ * by an executor.
+ */
+ public static class RunningEventStatus {
+ final ThreadInfo threadInfo;
+ final Runnable event;
+
+ public RunningEventStatus(Thread t, Runnable event) {
+ this.threadInfo = ThreadUtils.getThreadInfo(t);
+ this.event = event;
+ }
+ }
+}
\ No newline at end of file
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadUtils.java b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadUtils.java
new file mode 100644
index 0000000000..7b2fc928a6
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/thread/ThreadUtils.java
@@ -0,0 +1,202 @@
+/*
+ * 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 cn.escheduler.common.thread;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.concurrent.*;
+
+/**
+ * thread utils
+ */
+public class ThreadUtils {
+
+
+ private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+ private static final int STACK_DEPTH = 20;
+
+ /**
+ Wrapper over newCachedThreadPool. Thread names are formatted as prefix-ID, where ID is a
+ * unique, sequentially assigned integer.
+ * @param prefix
+ * @return
+ */
+ public static ThreadPoolExecutor newDaemonCachedThreadPool(String prefix){
+ ThreadFactory threadFactory = namedThreadFactory(prefix);
+ return ((ThreadPoolExecutor) Executors.newCachedThreadPool(threadFactory));
+ }
+
+ /**
+ * Create a thread factory that names threads with a prefix and also sets the threads to daemon.
+ * @param prefix
+ * @return
+ */
+ private static ThreadFactory namedThreadFactory(String prefix) {
+ return new ThreadFactoryBuilder().setDaemon(true).setNameFormat(prefix + "-%d").build();
+ }
+
+
+ /**
+ * Create a cached thread pool whose max number of threads is `maxThreadNumber`. Thread names
+ * are formatted as prefix-ID, where ID is a unique, sequentially assigned integer.
+ * @param prefix
+ * @param maxThreadNumber
+ * @param keepAliveSeconds
+ * @return
+ */
+ public static ThreadPoolExecutor newDaemonCachedThreadPool(String prefix ,
+ int maxThreadNumber,
+ int keepAliveSeconds){
+ ThreadFactory threadFactory = namedThreadFactory(prefix);
+ ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
+ // corePoolSize: the max number of threads to create before queuing the tasks
+ maxThreadNumber,
+ // maximumPoolSize: because we use LinkedBlockingDeque, this one is not used
+ maxThreadNumber,
+ keepAliveSeconds,
+ TimeUnit.SECONDS,
+ new LinkedBlockingQueue(),
+ threadFactory);
+ threadPool.allowCoreThreadTimeOut(true);
+ return threadPool;
+ }
+
+
+ /**
+ * Wrapper over newFixedThreadPool. Thread names are formatted as prefix-ID, where ID is a
+ * unique, sequentially assigned integer.
+ * @param nThreads
+ * @param prefix
+ * @return
+ */
+ public static ThreadPoolExecutor newDaemonFixedThreadPool(int nThreads , String prefix){
+ ThreadFactory threadFactory = namedThreadFactory(prefix);
+ return ((ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads, threadFactory));
+ }
+
+ /**
+ * Wrapper over newSingleThreadExecutor.
+ * @param threadName
+ * @return
+ */
+ public static ExecutorService newDaemonSingleThreadExecutor(String threadName){
+ ThreadFactory threadFactory = new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat(threadName)
+ .build();
+ return Executors.newSingleThreadExecutor(threadFactory);
+ }
+
+ /**
+ * Wrapper over newDaemonFixedThreadExecutor.
+ * @param threadName
+ * @param threadsNum
+ * @return
+ */
+ public static ExecutorService newDaemonFixedThreadExecutor(String threadName,int threadsNum){
+ ThreadFactory threadFactory = new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat(threadName)
+ .build();
+ return Executors.newFixedThreadPool(threadsNum,threadFactory);
+ }
+
+ /**
+ * Wrapper over ScheduledThreadPoolExecutor
+ * @param corePoolSize
+ * @return
+ */
+ public static ScheduledExecutorService newDaemonThreadScheduledExecutor(String threadName,int corePoolSize) {
+ ThreadFactory threadFactory = new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat(threadName)
+ .build();
+ ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
+ // By default, a cancelled task is not automatically removed from the work queue until its delay
+ // elapses. We have to enable it manually.
+ executor.setRemoveOnCancelPolicy(true);
+ return executor;
+ }
+
+
+ public static ThreadInfo getThreadInfo(Thread t) {
+ long tid = t.getId();
+ return threadBean.getThreadInfo(tid, STACK_DEPTH);
+ }
+
+
+ /**
+ * Format the given ThreadInfo object as a String.
+ * @param indent a prefix for each line, used for nested indentation
+ */
+ public static String formatThreadInfo(ThreadInfo threadInfo, String indent) {
+ StringBuilder sb = new StringBuilder();
+ appendThreadInfo(sb, threadInfo, indent);
+ return sb.toString();
+ }
+
+
+ /**
+ * Print all of the thread's information and stack traces.
+ *
+ * @param sb
+ * @param info
+ * @param indent
+ */
+ public static void appendThreadInfo(StringBuilder sb,
+ ThreadInfo info,
+ String indent) {
+ boolean contention = threadBean.isThreadContentionMonitoringEnabled();
+
+ if (info == null) {
+ sb.append(indent).append("Inactive (perhaps exited while monitoring was done)\n");
+ return;
+ }
+ String taskName = getTaskName(info.getThreadId(), info.getThreadName());
+ sb.append(indent).append("Thread ").append(taskName).append(":\n");
+
+ Thread.State state = info.getThreadState();
+ sb.append(indent).append(" State: ").append(state).append("\n");
+ sb.append(indent).append(" Blocked count: ").append(info.getBlockedCount()).append("\n");
+ sb.append(indent).append(" Waited count: ").append(info.getWaitedCount()).append("\n");
+ if (contention) {
+ sb.append(indent).append(" Blocked time: " + info.getBlockedTime()).append("\n");
+ sb.append(indent).append(" Waited time: " + info.getWaitedTime()).append("\n");
+ }
+ if (state == Thread.State.WAITING) {
+ sb.append(indent).append(" Waiting on ").append(info.getLockName()).append("\n");
+ } else if (state == Thread.State.BLOCKED) {
+ sb.append(indent).append(" Blocked on ").append(info.getLockName()).append("\n");
+ sb.append(indent).append(" Blocked by ").append(
+ getTaskName(info.getLockOwnerId(), info.getLockOwnerName())).append("\n");
+ }
+ sb.append(indent).append(" Stack:").append("\n");
+ for (StackTraceElement frame: info.getStackTrace()) {
+ sb.append(indent).append(" ").append(frame.toString()).append("\n");
+ }
+ }
+
+ private static String getTaskName(long id, String name) {
+ if (name == null) {
+ return Long.toString(id);
+ }
+ return id + " (" + name + ")";
+ }
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/utils/Bytes.java b/escheduler-common/src/main/java/cn/escheduler/common/utils/Bytes.java
new file mode 100644
index 0000000000..9cb4e094a6
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/utils/Bytes.java
@@ -0,0 +1,697 @@
+/*
+ * 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 cn.escheduler.common.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Utility class that handles Bytes
+ */
+public class Bytes {
+
+ private static final Logger logger = LoggerFactory.getLogger(Bytes.class);
+ public static final String UTF8_ENCODING = "UTF-8";
+ //An empty instance.
+ public static final byte [] EMPTY_BYTE_ARRAY = new byte [0];
+
+ /**
+ * Size of int in bytes
+ */
+ public static final int SIZEOF_INT = Integer.SIZE / Byte.SIZE;
+
+ /**
+ * Size of long in bytes
+ */
+ public static final int SIZEOF_LONG = Long.SIZE / Byte.SIZE;
+
+ /**
+ * Size of short in bytes
+ */
+ public static final int SIZEOF_SHORT = Short.SIZE / Byte.SIZE;
+
+
+
+ /**
+ * Put bytes at the specified byte array position.
+ * @param tgtBytes the byte array
+ * @param tgtOffset position in the array
+ * @param srcBytes array to write out
+ * @param srcOffset source offset
+ * @param srcLength source length
+ * @return incremented offset
+ */
+ public static int putBytes(byte[] tgtBytes, int tgtOffset, byte[] srcBytes,
+ int srcOffset, int srcLength) {
+ System.arraycopy(srcBytes, srcOffset, tgtBytes, tgtOffset, srcLength);
+ return tgtOffset + srcLength;
+ }
+
+ /**
+ * Write a single byte out to the specified byte array position.
+ * @param bytes the byte array
+ * @param offset position in the array
+ * @param b byte to write out
+ * @return incremented offset
+ */
+ public static int putByte(byte[] bytes, int offset, byte b) {
+ bytes[offset] = b;
+ return offset + 1;
+ }
+
+ /**
+ * Returns a new byte array, copied from the passed ByteBuffer.
+ * @param bb A ByteBuffer
+ * @return the byte array
+ */
+ public static byte[] toBytes(ByteBuffer bb) {
+ int length = bb.limit();
+ byte [] result = new byte[length];
+ System.arraycopy(bb.array(), bb.arrayOffset(), result, 0, length);
+ return result;
+ }
+
+ /**
+ * @param b Presumed UTF-8 encoded byte array.
+ * @return String made from b
+ */
+ public static String toString(final byte [] b) {
+ if (b == null) {
+ return null;
+ }
+ return toString(b, 0, b.length);
+ }
+
+ /**
+ * Joins two byte arrays together using a separator.
+ * @param b1 The first byte array.
+ * @param sep The separator to use.
+ * @param b2 The second byte array.
+ */
+ public static String toString(final byte [] b1,
+ String sep,
+ final byte [] b2) {
+ return toString(b1, 0, b1.length) + sep + toString(b2, 0, b2.length);
+ }
+
+ /**
+ * This method will convert utf8 encoded bytes into a string. If
+ * an UnsupportedEncodingException occurs, this method will eat it
+ * and return null instead.
+ *
+ * @param b Presumed UTF-8 encoded byte array.
+ * @param off offset into array
+ * @param len length of utf-8 sequence
+ * @return String made from b or null
+ */
+ public static String toString(final byte [] b, int off, int len) {
+ if (b == null) {
+ return null;
+ }
+ if (len == 0) {
+ return "";
+ }
+ return new String(b, off, len, StandardCharsets.UTF_8);
+ }
+
+
+ /**
+ * Converts a string to a UTF-8 byte array.
+ * @param s string
+ * @return the byte array
+ */
+ public static byte[] toBytes(String s) {
+ return s.getBytes(StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Convert a boolean to a byte array. True becomes -1
+ * and false becomes 0.
+ *
+ * @param b value
+ * @return b encoded in a byte array.
+ */
+ public static byte [] toBytes(final boolean b) {
+ return new byte[] { b ? (byte) -1 : (byte) 0 };
+ }
+
+ /**
+ * Reverses {@link #toBytes(boolean)}
+ * @param b array
+ * @return True or false.
+ */
+ public static boolean toBoolean(final byte [] b) {
+ if (b.length != 1) {
+ throw new IllegalArgumentException("Array has wrong size: " + b.length);
+ }
+ return b[0] != (byte) 0;
+ }
+
+ /**
+ * Convert a long value to a byte array using big-endian.
+ *
+ * @param val value to convert
+ * @return the byte array
+ */
+ public static byte[] toBytes(long val) {
+ byte [] b = new byte[8];
+ for (int i = 7; i > 0; i--) {
+ b[i] = (byte) val;
+ val >>>= 8;
+ }
+ b[0] = (byte) val;
+ return b;
+ }
+
+ /**
+ * Converts a byte array to a long value. Reverses
+ * {@link #toBytes(long)}
+ * @param bytes array
+ * @return the long value
+ */
+ public static long toLong(byte[] bytes) {
+ return toLong(bytes, 0, SIZEOF_LONG);
+ }
+
+ /**
+ * Converts a byte array to a long value. Assumes there will be
+ * {@link #SIZEOF_LONG} bytes available.
+ *
+ * @param bytes bytes
+ * @param offset offset
+ * @return the long value
+ */
+ public static long toLong(byte[] bytes, int offset) {
+ return toLong(bytes, offset, SIZEOF_LONG);
+ }
+
+ /**
+ * Converts a byte array to a long value.
+ *
+ * @param bytes array of bytes
+ * @param offset offset into array
+ * @param length length of data (must be {@link #SIZEOF_LONG})
+ * @return the long value
+ * @throws IllegalArgumentException if length is not {@link #SIZEOF_LONG} or
+ * if there's not enough room in the array at the offset indicated.
+ */
+ public static long toLong(byte[] bytes, int offset, final int length) {
+ if (length != SIZEOF_LONG || offset + length > bytes.length) {
+ throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG);
+ }
+ long l = 0;
+ for(int i = offset; i < offset + length; i++) {
+ l <<= 8;
+ l ^= bytes[i] & 0xFF;
+ }
+ return l;
+ }
+
+ private static IllegalArgumentException
+ explainWrongLengthOrOffset(final byte[] bytes,
+ final int offset,
+ final int length,
+ final int expectedLength) {
+ String reason;
+ if (length != expectedLength) {
+ reason = "Wrong length: " + length + ", expected " + expectedLength;
+ } else {
+ reason = "offset (" + offset + ") + length (" + length + ") exceed the"
+ + " capacity of the array: " + bytes.length;
+ }
+ return new IllegalArgumentException(reason);
+ }
+
+ /**
+ * Put a long value out to the specified byte array position.
+ * @param bytes the byte array
+ * @param offset position in the array
+ * @param val long to write out
+ * @return incremented offset
+ * @throws IllegalArgumentException if the byte array given doesn't have
+ * enough room at the offset specified.
+ */
+ public static int putLong(byte[] bytes, int offset, long val) {
+ if (bytes.length - offset < SIZEOF_LONG) {
+ throw new IllegalArgumentException("Not enough room to put a long at"
+ + " offset " + offset + " in a " + bytes.length + " byte array");
+ }
+ for(int i = offset + 7; i > offset; i--) {
+ bytes[i] = (byte) val;
+ val >>>= 8;
+ }
+ bytes[offset] = (byte) val;
+ return offset + SIZEOF_LONG;
+ }
+
+ /**
+ * Presumes float encoded as IEEE 754 floating-point "single format"
+ * @param bytes byte array
+ * @return Float made from passed byte array.
+ */
+ public static float toFloat(byte [] bytes) {
+ return toFloat(bytes, 0);
+ }
+
+ /**
+ * Presumes float encoded as IEEE 754 floating-point "single format"
+ * @param bytes array to convert
+ * @param offset offset into array
+ * @return Float made from passed byte array.
+ */
+ public static float toFloat(byte [] bytes, int offset) {
+ return Float.intBitsToFloat(toInt(bytes, offset, SIZEOF_INT));
+ }
+
+ /**
+ * @param bytes byte array
+ * @param offset offset to write to
+ * @param f float value
+ * @return New offset in bytes
+ */
+ public static int putFloat(byte [] bytes, int offset, float f) {
+ return putInt(bytes, offset, Float.floatToRawIntBits(f));
+ }
+
+ /**
+ * @param f float value
+ * @return the float represented as byte []
+ */
+ public static byte [] toBytes(final float f) {
+ // Encode it as int
+ return Bytes.toBytes(Float.floatToRawIntBits(f));
+ }
+
+ /**
+ * @param bytes byte array
+ * @return Return double made from passed bytes.
+ */
+ public static double toDouble(final byte [] bytes) {
+ return toDouble(bytes, 0);
+ }
+
+ /**
+ * @param bytes byte array
+ * @param offset offset where double is
+ * @return Return double made from passed bytes.
+ */
+ public static double toDouble(final byte [] bytes, final int offset) {
+ return Double.longBitsToDouble(toLong(bytes, offset, SIZEOF_LONG));
+ }
+
+ /**
+ * @param bytes byte array
+ * @param offset offset to write to
+ * @param d value
+ * @return New offset into array bytes
+ */
+ public static int putDouble(byte [] bytes, int offset, double d) {
+ return putLong(bytes, offset, Double.doubleToLongBits(d));
+ }
+
+ /**
+ * Serialize a double as the IEEE 754 double format output. The resultant
+ * array will be 8 bytes long.
+ *
+ * @param d value
+ * @return the double represented as byte []
+ */
+ public static byte [] toBytes(final double d) {
+ // Encode it as a long
+ return Bytes.toBytes(Double.doubleToRawLongBits(d));
+ }
+
+ /**
+ * Convert an int value to a byte array
+ * @param val value
+ * @return the byte array
+ */
+ public static byte[] toBytes(int val) {
+ byte [] b = new byte[4];
+ for(int i = 3; i > 0; i--) {
+ b[i] = (byte) val;
+ val >>>= 8;
+ }
+ b[0] = (byte) val;
+ return b;
+ }
+
+ /**
+ * Converts a byte array to an int value
+ * @param bytes byte array
+ * @return the int value
+ */
+ public static int toInt(byte[] bytes) {
+ return toInt(bytes, 0, SIZEOF_INT);
+ }
+
+ /**
+ * Converts a byte array to an int value
+ * @param bytes byte array
+ * @param offset offset into array
+ * @return the int value
+ */
+ public static int toInt(byte[] bytes, int offset) {
+ return toInt(bytes, offset, SIZEOF_INT);
+ }
+
+ /**
+ * Converts a byte array to an int value
+ * @param bytes byte array
+ * @param offset offset into array
+ * @param length length of int (has to be {@link #SIZEOF_INT})
+ * @return the int value
+ * @throws IllegalArgumentException if length is not {@link #SIZEOF_INT} or
+ * if there's not enough room in the array at the offset indicated.
+ */
+ public static int toInt(byte[] bytes, int offset, final int length) {
+ if (length != SIZEOF_INT || offset + length > bytes.length) {
+ throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT);
+ }
+ int n = 0;
+ for(int i = offset; i < (offset + length); i++) {
+ n <<= 8;
+ n ^= bytes[i] & 0xFF;
+ }
+ return n;
+ }
+
+ /**
+ * Put an int value out to the specified byte array position.
+ * @param bytes the byte array
+ * @param offset position in the array
+ * @param val int to write out
+ * @return incremented offset
+ * @throws IllegalArgumentException if the byte array given doesn't have
+ * enough room at the offset specified.
+ */
+ public static int putInt(byte[] bytes, int offset, int val) {
+ if (bytes.length - offset < SIZEOF_INT) {
+ throw new IllegalArgumentException("Not enough room to put an int at"
+ + " offset " + offset + " in a " + bytes.length + " byte array");
+ }
+ for(int i= offset + 3; i > offset; i--) {
+ bytes[i] = (byte) val;
+ val >>>= 8;
+ }
+ bytes[offset] = (byte) val;
+ return offset + SIZEOF_INT;
+ }
+
+ /**
+ * Convert a short value to a byte array of {@link #SIZEOF_SHORT} bytes long.
+ * @param val value
+ * @return the byte array
+ */
+ public static byte[] toBytes(short val) {
+ byte[] b = new byte[SIZEOF_SHORT];
+ b[1] = (byte) val;
+ val >>= 8;
+ b[0] = (byte) val;
+ return b;
+ }
+
+ /**
+ * Converts a byte array to a short value
+ * @param bytes byte array
+ * @return the short value
+ */
+ public static short toShort(byte[] bytes) {
+ return toShort(bytes, 0, SIZEOF_SHORT);
+ }
+
+ /**
+ * Converts a byte array to a short value
+ * @param bytes byte array
+ * @param offset offset into array
+ * @return the short value
+ */
+ public static short toShort(byte[] bytes, int offset) {
+ return toShort(bytes, offset, SIZEOF_SHORT);
+ }
+
+ /**
+ * Converts a byte array to a short value
+ * @param bytes byte array
+ * @param offset offset into array
+ * @param length length, has to be {@link #SIZEOF_SHORT}
+ * @return the short value
+ * @throws IllegalArgumentException if length is not {@link #SIZEOF_SHORT}
+ * or if there's not enough room in the array at the offset indicated.
+ */
+ public static short toShort(byte[] bytes, int offset, final int length) {
+ if (length != SIZEOF_SHORT || offset + length > bytes.length) {
+ throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT);
+ }
+ short n = 0;
+ n ^= bytes[offset] & 0xFF;
+ n <<= 8;
+ n ^= bytes[offset+1] & 0xFF;
+ return n;
+ }
+
+ /**
+ * This method will get a sequence of bytes from pos -> limit,
+ * but will restore pos after.
+ * @param buf
+ * @return byte array
+ */
+ public static byte[] getBytes(ByteBuffer buf) {
+ int savedPos = buf.position();
+ byte [] newBytes = new byte[buf.remaining()];
+ buf.get(newBytes);
+ buf.position(savedPos);
+ return newBytes;
+ }
+
+ /**
+ * Put a short value out to the specified byte array position.
+ * @param bytes the byte array
+ * @param offset position in the array
+ * @param val short to write out
+ * @return incremented offset
+ * @throws IllegalArgumentException if the byte array given doesn't have
+ * enough room at the offset specified.
+ */
+ public static int putShort(byte[] bytes, int offset, short val) {
+ if (bytes.length - offset < SIZEOF_SHORT) {
+ throw new IllegalArgumentException("Not enough room to put a short at"
+ + " offset " + offset + " in a " + bytes.length + " byte array");
+ }
+ bytes[offset+1] = (byte) val;
+ val >>= 8;
+ bytes[offset] = (byte) val;
+ return offset + SIZEOF_SHORT;
+ }
+
+ /**
+ * Convert a BigDecimal value to a byte array
+ *
+ * @param val
+ * @return the byte array
+ */
+ public static byte[] toBytes(BigDecimal val) {
+ byte[] valueBytes = val.unscaledValue().toByteArray();
+ byte[] result = new byte[valueBytes.length + SIZEOF_INT];
+ int offset = putInt(result, 0, val.scale());
+ putBytes(result, offset, valueBytes, 0, valueBytes.length);
+ return result;
+ }
+
+
+ /**
+ * Converts a byte array to a BigDecimal
+ *
+ * @param bytes
+ * @return the char value
+ */
+ public static BigDecimal toBigDecimal(byte[] bytes) {
+ return toBigDecimal(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Converts a byte array to a BigDecimal value
+ *
+ * @param bytes
+ * @param offset
+ * @param length
+ * @return the char value
+ */
+ public static BigDecimal toBigDecimal(byte[] bytes, int offset, final int length) {
+ if (bytes == null || length < SIZEOF_INT + 1 ||
+ (offset + length > bytes.length)) {
+ return null;
+ }
+
+ int scale = toInt(bytes, offset);
+ byte[] tcBytes = new byte[length - SIZEOF_INT];
+ System.arraycopy(bytes, offset + SIZEOF_INT, tcBytes, 0, length - SIZEOF_INT);
+ return new BigDecimal(new BigInteger(tcBytes), scale);
+ }
+
+ /**
+ * Put a BigDecimal value out to the specified byte array position.
+ *
+ * @param bytes the byte array
+ * @param offset position in the array
+ * @param val BigDecimal to write out
+ * @return incremented offset
+ */
+ public static int putBigDecimal(byte[] bytes, int offset, BigDecimal val) {
+ if (bytes == null) {
+ return offset;
+ }
+
+ byte[] valueBytes = val.unscaledValue().toByteArray();
+ byte[] result = new byte[valueBytes.length + SIZEOF_INT];
+ offset = putInt(result, offset, val.scale());
+ return putBytes(result, offset, valueBytes, 0, valueBytes.length);
+ }
+
+ /**
+ * @param a lower half
+ * @param b upper half
+ * @return New array that has a in lower half and b in upper half.
+ */
+ public static byte [] add(final byte [] a, final byte [] b) {
+ return add(a, b, EMPTY_BYTE_ARRAY);
+ }
+
+ /**
+ * @param a first third
+ * @param b second third
+ * @param c third third
+ * @return New array made from a, b and c
+ */
+ public static byte [] add(final byte [] a, final byte [] b, final byte [] c) {
+ byte [] result = new byte[a.length + b.length + c.length];
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
+ System.arraycopy(c, 0, result, a.length + b.length, c.length);
+ return result;
+ }
+
+ /**
+ * @param a array
+ * @param length amount of bytes to grab
+ * @return First length bytes from a
+ */
+ public static byte [] head(final byte [] a, final int length) {
+ if (a.length < length) {
+ return null;
+ }
+ byte [] result = new byte[length];
+ System.arraycopy(a, 0, result, 0, length);
+ return result;
+ }
+
+ /**
+ * @param a array
+ * @param length amount of bytes to snarf
+ * @return Last length bytes from a
+ */
+ public static byte [] tail(final byte [] a, final int length) {
+ if (a.length < length) {
+ return null;
+ }
+ byte [] result = new byte[length];
+ System.arraycopy(a, a.length - length, result, 0, length);
+ return result;
+ }
+
+ /**
+ * @param a array
+ * @param length new array size
+ * @return Value in a plus length prepended 0 bytes
+ */
+ public static byte [] padHead(final byte [] a, final int length) {
+ byte[] padding = getPadding(length);
+ return add(padding,a);
+ }
+
+ private static byte[] getPadding(int length) {
+ byte[] padding = new byte[length];
+ for (int i = 0; i < length; i++) {
+ padding[i] = 0;
+ }
+ return padding;
+ }
+
+ /**
+ * @param a array
+ * @param length new array size
+ * @return Value in a plus length appended 0 bytes
+ */
+ public static byte [] padTail(final byte [] a, final int length) {
+ byte[] padding = getPadding(length);
+ return add(a,padding);
+ }
+
+
+
+ /**
+ * @param bytes array to hash
+ * @param offset offset to start from
+ * @param length length to hash
+ * */
+ public static int hashCode(byte[] bytes, int offset, int length) {
+ int hash = 1;
+ for (int i = offset; i < offset + length; i++) {
+ hash = (31 * hash) + (int) bytes[i];
+ }
+ return hash;
+ }
+
+ /**
+ * @param t operands
+ * @return Array of byte arrays made from passed array of Text
+ */
+ public static byte [][] toByteArrays(final String [] t) {
+ byte [][] result = new byte[t.length][];
+ for (int i = 0; i < t.length; i++) {
+ result[i] = Bytes.toBytes(t[i]);
+ }
+ return result;
+ }
+
+ /**
+ * @param column operand
+ * @return A byte array of a byte array where first and only entry is
+ * column
+ */
+ public static byte [][] toByteArrays(final String column) {
+ return toByteArrays(toBytes(column));
+ }
+
+ /**
+ * @param column operand
+ * @return A byte array of a byte array where first and only entry is
+ * column
+ */
+ public static byte [][] toByteArrays(final byte [] column) {
+ byte [][] result = new byte[1][];
+ result[0] = column;
+ return result;
+ }
+
+
+}
diff --git a/escheduler-common/src/main/java/cn/escheduler/common/utils/CollectionUtils.java b/escheduler-common/src/main/java/cn/escheduler/common/utils/CollectionUtils.java
new file mode 100644
index 0000000000..907b6b51a9
--- /dev/null
+++ b/escheduler-common/src/main/java/cn/escheduler/common/utils/CollectionUtils.java
@@ -0,0 +1,292 @@
+/*
+ * 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 cn.escheduler.common.utils;
+
+
+import org.apache.commons.collections.BeanMap;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.*;
+
+
+/**
+ * Provides utility methods and decorators for {@link Collection} instances.
+ *
+ * Various utility methods might put the input objects into a Set/Map/Bag. In case
+ * the input objects override {@link Object#equals(Object)}, it is mandatory that
+ * the general contract of the {@link Object#hashCode()} method is maintained.
+ *
+ * NOTE: From 4.0, method parameters will take {@link Iterable} objects when possible.
+ *
+ * @version $Id: CollectionUtils.java 1686855 2015-06-22 13:00:27Z tn $
+ * @since 1.0
+ */
+public class CollectionUtils {
+
+ /**
+ * Returns a new {@link Collection} containing a minus a subset of
+ * b. Only the elements of b that satisfy the predicate
+ * condition, p are subtracted from a.
+ *
+ *
The cardinality of each element e in the returned {@link Collection}
+ * that satisfies the predicate condition will be the cardinality of e in a
+ * minus the cardinality of e in b, or zero, whichever is greater.
+ *
The cardinality of each element e in the returned {@link Collection} that does not
+ * satisfy the predicate condition will be equal to the cardinality of e in a.
+ *
+ * @param a the collection to subtract from, must not be null
+ * @param b the collection to subtract, must not be null
+ * @return a new collection with the results
+ * @see Collection#removeAll
+ */
+ public static Collection subtract(Set a, Set b) {
+ return org.apache.commons.collections4.CollectionUtils.subtract(a, b);
+ }
+
+ public static boolean isNotEmpty(Collection coll) {
+ return !isEmpty(coll);
+ }
+
+ public static boolean isEmpty(Collection coll) {
+ return coll == null || coll.isEmpty();
+ }
+
+ /**
+ * String to map
+ *
+ * @param str string
+ * @param separator separator
+ * @return
+ */
+ public static Map stringToMap(String str, String separator) {
+ return stringToMap(str, separator, "");
+ }
+
+ /**
+ * String to map
+ *
+ * @param str string
+ * @param separator separator
+ * @param keyPrefix prefix
+ * @return
+ */
+ public static Map stringToMap(String str, String separator, String keyPrefix) {
+ if (null == str || "".equals(str)) {
+ return null;
+ }
+ if (null == separator || "".equals(separator)) {
+ return null;
+ }
+ String[] strings = str.split(separator);
+ int mapLength = strings.length;
+ if ((strings.length % 2) != 0) {
+ mapLength = mapLength + 1;
+ }
+
+ Map map = new HashMap<>(mapLength);
+ for (int i = 0; i < strings.length; i++) {
+ String[] strArray = strings[i].split("=");
+ //strArray[0] KEY strArray[1] VALUE
+ if (StringUtils.isEmpty(keyPrefix)) {
+ map.put(strArray[0], strArray[1]);
+ } else {
+ map.put(keyPrefix + strArray[0], strArray[1]);
+ }
+ }
+ return map;
+ }
+
+
+ /**
+ * Helper class to easily access cardinality properties of two collections.
+ *
+ * @param the element type
+ */
+ private static class CardinalityHelper {
+
+ /**
+ * Contains the cardinality for each object in collection A.
+ */
+ final Map cardinalityA;
+
+ /**
+ * Contains the cardinality for each object in collection B.
+ */
+ final Map cardinalityB;
+
+ /**
+ * Create a new CardinalityHelper for two collections.
+ *
+ * @param a the first collection
+ * @param b the second collection
+ */
+ public CardinalityHelper(final Iterable extends O> a, final Iterable extends O> b) {
+ cardinalityA = CollectionUtils.getCardinalityMap(a);
+ cardinalityB = CollectionUtils.getCardinalityMap(b);
+ }
+
+ /**
+ * Returns the maximum frequency of an object.
+ *
+ * @param obj the object
+ * @return the maximum frequency of the object
+ */
+ public final int max(final Object obj) {
+ return Math.max(freqA(obj), freqB(obj));
+ }
+
+ /**
+ * Returns the minimum frequency of an object.
+ *
+ * @param obj the object
+ * @return the minimum frequency of the object
+ */
+ public final int min(final Object obj) {
+ return Math.min(freqA(obj), freqB(obj));
+ }
+
+ /**
+ * Returns the frequency of this object in collection A.
+ *
+ * @param obj the object
+ * @return the frequency of the object in collection A
+ */
+ public int freqA(final Object obj) {
+ return getFreq(obj, cardinalityA);
+ }
+
+ /**
+ * Returns the frequency of this object in collection B.
+ *
+ * @param obj the object
+ * @return the frequency of the object in collection B
+ */
+ public int freqB(final Object obj) {
+ return getFreq(obj, cardinalityB);
+ }
+
+ private final int getFreq(final Object obj, final Map, Integer> freqMap) {
+ final Integer count = freqMap.get(obj);
+ if (count != null) {
+ return count.intValue();
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * returns {@code true} iff the given {@link Collection}s contain
+ * exactly the same elements with exactly the same cardinalities.
+ *
+ * @param a the first collection
+ * @param b the second collection
+ * @return Returns true iff the given Collections contain exactly the same elements with exactly the same cardinalities.
+ * That is, iff the cardinality of e in a is equal to the cardinality of e in b, for each element e in a or b.
+ */
+ public static boolean equalLists(Collection> a, Collection> b) {
+ if (a == null && b == null) {
+ return true;
+ }
+
+ if ((a == null && b != null) || a != null && b == null) {
+ return false;
+ }
+
+ return isEqualCollection(a, b);
+ }
+
+ /**
+ * Returns {@code true} iff the given {@link Collection}s contain
+ * exactly the same elements with exactly the same cardinalities.
+ *
+ * That is, iff the cardinality of e in a is
+ * equal to the cardinality of e in b,
+ * for each element e in a or b.
+ *
+ * @param a the first collection, must not be null
+ * @param b the second collection, must not be null
+ * @return true iff the collections contain the same elements with the same cardinalities.
+ */
+ public static boolean isEqualCollection(final Collection> a, final Collection> b) {
+ if (a.size() != b.size()) {
+ return false;
+ }
+ final CardinalityHelper