You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2020/07/21 06:43:58 UTC
[shardingsphere-elasticjob-ui] 02/26: UI refactor
This is an automated email from the ASF dual-hosted git repository.
zhangliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere-elasticjob-ui.git
commit 61f0d2361dabca697d232ee041b6363b34d7245e
Author: menghaoranss <lo...@163.com>
AuthorDate: Thu Jul 16 12:37:31 2020 +0800
UI refactor
---
shardingsphere-elasticjob-ui-backend/pom.xml | 93 ++++++++-
.../shardingsphere/elasticjob/ui/Bootstrap.java | 39 ++++
.../ui/config/DynamicDataSourceConfig.java | 116 +++++++++++
.../elasticjob/ui/config/FilterConfiguration.java | 73 +++++++
.../config/advice/ConsoleRestControllerAdvice.java | 67 +++++++
.../ui/dao/search/JobExecutionLogRepository.java | 25 +++
.../ui/dao/search/JobStatusTraceLogRepository.java | 25 +++
.../JobRegisterStatisticsRepository.java | 43 ++++
.../statistics/JobRunningStatisticsRepository.java | 43 ++++
.../ui/dao/statistics/StatisticInterval.java | 37 ++++
.../statistics/TaskResultStatisticsRepository.java | 55 ++++++
.../TaskRunningStatisticsRepository.java | 43 ++++
.../type/job/JobExecutionTypeStatistics.java | 33 ++++
.../dao/statistics/type/job/JobTypeStatistics.java | 35 ++++
.../elasticjob/ui/domain/DataSourceFactory.java | 41 ++++
.../elasticjob/ui/domain/EventTraceDataSource.java | 52 +++++
.../domain/EventTraceDataSourceConfiguration.java | 66 +++++++
.../domain/EventTraceDataSourceConfigurations.java | 37 ++++
.../ui/domain/EventTraceDataSourceFactory.java | 66 +++++++
.../elasticjob/ui/domain/GlobalConfiguration.java | 39 ++++
.../elasticjob/ui/domain/JobExecutionLog.java | 86 ++++++++
.../ui/domain/JobRegisterStatistics.java | 59 ++++++
.../elasticjob/ui/domain/JobRunningStatistics.java | 59 ++++++
.../elasticjob/ui/domain/JobStatusTraceLog.java | 86 ++++++++
.../ui/domain/RegistryCenterConfiguration.java | 56 ++++++
.../ui/domain/RegistryCenterConfigurations.java | 37 ++++
.../elasticjob/ui/domain/TaskResultStatistics.java | 72 +++++++
.../ui/domain/TaskRunningStatistics.java | 59 ++++++
.../elasticjob/ui/dto/request/BasePageRequest.java | 60 ++++++
.../dto/request/FindJobExecutionEventsRequest.java | 76 ++++++++
.../request/FindJobStatusTraceEventsRequest.java | 63 ++++++
.../ui/dto/response/BasePageResponse.java | 65 ++++++
.../ui/exception/JobConsoleException.java | 45 +++++
.../ui/repository/ConfigurationsXmlRepository.java | 26 +++
.../elasticjob/ui/repository/XmlRepository.java | 40 ++++
.../repository/impl/AbstractXmlRepositoryImpl.java | 80 ++++++++
.../impl/ConfigurationsXmlRepositoryImpl.java | 31 +++
.../ui/security/AuthenticationFilter.java | 99 ++++++++++
.../ui/security/AuthenticationResult.java | 39 ++++
.../elasticjob/ui/security/UserAccount.java | 33 ++++
.../ui/security/UserAuthenticationService.java | 74 +++++++
.../EventTraceDataSourceConfigurationService.java | 75 +++++++
.../ui/service/EventTraceHistoryService.java | 46 +++++
.../elasticjob/ui/service/JobAPIService.java | 70 +++++++
.../RegistryCenterConfigurationService.java | 75 +++++++
...entTraceDataSourceConfigurationServiceImpl.java | 124 ++++++++++++
.../service/impl/EventTraceHistoryServiceImpl.java | 132 +++++++++++++
.../ui/service/impl/JobAPIServiceImpl.java | 73 +++++++
.../RegistryCenterConfigurationServiceImpl.java | 113 +++++++++++
.../elasticjob/ui/util/BeanUtils.java | 56 ++++++
.../elasticjob/ui/util/HomeFolderUtils.java | 58 ++++++
.../SessionEventTraceDataSourceConfiguration.java | 42 ++++
.../util/SessionRegistryCenterConfiguration.java | 49 +++++
.../controller/EventTraceDataSourceController.java | 138 +++++++++++++
.../controller/EventTraceHistoryController.java | 67 +++++++
.../ui/web/controller/JobConfigController.java | 77 ++++++++
.../ui/web/controller/JobOperationController.java | 139 +++++++++++++
.../web/controller/RegistryCenterController.java | 124 ++++++++++++
.../web/controller/ServerOperationController.java | 162 +++++++++++++++
.../elasticjob/ui/web/filter/CORSFilter.java | 60 ++++++
.../elasticjob/ui/web/response/ResponseResult.java | 45 +++++
.../ui/web/response/ResponseResultUtil.java | 120 ++++++++++++
.../src/main/resources/application.properties | 15 +-
.../ui/dao/search/RDBJobEventSearchTest.java | 217 +++++++++++++++++++++
.../search/RDBJobEventSearchTestConfiguration.java | 70 +++++++
.../statistics/rdb/RDBStatisticRepositoryTest.java | 175 +++++++++++++++++
.../elasticjob/ui/util/HomeFolderUtilsTest.java | 35 ++++
.../config/index.js | 2 +-
.../src/lang/en-US.js | 37 ++--
.../src/lang/zh-CN.js | 37 ++--
70 files changed, 4672 insertions(+), 34 deletions(-)
diff --git a/shardingsphere-elasticjob-ui-backend/pom.xml b/shardingsphere-elasticjob-ui-backend/pom.xml
index 302129e..ac95197 100644
--- a/shardingsphere-elasticjob-ui-backend/pom.xml
+++ b/shardingsphere-elasticjob-ui-backend/pom.xml
@@ -25,9 +25,98 @@
</parent>
<artifactId>shardingsphere-elasticjob-ui-backend</artifactId>
<name>${project.artifactId}</name>
-
+
+ <properties>
+ <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
+ <springframework.version>5.2.7.RELEASE</springframework.version>
+ </properties>
+
<dependencies>
-
+ <dependency>
+ <groupId>org.apache.shardingsphere.elasticjob</groupId>
+ <artifactId>elasticjob-lite-lifecycle</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <version>${spring-boot.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-jpa</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${springframework.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <version>${springframework.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <version>${springframework.version}</version>
+ <scope>compile</scope>
+ <exclusions>
+ <exclusion>
+ <artifactId>spring-web</artifactId>
+ <groupId>org.springframework</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>spring-context</artifactId>
+ <groupId>org.springframework</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>log4j-over-slf4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-dbcp2</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-dbcp</groupId>
+ <artifactId>commons-dbcp</artifactId>
+ <version>1.4</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.java
new file mode 100644
index 0000000..3af08d0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/Bootstrap.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 org.apache.shardingsphere.elasticjob.ui;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Console bootstrap.
+ */
+@SpringBootApplication
+public class Bootstrap {
+
+ /**
+ * Startup RESTful server.
+ *
+ * @param args arguments
+ */
+ //CHECKSTYLE:OFF
+ public static void main(final String[] args) {
+ //CHECKSTYLE:ON
+ SpringApplication.run(Bootstrap.class, args);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java
new file mode 100644
index 0000000..8e87862
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/DynamicDataSourceConfig.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.config;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Dynamic datasource config.
+ */
+@Configuration
+public class DynamicDataSourceConfig {
+
+ public static final String DRIVER_CLASS_NAME = "spring.datasource.default.driver-class-name";
+
+ public static final String DATASOURCE_URL = "spring.datasource.default.url";
+
+ public static final String DATASOURCE_USERNAME = "spring.datasource.default.username";
+
+ public static final String DATASOURCE_PASSWORD = "spring.datasource.default.password";
+
+ public static final String DEFAULT_DATASOURCE_NAME = "default";
+
+ /**
+ * Declare dynamicDataSource instead of default dataSource.
+ * @param environment spring environment
+ * @return A subClass of AbstractRoutingDataSource
+ */
+ @Bean(name = "dynamicDataSource")
+ @Primary
+ public DynamicDataSource dynamicDataSource(final Environment environment) {
+ DataSource defaultDataSource = createDefaultDataSource(environment);
+ DynamicDataSource dynamicDataSource = new DynamicDataSource();
+ dynamicDataSource.addDataSource(DEFAULT_DATASOURCE_NAME, defaultDataSource);
+ dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
+ return dynamicDataSource;
+ }
+
+ private DataSource createDefaultDataSource(final Environment environment) {
+ String driverName = environment.getProperty(DRIVER_CLASS_NAME);
+ String url = environment.getProperty(DATASOURCE_URL);
+ String username = environment.getProperty(DATASOURCE_USERNAME);
+ String password = environment.getProperty(DATASOURCE_PASSWORD);
+ return DataSourceBuilder.create().driverClassName(driverName).type(BasicDataSource.class).url(url)
+ .username(username).password(password).build();
+ }
+
+ public static class DynamicDataSource extends AbstractRoutingDataSource {
+
+ private final Map<Object, Object> dataSourceMap = new HashMap<>(10);
+
+ @Override
+ protected Object determineCurrentLookupKey() {
+ return DynamicDataSourceContextHolder.getDataSourceName();
+ }
+
+ /**
+ * Add a data source.
+ *
+ * @param dataSourceName data source name
+ * @param dataSource data source
+ */
+ public void addDataSource(final String dataSourceName, final DataSource dataSource) {
+ dataSourceMap.put(dataSourceName, dataSource);
+ setTargetDataSources(dataSourceMap);
+ afterPropertiesSet();
+ }
+ }
+
+ public static class DynamicDataSourceContextHolder {
+
+ private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
+
+ /**
+ * Get the specify dataSource.
+ *
+ * @return data source name
+ */
+ public static String getDataSourceName() {
+ return CONTEXT_HOLDER.get();
+ }
+
+ /**
+ * Specify a dataSource.
+ *
+ * @param dataSourceName data source name
+ */
+ public static void setDataSourceName(final String dataSourceName) {
+ CONTEXT_HOLDER.set(dataSourceName);
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.java
new file mode 100644
index 0000000..32f45b9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/FilterConfiguration.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 org.apache.shardingsphere.elasticjob.ui.config;
+
+import org.apache.shardingsphere.elasticjob.ui.security.AuthenticationFilter;
+import org.apache.shardingsphere.elasticjob.ui.security.UserAuthenticationService;
+import org.apache.shardingsphere.elasticjob.ui.web.filter.CORSFilter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Web filter configuration.
+ */
+@Configuration
+public class FilterConfiguration {
+
+ @Autowired
+ private UserAuthenticationService userAuthenticationService;
+
+ /**
+ * Register the CORS filter.
+ *
+ * @return filter registration bean
+ */
+ @Bean
+ public FilterRegistrationBean corsFilter() {
+ CORSFilter corsFilter = new CORSFilter();
+ FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
+ filterRegBean.setFilter(corsFilter);
+ List<String> urlPatterns = new ArrayList<>();
+ urlPatterns.add("/api/*");
+ filterRegBean.setUrlPatterns(urlPatterns);
+ return filterRegBean;
+ }
+
+ /**
+ * Register the authentication filter.
+ *
+ * @return filter registration bean
+ */
+ @Bean
+ public FilterRegistrationBean authenticationFilter() {
+ AuthenticationFilter authenticationFilter = new AuthenticationFilter();
+ authenticationFilter.setUserAuthenticationService(userAuthenticationService);
+ FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
+ filterRegBean.setFilter(authenticationFilter);
+ List<String> urlPatterns = new ArrayList<>();
+ urlPatterns.add("/api/*");
+ filterRegBean.setUrlPatterns(urlPatterns);
+ return filterRegBean;
+ }
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.java
new file mode 100644
index 0000000..e3e6898
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/config/advice/ConsoleRestControllerAdvice.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 org.apache.shardingsphere.elasticjob.ui.config.advice;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.infra.exception.ExceptionUtils;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * Console rest controller advice.
+ **/
+@RestControllerAdvice
+@Slf4j
+public final class ConsoleRestControllerAdvice implements ResponseBodyAdvice<Object> {
+
+ @Override
+ public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
+ //only advice return void method.
+ if (null == returnType.getMethod()) {
+ return false;
+ }
+ return void.class.isAssignableFrom(returnType.getMethod().getReturnType());
+ }
+
+ @Override
+ public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType,
+ final Class<? extends HttpMessageConverter<?>> selectedConverterType, final ServerHttpRequest request, final ServerHttpResponse response) {
+ //if the method return void, then the value is true and returns.
+ return null == body ? true : body;
+ }
+
+ /**
+ * Handle exception.
+ *
+ * @param ex exception
+ * @return response result
+ */
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity<String> toResponse(final Exception ex) {
+ log.error("CONSOLE ERROR", ex);
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ExceptionUtils.transform(ex));
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.java
new file mode 100644
index 0000000..c27d2c1
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobExecutionLogRepository.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 org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobExecutionLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface JobExecutionLogRepository extends JpaRepository<JobExecutionLog, String>, JpaSpecificationExecutor<JobExecutionLog> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.java
new file mode 100644
index 0000000..ee451f0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/search/JobStatusTraceLogRepository.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 org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobStatusTraceLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+public interface JobStatusTraceLogRepository extends JpaRepository<JobStatusTraceLog, String>, JpaSpecificationExecutor<JobStatusTraceLog> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java
new file mode 100644
index 0000000..393bd89
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRegisterStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRegisterStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Job register statistics repository.
+ */
+@Repository
+public interface JobRegisterStatisticsRepository extends JpaRepository<JobRegisterStatistics, Long> {
+
+ /**
+ * Find job register statistics.
+ *
+ * @param fromTime from date to statistics
+ * @return job register statistics
+ */
+ @Query("FROM JobRegisterStatistics WHERE statisticsTime >= :fromTime")
+ List<JobRegisterStatistics> findJobRegisterStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java
new file mode 100644
index 0000000..a5b8a1d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/JobRunningStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRunningStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Job running statistics repository.
+ */
+@Repository
+public interface JobRunningStatisticsRepository extends JpaRepository<JobRunningStatistics, Long> {
+
+ /**
+ * Find job running statistics.
+ *
+ * @param fromTime from date to statistics
+ * @return job running statistics
+ */
+ @Query("FROM JobRunningStatistics WHERE statisticsTime >= :fromTime")
+ List<JobRunningStatistics> findJobRunningStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.java
new file mode 100644
index 0000000..0322a03
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/StatisticInterval.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 org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Statistic interval.
+ */
+@Getter
+@RequiredArgsConstructor
+public enum StatisticInterval {
+
+ MINUTE("0 * * * * ?"),
+
+ HOUR("0 0 * * * ?"),
+
+ DAY("0 0 0 * * ?");
+
+ private final String cron;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java
new file mode 100644
index 0000000..248f027
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskResultStatisticsRepository.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskResultStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Task result statistics repository.
+ */
+@Repository
+public interface TaskResultStatisticsRepository extends JpaRepository<TaskResultStatistics, Long> {
+
+ /**
+ * Find task result statistics.
+ *
+ * @param fromTime from date to statistics
+ * @param statisticInterval statistic interval
+ * @return task result statistics
+ */
+ @Query("FROM TaskResultStatistics WHERE statisticInterval = :statisticInterval AND statisticsTime >= :fromTime ORDER BY id ASC")
+ List<TaskResultStatistics> findTaskResultStatistics(@Param("fromTime") Date fromTime, @Param("statisticInterval") String statisticInterval);
+
+ /**
+ * Get summed task result statistics.
+ *
+ * @param fromTime from date to statistics
+ * @param statisticInterval statistic interval
+ * @return summed task result statistics
+ */
+ @Query("SELECT new TaskResultStatistics(SUM(successCount), SUM(failedCount)) FROM TaskResultStatistics WHERE "
+ + "statisticInterval = :statisticInterval AND statisticsTime >= :fromTime")
+ TaskResultStatistics getSummedTaskResultStatistics(@Param("fromTime") Date fromTime, @Param("statisticInterval") String statisticInterval);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java
new file mode 100644
index 0000000..328028c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/TaskRunningStatisticsRepository.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.statistics;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskRunningStatistics;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Task running statistics repository.
+ */
+@Repository
+public interface TaskRunningStatisticsRepository extends JpaRepository<TaskRunningStatistics, Long> {
+
+ /**
+ * Find task running statistics.
+ *
+ * @param fromTime from date to statistics
+ * @return Task running statistics
+ */
+ @Query("FROM TaskRunningStatistics where statisticsTime >= :fromTime")
+ List<TaskRunningStatistics> findTaskRunningStatistics(@Param("fromTime") Date fromTime);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.java
new file mode 100644
index 0000000..8aace8d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobExecutionTypeStatistics.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 org.apache.shardingsphere.elasticjob.ui.dao.statistics.type.job;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Job execution type statistics.
+ */
+@Getter
+@AllArgsConstructor
+public final class JobExecutionTypeStatistics {
+
+ private int transientJobCount;
+
+ private int daemonJobCount;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.java
new file mode 100644
index 0000000..1a9a00c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/type/job/JobTypeStatistics.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 org.apache.shardingsphere.elasticjob.ui.dao.statistics.type.job;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Job type statistics.
+ */
+@Getter
+@AllArgsConstructor
+public final class JobTypeStatistics {
+
+ private int scriptJobCount;
+
+ private int simpleJobCount;
+
+ private int dataflowJobCount;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java
new file mode 100644
index 0000000..d7abd7b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/DataSourceFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+
+import javax.sql.DataSource;
+
+/**
+ * Dynamic data source factory.
+ */
+public final class DataSourceFactory {
+
+ /**
+ * Create a DataSource.
+ * @param config event trace data source config
+ * @return data source
+ */
+ public static DataSource createDataSource(final EventTraceDataSourceConfiguration config) {
+ // Determine whether the data source is valid.
+ new EventTraceDataSource(config).init();
+ return DataSourceBuilder.create().type(BasicDataSource.class).driverClassName(config.getDriver()).url(config.getUrl())
+ .username(config.getUsername()).password(config.getPassword()).build();
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java
new file mode 100644
index 0000000..bc0cad0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSource.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * Event tracing data source.
+ */
+@Slf4j
+public final class EventTraceDataSource {
+
+ @Getter(AccessLevel.PROTECTED)
+ private EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration;
+
+ public EventTraceDataSource(final EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration) {
+ this.eventTraceDataSourceConfiguration = eventTraceDataSourceConfiguration;
+ }
+
+ /**
+ * Initialize data source.
+ */
+ public void init() {
+ log.debug("Elastic job: data source init, connection url is: {}.", eventTraceDataSourceConfiguration.getUrl());
+ try {
+ Class.forName(eventTraceDataSourceConfiguration.getDriver());
+ DriverManager.getConnection(eventTraceDataSourceConfiguration.getUrl(), eventTraceDataSourceConfiguration.getUsername(), eventTraceDataSourceConfiguration.getPassword());
+ } catch (final ClassNotFoundException | SQLException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java
new file mode 100644
index 0000000..dc683f7
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfiguration.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * Event trace data source configuration.
+ */
+@NoArgsConstructor
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class EventTraceDataSourceConfiguration implements Serializable {
+
+ private static final long serialVersionUID = -5996257770767863699L;
+
+ @XmlAttribute(required = true)
+ private String name;
+
+ @XmlAttribute(required = true)
+ private String driver;
+
+ @XmlAttribute
+ private String url;
+
+ @XmlAttribute
+ private String username;
+
+ @XmlAttribute
+ private String password;
+
+ @XmlAttribute
+ private boolean activated;
+
+ public EventTraceDataSourceConfiguration(final String driver, final String url, final String username, final String password) {
+ this.driver = driver;
+ this.url = url;
+ this.username = username;
+ this.password = password;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.java
new file mode 100644
index 0000000..9250f7f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceConfigurations.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 org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Event trace data source configurations.
+ */
+@Getter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class EventTraceDataSourceConfigurations {
+
+ private Set<EventTraceDataSourceConfiguration> eventTraceDataSourceConfiguration = new LinkedHashSet<>();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java
new file mode 100644
index 0000000..36fc116
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/EventTraceDataSourceFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Event trace data source factory.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class EventTraceDataSourceFactory {
+
+ private static final ConcurrentHashMap<HashCode, EventTraceDataSource> DATA_SOURCE_REGISTRY = new ConcurrentHashMap<>();
+
+ /**
+ * Create event trace data source.
+ *
+ * @param driverClassName database driver class name
+ * @param url database URL
+ * @param username database username
+ * @param password database password
+ * @return event trace data source
+ */
+ public static EventTraceDataSource createEventTraceDataSource(final String driverClassName, final String url, final String username, final String password) {
+ Hasher hasher = Hashing.sha256().newHasher().putString(driverClassName, Charsets.UTF_8).putString(url, Charsets.UTF_8);
+ if (!Strings.isNullOrEmpty(username)) {
+ hasher.putString(username, Charsets.UTF_8);
+ }
+ if (null != password) {
+ hasher.putString(password, Charsets.UTF_8);
+ }
+ HashCode hashCode = hasher.hash();
+ EventTraceDataSource result = DATA_SOURCE_REGISTRY.get(hashCode);
+ if (null != result) {
+ return result;
+ }
+ EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration = new EventTraceDataSourceConfiguration(driverClassName, url, username, password);
+ result = new EventTraceDataSource(eventTraceDataSourceConfiguration);
+ result.init();
+ DATA_SOURCE_REGISTRY.put(hashCode, result);
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.java
new file mode 100644
index 0000000..273a90d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/GlobalConfiguration.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 org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Global configuration.
+ */
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class GlobalConfiguration {
+
+ private RegistryCenterConfigurations registryCenterConfigurations;
+
+ private EventTraceDataSourceConfigurations eventTraceDataSourceConfigurations;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java
new file mode 100644
index 0000000..ce98008
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobExecutionLog.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Data;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.Date;
+
+@Data
+@Entity(name = "JOB_EXECUTION_LOG")
+public class JobExecutionLog {
+
+ @Id
+ private String id;
+
+ @Column(name = "job_name")
+ private String jobName;
+
+ @Column(name = "task_id")
+ private String taskId;
+
+ @Column(name = "hostname")
+ private String hostname;
+
+ @Column(name = "ip")
+ private String ip;
+
+ @Column(name = "sharding_item")
+ private Integer shardingItem;
+
+ @Column(name = "execution_source")
+ private String executionSource;
+
+ @Column(name = "failure_cause")
+ private String failureCause;
+
+ @Column(name = "is_success")
+ private Boolean isSuccess;
+
+ @Column(name = "start_time")
+ private Date startTime;
+
+ @Column(name = "complete_time")
+ private Date completeTime;
+
+ /**
+ * JobExecutionLog convert to JobExecutionEvent.
+ *
+ * @return JobExecutionEvent entity
+ */
+ public JobExecutionEvent toJobExecutionEvent() {
+ return new JobExecutionEvent(
+ id,
+ hostname,
+ ip,
+ taskId,
+ jobName,
+ JobExecutionEvent.ExecutionSource.valueOf(executionSource),
+ shardingItem,
+ startTime,
+ completeTime,
+ isSuccess,
+ failureCause
+ );
+ }
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java
new file mode 100644
index 0000000..62f3713
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRegisterStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Job register statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "JOB_REGISTER_STATISTICS")
+public final class JobRegisterStatistics {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "registered_count", length = 11)
+ private Integer registeredCount;
+
+ @Column(name = "statistics_time", nullable = false)
+ private Date statisticsTime;
+
+ @Column(name = "creation_time", nullable = false)
+ private Date creationTime = new Date();
+
+ public JobRegisterStatistics(final Integer registeredCount, final Date statisticsTime) {
+ this.registeredCount = registeredCount;
+ this.statisticsTime = statisticsTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java
new file mode 100644
index 0000000..e8e5eea
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobRunningStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Job running statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "JOB_RUNNING_STATISTICS")
+public final class JobRunningStatistics {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "running_count", length = 11)
+ private Integer runningCount;
+
+ @Column(name = "statistics_time", nullable = false)
+ private Date statisticsTime;
+
+ @Column(name = "creation_time", nullable = false)
+ private Date creationTime = new Date();
+
+ public JobRunningStatistics(final Integer runningCount, final Date statisticsTime) {
+ this.runningCount = runningCount;
+ this.statisticsTime = statisticsTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java
new file mode 100644
index 0000000..7803e09
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/JobStatusTraceLog.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Data;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import java.util.Date;
+
+@Data
+@Entity(name = "JOB_STATUS_TRACE_LOG")
+public class JobStatusTraceLog {
+
+ @Id
+ private String id;
+
+ @Column(name = "job_name")
+ private String jobName;
+
+ @Column(name = "original_task_id")
+ private String originalTaskId;
+
+ @Column(name = "task_id")
+ private String taskId;
+
+ @Column(name = "slave_id")
+ private String slaveId;
+
+ @Column(name = "source")
+ private String source;
+
+ @Column(name = "execution_type")
+ private String executionType;
+
+ @Column(name = "sharding_item")
+ private String shardingItem;
+
+ @Column(name = "state")
+ private String state;
+
+ @Column(name = "message")
+ private String message;
+
+ @Column(name = "creation_time")
+ private Date creationTime;
+
+ /**
+ * JobStatusTraceLog convert to JobStatusTraceEvent.
+ *
+ * @return JobStatusTraceEvent entity
+ */
+ public JobStatusTraceEvent toJobStatusTraceEvent() {
+ return new JobStatusTraceEvent(
+ id,
+ jobName,
+ originalTaskId,
+ taskId,
+ slaveId,
+ JobStatusTraceEvent.Source.valueOf(source),
+ executionType,
+ shardingItem,
+ JobStatusTraceEvent.State.valueOf(state),
+ message,
+ creationTime
+ );
+ }
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java
new file mode 100644
index 0000000..6f46434
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+/**
+ * Registry center configuration.
+ */
+@Getter
+@Setter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+@NoArgsConstructor
+public final class RegistryCenterConfiguration implements Serializable {
+
+ private static final long serialVersionUID = -5996257770767863699L;
+
+ @XmlAttribute(required = true)
+ private String name;
+
+ @XmlAttribute(required = true)
+ private String zkAddressList;
+
+ @XmlAttribute
+ private String namespace;
+
+ @XmlAttribute
+ private String digest;
+
+ @XmlAttribute
+ private boolean activated;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.java
new file mode 100644
index 0000000..403d29f
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/RegistryCenterConfigurations.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 org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.Getter;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Registry center configurations.
+ */
+@Getter
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public final class RegistryCenterConfigurations {
+
+ private Set<RegistryCenterConfiguration> registryCenterConfiguration = new LinkedHashSet<>();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java
new file mode 100644
index 0000000..e0006d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskResultStatistics.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Task result statistics.
+ */
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@Entity
+@Table(name = "TASK_RESULT_STATISTICS")
+public final class TaskResultStatistics {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "success_count", length = 11)
+ private Long successCount;
+
+ @Column(name = "failed_count", length = 11)
+ private Long failedCount;
+
+ @Column(name = "statistic_interval", length = 10)
+ private String statisticInterval;
+
+ @Column(name = "statistics_time", nullable = false)
+ private Date statisticsTime;
+
+ @Column(name = "creation_time", nullable = false)
+ private Date creationTime = new Date();
+
+ public TaskResultStatistics(final Long successCount, final Long failedCount) {
+ this.successCount = successCount;
+ this.failedCount = failedCount;
+ }
+
+ public TaskResultStatistics(final Long successCount, final Long failedCount, final String statisticInterval, final Date statisticsTime) {
+ this.successCount = successCount;
+ this.failedCount = failedCount;
+ this.statisticInterval = statisticInterval;
+ this.statisticsTime = statisticsTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java
new file mode 100644
index 0000000..638ff6c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/domain/TaskRunningStatistics.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+/**
+ * Task running statistics.
+ */
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "TASK_RUNNING_STATISTICS")
+public final class TaskRunningStatistics {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "running_count", length = 11)
+ private Integer runningCount;
+
+ @Column(name = "statistics_time", nullable = false)
+ private Date statisticsTime;
+
+ @Column(name = "creation_time", nullable = false)
+ private Date creationTime = new Date();
+
+ public TaskRunningStatistics(final Integer runningCount, final Date statisticsTime) {
+ this.runningCount = runningCount;
+ this.statisticsTime = statisticsTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java
new file mode 100644
index 0000000..2358c03
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/BasePageRequest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Pageable request base request.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class BasePageRequest {
+
+ public static final int DEFAULT_PAGE_SIZE = 10;
+
+ /**
+ * Page size of request.
+ */
+ @JsonProperty("per_page")
+ private Integer pageSize = DEFAULT_PAGE_SIZE;
+
+ /**
+ * Page number of request.
+ */
+ @JsonProperty("page")
+ private Integer pageNumber = 1;
+
+ /**
+ * The field name for sort by.
+ */
+ @JsonProperty("sort")
+ private String sortBy;
+
+ /**
+ * Order type, asc or desc.
+ */
+ @JsonProperty("order")
+ private String orderType;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java
new file mode 100644
index 0000000..c937059
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobExecutionEventsRequest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * Request object of uri '/event-trace/execution'.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class FindJobExecutionEventsRequest extends BasePageRequest {
+
+ private String jobName;
+
+ private String ip;
+
+ private Boolean isSuccess;
+
+ @JsonProperty("startTime")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date start;
+
+ @JsonProperty("endTime")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date end;
+
+ /**
+ * Create new FindJobExecutionEventsRequest with pageSize and pageNumber.
+ * @param pageNumber page number
+ * @param pageSize page size
+ */
+ public FindJobExecutionEventsRequest(final Integer pageSize, final Integer pageNumber) {
+ super(pageSize, pageNumber, null, null);
+ }
+
+ /**
+ * Create new FindJobExecutionEventsRequest with properties.
+ * @param pageNumber page number
+ * @param pageSize page size
+ * @param sortBy the field name sort by
+ * @param orderType order type, asc or desc
+ * @param startTime start time
+ * @param endTime end time
+ */
+ public FindJobExecutionEventsRequest(final Integer pageSize, final Integer pageNumber, final String sortBy,
+ final String orderType, final Date startTime, final Date endTime) {
+ super(pageSize, pageNumber, sortBy, orderType);
+ this.start = startTime;
+ this.end = endTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java
new file mode 100644
index 0000000..f10e0e6
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/request/FindJobStatusTraceEventsRequest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.request;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * Request object of uri '/event-trace/status'.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class FindJobStatusTraceEventsRequest extends BasePageRequest {
+
+ private String jobName;
+
+ private String source;
+
+ private String executionType;
+
+ private String state;
+
+ @JsonProperty("startTime")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date start;
+
+ @JsonProperty("endTime")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date end;
+
+ public FindJobStatusTraceEventsRequest(final Integer pageSize, final Integer pageNumber) {
+ super(pageSize, pageNumber, null, null);
+ }
+
+ public FindJobStatusTraceEventsRequest(final Integer pageSize, final Integer pageNumber, final String sortBy, final String orderType, final Date startTime, final Date endTime) {
+ super(pageSize, pageNumber, sortBy, orderType);
+ this.start = startTime;
+ this.end = endTime;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java
new file mode 100644
index 0000000..fdfd767
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/dto/response/BasePageResponse.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dto.response;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.data.domain.Page;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class BasePageResponse<T> implements Serializable {
+
+ /**
+ * Total count of rows.
+ */
+ private Long total;
+
+ /**
+ * Rows data.
+ */
+ private List<T> rows;
+
+ /**
+ * Create new BasePageResponse with total and data.
+ * @param total Total count of match data
+ * @param data Current page of data
+ * @param <T> Data type
+ * @return BasePageResponse
+ */
+ public static <T> BasePageResponse of(final Long total, final List<T> data) {
+ return new BasePageResponse(total, data);
+ }
+
+ /**
+ * Create new BasePageResponse with Page.
+ * @param page match data info.
+ * @param <T> Data type
+ * @return BasePageResponse
+ */
+ public static <T> BasePageResponse of(final Page<T> page) {
+ return new BasePageResponse(page.getTotalElements(), page.getContent());
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java
new file mode 100644
index 0000000..d2c0f29
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/exception/JobConsoleException.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.exception;
+
+import lombok.Getter;
+
+/**
+ * Job console exception.
+ */
+@Getter
+public final class JobConsoleException extends RuntimeException {
+
+ private static final long serialVersionUID = 1393957353478034407L;
+
+ public static final int INVALID_PARAM = 400;
+
+ public static final int NO_RIGHT = 403;
+
+ public static final int SERVER_ERROR = 500;
+
+ private final int errorCode;
+
+ private final String errorMessage;
+
+ public JobConsoleException(final int errorCode, final String errorMessage) {
+ super(errorMessage);
+ this.errorCode = errorCode;
+ this.errorMessage = errorMessage;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java
new file mode 100644
index 0000000..c9e644c
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/ConfigurationsXmlRepository.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.repository;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+
+/**
+ * Configurations XML repository.
+ */
+public interface ConfigurationsXmlRepository extends XmlRepository<GlobalConfiguration> {
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.java
new file mode 100644
index 0000000..e8f0caf
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/XmlRepository.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 org.apache.shardingsphere.elasticjob.ui.repository;
+
+/**
+ * XML repository.
+ *
+ * @param <E> type of data
+ */
+public interface XmlRepository<E> {
+
+ /**
+ * Load data.
+ *
+ * @return load result
+ */
+ E load();
+
+ /**
+ * Save data.
+ *
+ * @param entity entity
+ */
+ void save(E entity);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.java
new file mode 100644
index 0000000..fcb9247
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/AbstractXmlRepositoryImpl.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 org.apache.shardingsphere.elasticjob.ui.repository.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.exception.JobConsoleException;
+import org.apache.shardingsphere.elasticjob.ui.repository.XmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.util.HomeFolderUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import java.io.File;
+
+/**
+ * Abstract XML repository implementation.
+ *
+ * @param <E> type of data
+ */
+public abstract class AbstractXmlRepositoryImpl<E> implements XmlRepository<E> {
+
+ private final File file;
+
+ private final Class<E> clazz;
+
+ private JAXBContext jaxbContext;
+
+ protected AbstractXmlRepositoryImpl(final String fileName, final Class<E> clazz) {
+ file = new File(HomeFolderUtils.getFilePathInHomeFolder(fileName));
+ this.clazz = clazz;
+ HomeFolderUtils.createHomeFolderIfNotExisted();
+ try {
+ jaxbContext = JAXBContext.newInstance(clazz);
+ } catch (final JAXBException ex) {
+ throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public synchronized E load() {
+ if (!file.exists()) {
+ try {
+ return clazz.newInstance();
+ } catch (final InstantiationException | IllegalAccessException ex) {
+ throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+ }
+ }
+ try {
+ return (E) jaxbContext.createUnmarshaller().unmarshal(file);
+ } catch (final JAXBException ex) {
+ throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+ }
+ }
+
+ @Override
+ public synchronized void save(final E entity) {
+ try {
+ Marshaller marshaller = jaxbContext.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.marshal(entity, file);
+ } catch (final JAXBException ex) {
+ throw new JobConsoleException(JobConsoleException.SERVER_ERROR, ex.getMessage());
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.java
new file mode 100644
index 0000000..5b4b64e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/repository/impl/ConfigurationsXmlRepositoryImpl.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 org.apache.shardingsphere.elasticjob.ui.repository.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+
+/**
+ * Configurations XML repository implementation.
+ */
+public final class ConfigurationsXmlRepositoryImpl extends AbstractXmlRepositoryImpl<GlobalConfiguration> implements ConfigurationsXmlRepository {
+
+ public ConfigurationsXmlRepositoryImpl() {
+ super("Configurations.xml", GlobalConfiguration.class);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java
new file mode 100644
index 0000000..a892759
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationFilter.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import lombok.Setter;
+import org.apache.shardingsphere.elasticjob.ui.web.response.ResponseResultUtil;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Authentication filter.
+ */
+public final class AuthenticationFilter implements Filter {
+
+ private static final String LOGIN_URI = "/api/login";
+
+ private final Gson gson = new Gson();
+
+ @Setter
+ private UserAuthenticationService userAuthenticationService;
+
+ @Override
+ public void init(final FilterConfig filterConfig) {
+ }
+
+ @Override
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
+ HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
+ if (LOGIN_URI.equals(httpRequest.getRequestURI())) {
+ handleLogin(httpRequest, httpResponse);
+ } else {
+ String accessToken = httpRequest.getHeader("Access-Token");
+ if (!Strings.isNullOrEmpty(accessToken) && accessToken.equals(userAuthenticationService.getToken())) {
+ filterChain.doFilter(httpRequest, httpResponse);
+ } else {
+ respondWithUnauthorized(httpResponse);
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ private void handleLogin(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse) {
+ try {
+ UserAccount user = gson.fromJson(httpRequest.getReader(), UserAccount.class);
+ AuthenticationResult authenticationResult = userAuthenticationService.checkUser(user);
+ if (null != authenticationResult && authenticationResult.isSuccess()) {
+ httpResponse.setContentType("application/json");
+ httpResponse.setCharacterEncoding("UTF-8");
+ Map<String, Object> result = new HashMap<>();
+ result.put("username", authenticationResult.getUsername());
+ result.put("accessToken", userAuthenticationService.getToken());
+ result.put("isGuest", authenticationResult.isGuest());
+ httpResponse.getWriter().write(gson.toJson(ResponseResultUtil.build(result)));
+ } else {
+ respondWithUnauthorized(httpResponse);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ private void respondWithUnauthorized(final HttpServletResponse httpResponse) throws IOException {
+ httpResponse.setContentType("application/json");
+ httpResponse.setCharacterEncoding("UTF-8");
+ httpResponse.getWriter().write(new Gson().toJson(ResponseResultUtil.handleUnauthorizedException("Unauthorized.")));
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.java
new file mode 100644
index 0000000..8758f43
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/AuthenticationResult.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 org.apache.shardingsphere.elasticjob.ui.security;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Authentication result.
+ **/
+@Getter
+@RequiredArgsConstructor
+public final class AuthenticationResult {
+
+ private final String username;
+
+ private final String password;
+
+ private final boolean success;
+
+ private final boolean isGuest;
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.java
new file mode 100644
index 0000000..3fe02f3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAccount.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 org.apache.shardingsphere.elasticjob.ui.security;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * User account.
+ */
+@Getter
+@Setter
+public final class UserAccount {
+
+ private String username;
+
+ private String password;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java
new file mode 100644
index 0000000..b41d7d3
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/security/UserAuthenticationService.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.security;
+
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+import lombok.Setter;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * User authentication service.
+ */
+@Component
+@ConfigurationProperties(prefix = "auth")
+@Setter
+public final class UserAuthenticationService {
+
+ private String rootUsername;
+
+ private String rootPassword;
+
+ private String guestUsername;
+
+ private String guestPassword;
+
+ private final Base64 base64 = new Base64();
+
+ private Gson gson = new Gson();
+
+ /**
+ * Check user.
+ *
+ * @param userAccount user account
+ * @return check success or failure
+ */
+ public AuthenticationResult checkUser(final UserAccount userAccount) {
+ if (null == userAccount || Strings.isNullOrEmpty(userAccount.getUsername()) || Strings.isNullOrEmpty(userAccount.getPassword())) {
+ return new AuthenticationResult(null, null, false, false);
+ }
+ if (rootUsername.equals(userAccount.getUsername()) && rootPassword.equals(userAccount.getPassword())) {
+ return new AuthenticationResult(rootUsername, rootPassword, true, false);
+ }
+ if (guestUsername.equals(userAccount.getUsername()) && guestPassword.equals(userAccount.getPassword())) {
+ return new AuthenticationResult(guestUsername, guestPassword, true, true);
+ }
+ return new AuthenticationResult(null ,null, false, false);
+ }
+
+ /**
+ * Get user authentication token.
+ *
+ * @return authentication token
+ */
+ public String getToken() {
+ return base64.encodeToString(gson.toJson(this).getBytes());
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java
new file mode 100644
index 0000000..0135623
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceDataSourceConfigurationService.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfigurations;
+
+import java.util.Optional;
+
+/**
+ * Event trace data source configuration service.
+ */
+public interface EventTraceDataSourceConfigurationService {
+
+ /**
+ * Load all event trace data source configurations.
+ *
+ * @return all event trace data source configuration
+ */
+ EventTraceDataSourceConfigurations loadAll();
+
+ /**
+ * Load event trace data source configuration.
+ *
+ * @param name name of event trace data source configuration
+ * @return event trace data source configuration
+ */
+ EventTraceDataSourceConfiguration load(String name);
+
+ /**
+ * Find event trace data source configuration.
+ *
+ * @param name name of event trace data source configuration
+ * @param configs event trace data source configurations
+ * @return event trace data source configuration
+ */
+ EventTraceDataSourceConfiguration find(String name, EventTraceDataSourceConfigurations configs);
+
+ /**
+ * Load activated event trace data source configuration.
+ *
+ * @return activated event trace data source configuration
+ */
+ Optional<EventTraceDataSourceConfiguration> loadActivated();
+
+ /**
+ * Add event trace data source configuration.
+ *
+ * @param config event trace data source configuration
+ * @return success to add or not
+ */
+ boolean add(EventTraceDataSourceConfiguration config);
+
+ /**
+ * Delete event trace data source configuration.
+ *
+ * @param name name of event trace data source configuration
+ */
+ void delete(String name);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java
new file mode 100644
index 0000000..9a64552
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/EventTraceHistoryService.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.springframework.data.domain.Page;
+
+/**
+ * Event trace history service.
+ */
+public interface EventTraceHistoryService {
+
+ /**
+ * Find job execution events.
+ *
+ * @param findJobExecutionEventsRequest query params
+ * @return job execution events
+ */
+ Page<JobExecutionEvent> findJobExecutionEvents(FindJobExecutionEventsRequest findJobExecutionEventsRequest);
+
+ /**
+ * Find job status trace events.
+ *
+ * @param findJobStatusTraceEventsRequest query params
+ * @return job status trace events
+ */
+ Page<JobStatusTraceEvent> findJobStatusTraceEvents(FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.java
new file mode 100644
index 0000000..01008f5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/JobAPIService.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 org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobConfigurationAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ServerStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingStatisticsAPI;
+
+public interface JobAPIService {
+
+ /**
+ * Job configuration API.
+ *
+ * @return job configuration API
+ */
+ JobConfigurationAPI getJobConfigurationAPI();
+
+ /**
+ * Job operate API.
+ *
+ * @return Job operate API
+ */
+ JobOperateAPI getJobOperatorAPI();
+
+ /**
+ * Sharding operate API.
+ *
+ * @return sharding operate API
+ */
+ ShardingOperateAPI getShardingOperateAPI();
+
+ /**
+ * Job statistics API.
+ *
+ * @return job statistics API
+ */
+ JobStatisticsAPI getJobStatisticsAPI();
+
+ /**
+ * Servers statistics API.
+ *
+ * @return server statistics API
+ */
+ ServerStatisticsAPI getServerStatisticsAPI();
+
+ /**
+ * Sharding statistics API.
+ *
+ * @return sharding statistics API
+ */
+ ShardingStatisticsAPI getShardingStatisticsAPI();
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java
new file mode 100644
index 0000000..9aad0d8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/RegistryCenterConfigurationService.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfigurations;
+
+import java.util.Optional;
+
+/**
+ * Registry center configuration service.
+ */
+public interface RegistryCenterConfigurationService {
+
+ /**
+ * Load all registry center configurations.
+ *
+ * @return all registry center configurations
+ */
+ RegistryCenterConfigurations loadAll();
+
+ /**
+ * Load registry center configuration.
+ *
+ * @param name name of registry center configuration
+ * @return registry center configuration
+ */
+ RegistryCenterConfiguration load(String name);
+
+ /**
+ * Find registry center configuration.
+ *
+ * @param name name of registry center configuration
+ * @param configs registry center configurations
+ * @return registry center configuration
+ */
+ RegistryCenterConfiguration find(String name, RegistryCenterConfigurations configs);
+
+ /**
+ * Load activated registry center configuration.
+ *
+ * @return activated registry center configuration
+ */
+ Optional<RegistryCenterConfiguration> loadActivated();
+
+ /**
+ * Add registry center configuration.
+ *
+ * @param config registry center configuration
+ * @return success to add or not
+ */
+ boolean add(RegistryCenterConfiguration config);
+
+ /**
+ * Delete registry center configuration.
+ *
+ * @param name name of registry center configuration
+ */
+ void delete(String name);
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java
new file mode 100644
index 0000000..b3a80d9
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceDataSourceConfigurationServiceImpl.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.config.DynamicDataSourceConfig;
+import org.apache.shardingsphere.elasticjob.ui.domain.DataSourceFactory;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfigurations;
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.repository.impl.ConfigurationsXmlRepositoryImpl;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceDataSourceConfigurationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.sql.DataSource;
+import java.util.Optional;
+
+/**
+ * Event trace data source configuration service implementation.
+ */
+@Service
+public final class EventTraceDataSourceConfigurationServiceImpl implements EventTraceDataSourceConfigurationService {
+
+ private ConfigurationsXmlRepository configurationsXmlRepository = new ConfigurationsXmlRepositoryImpl();
+
+ @Autowired
+ private DynamicDataSourceConfig.DynamicDataSource dynamicDataSource;
+
+ @Override
+ public EventTraceDataSourceConfigurations loadAll() {
+ return loadGlobal().getEventTraceDataSourceConfigurations();
+ }
+
+ @Override
+ public EventTraceDataSourceConfiguration load(final String name) {
+ GlobalConfiguration configs = loadGlobal();
+ EventTraceDataSourceConfiguration result = find(name, configs.getEventTraceDataSourceConfigurations());
+ setActivated(configs, result);
+ // Activate the dataSource by data source name for spring boot
+ DynamicDataSourceConfig.DynamicDataSourceContextHolder.setDataSourceName(name);
+ return result;
+ }
+
+ @Override
+ public EventTraceDataSourceConfiguration find(final String name, final EventTraceDataSourceConfigurations configs) {
+ for (EventTraceDataSourceConfiguration each : configs.getEventTraceDataSourceConfiguration()) {
+ if (name.equals(each.getName())) {
+ return each;
+ }
+ }
+ return null;
+ }
+
+ private void setActivated(final GlobalConfiguration configs, final EventTraceDataSourceConfiguration toBeConnectedConfig) {
+ EventTraceDataSourceConfiguration activatedConfig = findActivatedDataSourceConfiguration(configs);
+ if (!toBeConnectedConfig.equals(activatedConfig)) {
+ if (null != activatedConfig) {
+ activatedConfig.setActivated(false);
+ }
+ toBeConnectedConfig.setActivated(true);
+ configurationsXmlRepository.save(configs);
+ }
+ }
+
+ @Override
+ public Optional<EventTraceDataSourceConfiguration> loadActivated() {
+ return Optional.ofNullable(findActivatedDataSourceConfiguration(loadGlobal()));
+ }
+
+ private EventTraceDataSourceConfiguration findActivatedDataSourceConfiguration(final GlobalConfiguration configs) {
+ for (EventTraceDataSourceConfiguration each : configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration()) {
+ if (each.isActivated()) {
+ return each;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean add(final EventTraceDataSourceConfiguration config) {
+ GlobalConfiguration configs = loadGlobal();
+ boolean result = configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration().add(config);
+ if (result) {
+ configurationsXmlRepository.save(configs);
+ }
+ DataSource dataSource = DataSourceFactory.createDataSource(config);
+ dynamicDataSource.addDataSource(config.getName(), dataSource);
+ return result;
+ }
+
+ @Override
+ public void delete(final String name) {
+ GlobalConfiguration configs = loadGlobal();
+ EventTraceDataSourceConfiguration toBeRemovedConfig = find(name, configs.getEventTraceDataSourceConfigurations());
+ if (null != toBeRemovedConfig) {
+ configs.getEventTraceDataSourceConfigurations().getEventTraceDataSourceConfiguration().remove(toBeRemovedConfig);
+ configurationsXmlRepository.save(configs);
+ }
+ }
+
+ private GlobalConfiguration loadGlobal() {
+ GlobalConfiguration result = configurationsXmlRepository.load();
+ if (null == result.getEventTraceDataSourceConfigurations()) {
+ result.setEventTraceDataSourceConfigurations(new EventTraceDataSourceConfigurations());
+ }
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java
new file mode 100644
index 0000000..d80e1a5
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/EventTraceHistoryServiceImpl.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dao.search.JobExecutionLogRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.search.JobStatusTraceLogRepository;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobExecutionLog;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobStatusTraceLog;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.BasePageRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.apache.shardingsphere.elasticjob.ui.util.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Component;
+
+import javax.persistence.criteria.Predicate;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Event trace history service implementation.
+ */
+@Slf4j
+@Component
+public final class EventTraceHistoryServiceImpl implements EventTraceHistoryService {
+
+ @Autowired
+ private JobExecutionLogRepository jobExecutionLogRepository;
+
+ @Autowired
+ private JobStatusTraceLogRepository jobStatusTraceLogRepository;
+
+ @Override
+ public Page<JobExecutionEvent> findJobExecutionEvents(final FindJobExecutionEventsRequest findJobExecutionEventsRequest) {
+ Example<JobExecutionLog> jobExecutionLogExample = getExample(findJobExecutionEventsRequest, JobExecutionLog.class);
+ Specification<JobExecutionLog> specification = getSpecWithExampleAndDate(jobExecutionLogExample, findJobExecutionEventsRequest.getStart(),
+ findJobExecutionEventsRequest.getEnd(), "startTime");
+
+ Page<JobExecutionLog> page = jobExecutionLogRepository.findAll(specification, getPageable(findJobExecutionEventsRequest, JobExecutionLog.class));
+ return new PageImpl<>(page.get().map(JobExecutionLog::toJobExecutionEvent).collect(Collectors.toList()), page.getPageable(), page.getTotalElements());
+ }
+
+ @Override
+ public Page<JobStatusTraceEvent> findJobStatusTraceEvents(final FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest) {
+ Example<JobStatusTraceLog> jobStatusTraceLogExample = getExample(findJobStatusTraceEventsRequest, JobStatusTraceLog.class);
+ Specification<JobStatusTraceLog> specification = getSpecWithExampleAndDate(jobStatusTraceLogExample, findJobStatusTraceEventsRequest.getStart(),
+ findJobStatusTraceEventsRequest.getEnd(), "creationTime");
+ Page<JobStatusTraceLog> page = jobStatusTraceLogRepository.findAll(specification, getPageable(findJobStatusTraceEventsRequest, JobStatusTraceLog.class));
+ return new PageImpl<>(page.get().map(JobStatusTraceLog::toJobStatusTraceEvent).collect(Collectors.toList()), page.getPageable(), page.getTotalElements());
+ }
+
+ private <T> Pageable getPageable(final BasePageRequest pageRequest, final Class<T> clazz) {
+ int page = 0;
+ int perPage = BasePageRequest.DEFAULT_PAGE_SIZE;
+ if (pageRequest.getPageNumber() > 0 && pageRequest.getPageSize() > 0) {
+ page = pageRequest.getPageNumber() - 1;
+ perPage = pageRequest.getPageSize();
+ }
+ return PageRequest.of(page, perPage, getSort(pageRequest, clazz));
+ }
+
+ private <T> Sort getSort(final BasePageRequest pageRequest, final Class<T> clazz) {
+ Sort sort = Sort.unsorted();
+ boolean sortFieldIsPresent = Arrays.stream(clazz.getDeclaredFields())
+ .map(Field::getName)
+ .anyMatch(e -> e.equals(pageRequest.getSortBy()));
+ if (!sortFieldIsPresent) {
+ return sort;
+ }
+ if (!Strings.isNullOrEmpty(pageRequest.getSortBy())) {
+ Sort.Direction order = Sort.Direction.ASC;
+ try {
+ order = Sort.Direction.valueOf(pageRequest.getOrderType());
+ } catch (IllegalArgumentException ignored) {
+ }
+ sort = Sort.by(order, pageRequest.getSortBy());
+ }
+ return sort;
+ }
+
+ private <T> Specification<T> getSpecWithExampleAndDate(final Example<T> example, final Date from, final Date to, final String field) {
+ return (Specification<T>) (root, query, builder) -> {
+ final List<Predicate> predicates = new ArrayList<>();
+ if (from != null) {
+ predicates.add(builder.greaterThan(root.get(field), from));
+ }
+ if (to != null) {
+ predicates.add(builder.lessThan(root.get(field), to));
+ }
+ predicates.add(QueryByExamplePredicateBuilder.getPredicate(root, builder, example));
+ return builder.and(predicates.toArray(new Predicate[0]));
+ };
+ }
+
+ private <T> Example<T> getExample(final Object source, final Class<T> clazz) {
+ T instance = BeanUtils.newInstance(clazz);
+ BeanUtils.copyProperties(source, instance);
+ return Example.of(instance);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.java
new file mode 100644
index 0000000..d135341
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/JobAPIServiceImpl.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 org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobAPIFactory;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobConfigurationAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.JobStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ServerStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingOperateAPI;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.api.ShardingStatisticsAPI;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionRegistryCenterConfiguration;
+import org.springframework.stereotype.Service;
+
+/**
+ * Job API service implementation.
+ */
+@Service
+public final class JobAPIServiceImpl implements JobAPIService {
+
+ @Override
+ public JobConfigurationAPI getJobConfigurationAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createJobConfigurationAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+
+ @Override
+ public JobOperateAPI getJobOperatorAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createJobOperateAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+
+ @Override
+ public ShardingOperateAPI getShardingOperateAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createShardingOperateAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+
+ @Override
+ public JobStatisticsAPI getJobStatisticsAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createJobStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+
+ @Override
+ public ServerStatisticsAPI getServerStatisticsAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createServerStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+
+ @Override
+ public ShardingStatisticsAPI getShardingStatisticsAPI() {
+ RegistryCenterConfiguration regCenterConfig = SessionRegistryCenterConfiguration.getRegistryCenterConfiguration();
+ return JobAPIFactory.createShardingStatisticsAPI(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java
new file mode 100644
index 0000000..ddbb47e
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/service/impl/RegistryCenterConfigurationServiceImpl.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.service.impl;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.GlobalConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfigurations;
+import org.apache.shardingsphere.elasticjob.ui.repository.ConfigurationsXmlRepository;
+import org.apache.shardingsphere.elasticjob.ui.repository.impl.ConfigurationsXmlRepositoryImpl;
+import org.apache.shardingsphere.elasticjob.ui.service.RegistryCenterConfigurationService;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+/**
+ * Registry center configuration service implementation.
+ */
+@Service
+public final class RegistryCenterConfigurationServiceImpl implements RegistryCenterConfigurationService {
+
+ private ConfigurationsXmlRepository configurationsXmlRepository = new ConfigurationsXmlRepositoryImpl();
+
+ @Override
+ public RegistryCenterConfigurations loadAll() {
+ return loadGlobal().getRegistryCenterConfigurations();
+ }
+
+ @Override
+ public RegistryCenterConfiguration load(final String name) {
+ GlobalConfiguration configs = loadGlobal();
+ RegistryCenterConfiguration result = find(name, configs.getRegistryCenterConfigurations());
+ setActivated(configs, result);
+ return result;
+ }
+
+ @Override
+ public RegistryCenterConfiguration find(final String name, final RegistryCenterConfigurations configs) {
+ for (RegistryCenterConfiguration each : configs.getRegistryCenterConfiguration()) {
+ if (name.equals(each.getName())) {
+ return each;
+ }
+ }
+ return null;
+ }
+
+ private void setActivated(final GlobalConfiguration configs, final RegistryCenterConfiguration toBeConnectedConfig) {
+ RegistryCenterConfiguration activatedConfig = findActivatedRegistryCenterConfiguration(configs);
+ if (!toBeConnectedConfig.equals(activatedConfig)) {
+ if (null != activatedConfig) {
+ activatedConfig.setActivated(false);
+ }
+ toBeConnectedConfig.setActivated(true);
+ configurationsXmlRepository.save(configs);
+ }
+ }
+
+ @Override
+ public Optional<RegistryCenterConfiguration> loadActivated() {
+ return Optional.ofNullable(findActivatedRegistryCenterConfiguration(loadGlobal()));
+ }
+
+ private RegistryCenterConfiguration findActivatedRegistryCenterConfiguration(final GlobalConfiguration configs) {
+ for (RegistryCenterConfiguration each : configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration()) {
+ if (each.isActivated()) {
+ return each;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean add(final RegistryCenterConfiguration config) {
+ GlobalConfiguration configs = loadGlobal();
+ boolean result = configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration().add(config);
+ if (result) {
+ configurationsXmlRepository.save(configs);
+ }
+ return result;
+ }
+
+ @Override
+ public void delete(final String name) {
+ GlobalConfiguration configs = loadGlobal();
+ RegistryCenterConfiguration toBeRemovedConfig = find(name, configs.getRegistryCenterConfigurations());
+ if (null != toBeRemovedConfig) {
+ configs.getRegistryCenterConfigurations().getRegistryCenterConfiguration().remove(toBeRemovedConfig);
+ configurationsXmlRepository.save(configs);
+ }
+ }
+
+ private GlobalConfiguration loadGlobal() {
+ GlobalConfiguration result = configurationsXmlRepository.load();
+ if (null == result.getRegistryCenterConfigurations()) {
+ result.setRegistryCenterConfigurations(new RegistryCenterConfigurations());
+ }
+ return result;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java
new file mode 100644
index 0000000..0566471
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/BeanUtils.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import org.springframework.cglib.beans.BeanMap;
+
+import java.util.Map;
+import java.util.Objects;
+
+public class BeanUtils extends org.springframework.beans.BeanUtils {
+
+ /**
+ * return a new instance by specified java type.
+ *
+ * @param clazz java type class
+ * @param <T> java type
+ * @return new instance
+ */
+ public static <T> T newInstance(final Class<T> clazz) {
+ return instantiateClass(clazz);
+ }
+
+ /**
+ * map to java object.
+ *
+ * @param map source map
+ * @param type class
+ * @param <T> target java type
+ * @return java object
+ */
+ public static <T> T toBean(final Map<String, Object> map, final Class<T> type) {
+ if (Objects.isNull(map)) {
+ return null;
+ }
+ T bean = newInstance(type);
+ BeanMap beanMap = BeanMap.create(bean);
+ beanMap.putAll(map);
+ return bean;
+ }
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.java
new file mode 100644
index 0000000..1c4aa10
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtils.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 org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.io.File;
+
+/**
+ * Home folder Utils.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class HomeFolderUtils {
+
+ private static final String USER_HOME = System.getProperty("user.home");
+
+ private static final String CONSOLE_ROOT_FOLDER = ".elasticjob-console";
+
+ /**
+ * Get file path in home folder.
+ *
+ * @param fileName file name
+ * @return file path in home folder
+ */
+ public static String getFilePathInHomeFolder(final String fileName) {
+ return String.format("%s%s", getHomeFolder(), fileName);
+ }
+
+ /**
+ * Create home folder if not existed.
+ */
+ public static void createHomeFolderIfNotExisted() {
+ File file = new File(getHomeFolder());
+ if (!file.exists()) {
+ file.mkdirs();
+ }
+ }
+
+ private static String getHomeFolder() {
+ return String.format("%s%s%s%s", USER_HOME, File.separator, CONSOLE_ROOT_FOLDER, File.separator);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java
new file mode 100644
index 0000000..1445b7d
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionEventTraceDataSourceConfiguration.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.config.DynamicDataSourceConfig;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+
+/**
+ * Event trace data source configuration in session.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class SessionEventTraceDataSourceConfiguration {
+
+ private static EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration;
+
+ /**
+ * Set event trace data source configuration.
+ *
+ * @param eventTraceDataSourceConfiguration event trace data source configuration
+ */
+ public static void setDataSourceConfiguration(final EventTraceDataSourceConfiguration eventTraceDataSourceConfiguration) {
+ DynamicDataSourceConfig.DynamicDataSourceContextHolder.setDataSourceName(eventTraceDataSourceConfiguration.getName());
+ SessionEventTraceDataSourceConfiguration.eventTraceDataSourceConfiguration = eventTraceDataSourceConfiguration;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java
new file mode 100644
index 0000000..74fe0c2
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/util/SessionRegistryCenterConfiguration.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+
+/**
+ * Registry center configuration configuration.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class SessionRegistryCenterConfiguration {
+
+ private static RegistryCenterConfiguration regCenterConfig;
+
+ /**
+ * Get registry center configuration.
+ *
+ * @return registry center configuration
+ */
+ public static RegistryCenterConfiguration getRegistryCenterConfiguration() {
+ return regCenterConfig;
+ }
+
+ /**
+ * Set registry center configuration.
+ *
+ * @param regCenterConfig registry center configuration
+ */
+ public static void setRegistryCenterConfiguration(final RegistryCenterConfiguration regCenterConfig) {
+ SessionRegistryCenterConfiguration.regCenterConfig = regCenterConfig;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
new file mode 100644
index 0000000..d4bd7c0
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceDataSourceController.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.domain.EventTraceDataSourceFactory;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceDataSourceConfigurationService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionEventTraceDataSourceConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Event trace data source RESTful API.
+ */
+@RestController
+@RequestMapping("/data-source")
+public final class EventTraceDataSourceController {
+
+ public static final String DATA_SOURCE_CONFIG_KEY = "data_source_config_key";
+
+ private EventTraceDataSourceConfigurationService eventTraceDataSourceConfigurationService;
+
+ @Autowired
+ public EventTraceDataSourceController(final EventTraceDataSourceConfigurationService eventTraceDataSourceConfigurationService) {
+ this.eventTraceDataSourceConfigurationService = eventTraceDataSourceConfigurationService;
+ }
+
+ /**
+ * Judge whether event trace data source is activated.
+ *
+ * @param request HTTP request
+ * @return event trace data source is activated or not
+ */
+ @GetMapping("/activated")
+ public boolean activated(@Context final HttpServletRequest request) {
+ return eventTraceDataSourceConfigurationService.loadActivated().isPresent();
+ }
+
+ /**
+ * Load event trace data source configuration.
+ *
+ * @param request HTTP request
+ * @return event trace data source configurations
+ */
+ @GetMapping(produces = MediaType.APPLICATION_JSON)
+ public Collection<EventTraceDataSourceConfiguration> load(@Context final HttpServletRequest request) {
+ eventTraceDataSourceConfigurationService.loadActivated().ifPresent(eventTraceDataSourceConfig -> setDataSourceNameToSession(eventTraceDataSourceConfig, request.getSession()));
+ return eventTraceDataSourceConfigurationService.loadAll().getEventTraceDataSourceConfiguration();
+ }
+
+ /**
+ * Add event trace data source configuration.
+ *
+ * @param config event trace data source configuration
+ * @return success to added or not
+ */
+ @PostMapping(produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+ public boolean add(@RequestBody final EventTraceDataSourceConfiguration config) {
+ return eventTraceDataSourceConfigurationService.add(config);
+ }
+
+ /**
+ * Delete event trace data source configuration.
+ *
+ * @param config event trace data source configuration
+ */
+ @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
+ public void delete(@RequestBody final EventTraceDataSourceConfiguration config) {
+ eventTraceDataSourceConfigurationService.delete(config.getName());
+ }
+
+ /**
+ * Test event trace data source connection.
+ *
+ * @param config event trace data source configuration
+ * @param request HTTP request
+ * @return success or not
+ */
+ @PostMapping(value = "/connectTest", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+ public boolean connectTest(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+ return setDataSourceNameToSession(config, request.getSession());
+ }
+
+ /**
+ * Connect event trace data source.
+ *
+ * @param config event trace data source
+ * @param request HTTP request
+ * @return success or not
+ */
+ @PostMapping(value = "/connect", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+ public boolean connect(@RequestBody final EventTraceDataSourceConfiguration config, @Context final HttpServletRequest request) {
+ boolean isConnected = setDataSourceNameToSession(eventTraceDataSourceConfigurationService.find(config.getName(), eventTraceDataSourceConfigurationService.loadAll()), request.getSession());
+ if (isConnected) {
+ eventTraceDataSourceConfigurationService.load(config.getName());
+ }
+ return isConnected;
+ }
+
+ private boolean setDataSourceNameToSession(final EventTraceDataSourceConfiguration dataSourceConfig, final HttpSession session) {
+ session.setAttribute(DATA_SOURCE_CONFIG_KEY, dataSourceConfig);
+ try {
+ EventTraceDataSourceFactory.createEventTraceDataSource(dataSourceConfig.getDriver(), dataSourceConfig.getUrl(), dataSourceConfig.getUsername(), dataSourceConfig.getPassword());
+ SessionEventTraceDataSourceConfiguration.setDataSourceConfiguration((EventTraceDataSourceConfiguration) session.getAttribute(DATA_SOURCE_CONFIG_KEY));
+ // CHECKSTYLE:OFF
+ } catch (final Exception ex) {
+ // CHECKSTYLE:ON
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.java
new file mode 100644
index 0000000..c8499e1
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/EventTraceHistoryController.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 org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.response.BasePageResponse;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Event trace history RESTful API.
+ */
+@RestController
+@RequestMapping("/event-trace")
+public final class EventTraceHistoryController {
+
+ @Autowired
+ private EventTraceHistoryService eventTraceHistoryService;
+
+ /**
+ * Find job execution events.
+ *
+ * @param requestParams query criteria
+ * @return job execution event trace result
+ */
+ @GetMapping(value = "/execution", produces = MediaType.APPLICATION_JSON)
+ public BasePageResponse<JobExecutionEvent> findJobExecutionEvents(final FindJobExecutionEventsRequest requestParams) {
+ Page<JobExecutionEvent> jobExecutionEvents = eventTraceHistoryService.findJobExecutionEvents(requestParams);
+ return BasePageResponse.of(jobExecutionEvents);
+ }
+
+ /**
+ * Find job status trace events.
+ *
+ * @param requestParams query criteria
+ * @return job status trace result
+ */
+ @GetMapping(value = "/status", produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+ public BasePageResponse<JobStatusTraceEvent> findJobStatusTraceEvents(final FindJobStatusTraceEventsRequest requestParams) {
+ Page<JobStatusTraceEvent> jobStatusTraceEvents = eventTraceHistoryService.findJobStatusTraceEvents(requestParams);
+ return BasePageResponse.of(jobStatusTraceEvents);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.java
new file mode 100644
index 0000000..65c876b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobConfigController.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 org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.internal.config.pojo.JobConfigurationPOJO;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Job configuration RESTful API.
+ */
+@RestController
+@RequestMapping("/jobs/config")
+public final class JobConfigController {
+
+ private JobAPIService jobAPIService;
+
+ @Autowired
+ public JobConfigController(final JobAPIService jobAPIService) {
+ this.jobAPIService = jobAPIService;
+ }
+
+ /**
+ * Get job configuration.
+ *
+ * @param jobName job name
+ * @return job configuration
+ */
+ @GetMapping(value = "/{jobName}", produces = MediaType.APPLICATION_JSON)
+ public JobConfigurationPOJO getJobConfig(@PathVariable("jobName") final String jobName) {
+ return jobAPIService.getJobConfigurationAPI().getJobConfiguration(jobName);
+ }
+
+ /**
+ * Update job configuration.
+ *
+ * @param jobConfiguration job configuration
+ */
+ @PutMapping(consumes = MediaType.APPLICATION_JSON)
+ public void updateJobConfig(@RequestBody final JobConfigurationPOJO jobConfiguration) {
+ jobAPIService.getJobConfigurationAPI().updateJobConfiguration(jobConfiguration);
+ }
+
+ /**
+ * Remove job configuration.
+ *
+ * @param jobName job name
+ */
+ @DeleteMapping("/{jobName}")
+ public void removeJob(@PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobConfigurationAPI().removeJobConfiguration(jobName);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java
new file mode 100644
index 0000000..f5ba118
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/JobOperationController.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.JobBriefInfo;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.ShardingInfo;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Job operation RESTful API.
+ */
+@RestController
+@RequestMapping("/jobs")
+public final class JobOperationController {
+
+ private JobAPIService jobAPIService;
+
+ @Autowired
+ public JobOperationController(final JobAPIService jobAPIService) {
+ this.jobAPIService = jobAPIService;
+ }
+
+ /**
+ * Get jobs total count.
+ *
+ * @return jobs total count
+ */
+ @GetMapping("/count")
+ public int getJobsTotalCount() {
+ return jobAPIService.getJobStatisticsAPI().getJobsTotalCount();
+ }
+
+ /**
+ * Get all jobs brief info.
+ *
+ * @return all jobs brief info
+ */
+ @GetMapping(produces = MediaType.APPLICATION_JSON)
+ public Collection<JobBriefInfo> getAllJobsBriefInfo() {
+ return jobAPIService.getJobStatisticsAPI().getAllJobsBriefInfo();
+ }
+
+ /**
+ * Trigger job.
+ *
+ * @param jobName job name
+ */
+ @PostMapping("/{jobName}/trigger")
+ public void triggerJob(@PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().trigger(jobName);
+ }
+
+ /**
+ * Disable job.
+ *
+ * @param jobName job name
+ */
+ @PostMapping(value = "/{jobName}/disable")
+ public void disableJob(@PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().disable(jobName, null);
+ }
+
+ /**
+ * Enable job.
+ *
+ * @param jobName job name
+ */
+ @PostMapping(value = "/{jobName}/enable")
+ public void enableJob(@PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().enable(jobName, null);
+ }
+
+ /**
+ * Shutdown job.
+ *
+ * @param jobName job name
+ */
+ @PostMapping(value = "/{jobName}/shutdown")
+ public void shutdownJob(@PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().shutdown(jobName, null);
+ }
+
+ /**
+ * Get sharding info.
+ *
+ * @param jobName job name
+ * @return sharding info
+ */
+ @GetMapping(value = "/{jobName}/sharding", produces = MediaType.APPLICATION_JSON)
+ public Collection<ShardingInfo> getShardingInfo(@PathVariable("jobName") final String jobName) {
+ return jobAPIService.getShardingStatisticsAPI().getShardingInfo(jobName);
+ }
+
+ /**
+ * Disable sharding.
+ *
+ * @param jobName job name
+ * @param item sharding item
+ */
+ @PostMapping(value = "/{jobName}/sharding/{item}/disable")
+ public void disableSharding(@PathVariable("jobName") final String jobName, @PathVariable("item") final String item) {
+ jobAPIService.getShardingOperateAPI().disable(jobName, item);
+ }
+
+ /**
+ * Enable sharding.
+ *
+ * @param jobName job name
+ * @param item sharding item
+ */
+ @PostMapping(value = "/{jobName}/sharding/{item}/enable")
+ public void enableSharding(@PathVariable("jobName") final String jobName, @PathVariable("item") final String item) {
+ jobAPIService.getShardingOperateAPI().enable(jobName, item);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
new file mode 100644
index 0000000..9225b91
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/RegistryCenterController.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.internal.reg.RegistryCenterFactory;
+import org.apache.shardingsphere.elasticjob.reg.exception.RegException;
+import org.apache.shardingsphere.elasticjob.ui.domain.RegistryCenterConfiguration;
+import org.apache.shardingsphere.elasticjob.ui.service.RegistryCenterConfigurationService;
+import org.apache.shardingsphere.elasticjob.ui.util.SessionRegistryCenterConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Registry center RESTful API.
+ */
+@RestController
+@RequestMapping("/registry-center")
+public final class RegistryCenterController {
+
+ public static final String REG_CENTER_CONFIG_KEY = "reg_center_config_key";
+
+ private RegistryCenterConfigurationService regCenterService;
+
+ @Autowired
+ public RegistryCenterController(final RegistryCenterConfigurationService regCenterService) {
+ this.regCenterService = regCenterService;
+ }
+
+ /**
+ * Judge whether registry center is activated.
+ *
+ * @return registry center is activated or not
+ */
+ @GetMapping("/activated")
+ public boolean activated() {
+ return regCenterService.loadActivated().isPresent();
+ }
+
+ /**
+ * Load configuration from registry center.
+ *
+ * @param request HTTP request
+ * @return registry center configurations
+ */
+ @GetMapping(produces = MediaType.APPLICATION_JSON)
+ public Collection<RegistryCenterConfiguration> load(final HttpServletRequest request) {
+ regCenterService.loadActivated().ifPresent(regCenterConfig -> setRegistryCenterNameToSession(regCenterConfig, request.getSession()));
+ return regCenterService.loadAll().getRegistryCenterConfiguration();
+ }
+
+ /**
+ * Add registry center.
+ *
+ * @param config registry center configuration
+ * @return success to add or not
+ */
+ @PostMapping(produces = MediaType.APPLICATION_JSON)
+ public boolean add(@RequestBody final RegistryCenterConfiguration config) {
+ return regCenterService.add(config);
+ }
+
+ /**
+ * Delete registry center.
+ *
+ * @param config registry center configuration
+ */
+ @DeleteMapping(consumes = MediaType.APPLICATION_JSON)
+ public void delete(@RequestBody final RegistryCenterConfiguration config) {
+ regCenterService.delete(config.getName());
+ }
+
+ /**
+ * Connect to registry center.
+ *
+ * @param config config of registry center
+ * @param request HTTP request
+ * @return connected or not
+ */
+ @PostMapping(value = "/connect", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
+ public boolean connect(@RequestBody final RegistryCenterConfiguration config, @Context final HttpServletRequest request) {
+ boolean isConnected = setRegistryCenterNameToSession(regCenterService.find(config.getName(), regCenterService.loadAll()), request.getSession());
+ if (isConnected) {
+ regCenterService.load(config.getName());
+ }
+ return isConnected;
+ }
+
+ private boolean setRegistryCenterNameToSession(final RegistryCenterConfiguration regCenterConfig, final HttpSession session) {
+ session.setAttribute(REG_CENTER_CONFIG_KEY, regCenterConfig);
+ try {
+ RegistryCenterFactory.createCoordinatorRegistryCenter(regCenterConfig.getZkAddressList(), regCenterConfig.getNamespace(), regCenterConfig.getDigest());
+ SessionRegistryCenterConfiguration.setRegistryCenterConfiguration((RegistryCenterConfiguration) session.getAttribute(REG_CENTER_CONFIG_KEY));
+ } catch (final RegException ex) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java
new file mode 100644
index 0000000..2a36f66
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/controller/ServerOperationController.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.controller;
+
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.JobBriefInfo;
+import org.apache.shardingsphere.elasticjob.lite.lifecycle.domain.ServerBriefInfo;
+import org.apache.shardingsphere.elasticjob.ui.service.JobAPIService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.core.MediaType;
+import java.util.Collection;
+
+/**
+ * Server operation RESTful API.
+ */
+@RestController
+@RequestMapping("/servers")
+public final class ServerOperationController {
+
+ private JobAPIService jobAPIService;
+
+ @Autowired
+ public ServerOperationController(final JobAPIService jobAPIService) {
+ this.jobAPIService = jobAPIService;
+ }
+
+ /**
+ * Get servers total count.
+ *
+ * @return servers total count
+ */
+ @GetMapping("/count")
+ public int getServersTotalCount() {
+ return jobAPIService.getServerStatisticsAPI().getServersTotalCount();
+ }
+
+ /**
+ * Get all servers brief info.
+ *
+ * @return all servers brief info
+ */
+ @GetMapping(produces = MediaType.APPLICATION_JSON)
+ public Collection<ServerBriefInfo> getAllServersBriefInfo() {
+ return jobAPIService.getServerStatisticsAPI().getAllServersBriefInfo();
+ }
+
+ /**
+ * Disable server.
+ *
+ * @param serverIp server IP address
+ */
+ @PostMapping("/{serverIp}/disable")
+ public void disableServer(@PathVariable("serverIp") final String serverIp) {
+ jobAPIService.getJobOperatorAPI().disable(null, serverIp);
+ }
+
+ /**
+ * Enable server.
+ *
+ * @param serverIp server IP address
+ */
+ @PostMapping("/{serverIp}/enable")
+ public void enableServer(@PathVariable("serverIp") final String serverIp) {
+ jobAPIService.getJobOperatorAPI().enable(null, serverIp);
+ }
+
+ /**
+ * Shutdown server.
+ *
+ * @param serverIp server IP address
+ */
+ @PostMapping("/{serverIp}/shutdown")
+ public void shutdownServer(@PathVariable("serverIp") final String serverIp) {
+ jobAPIService.getJobOperatorAPI().shutdown(null, serverIp);
+ }
+
+ /**
+ * Remove server.
+ *
+ * @param serverIp server IP address
+ */
+ @DeleteMapping("/{serverIp}")
+ public void removeServer(@PathVariable("serverIp") final String serverIp) {
+ jobAPIService.getJobOperatorAPI().remove(null, serverIp);
+ }
+
+ /**
+ * Get jobs.
+ *
+ * @param serverIp server IP address
+ * @return Job brief info
+ */
+ @GetMapping(value = "/{serverIp}/jobs", produces = MediaType.APPLICATION_JSON)
+ public Collection<JobBriefInfo> getJobs(@PathVariable("serverIp") final String serverIp) {
+ return jobAPIService.getJobStatisticsAPI().getJobsBriefInfo(serverIp);
+ }
+
+ /**
+ * Disable server job.
+ *
+ * @param serverIp server IP address
+ * @param jobName job name
+ */
+ @PostMapping(value = "/{serverIp}/jobs/{jobName}/disable")
+ public void disableServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().disable(jobName, serverIp);
+ }
+
+ /**
+ * Enable server job.
+ *
+ * @param serverIp server IP address
+ * @param jobName job name
+ */
+ @PostMapping("/{serverIp}/jobs/{jobName}/enable")
+ public void enableServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().enable(jobName, serverIp);
+ }
+
+ /**
+ * Shutdown server job.
+ *
+ * @param serverIp server IP address
+ * @param jobName job name
+ */
+ @PostMapping("/{serverIp}/jobs/{jobName}/shutdown")
+ public void shutdownServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().shutdown(jobName, serverIp);
+ }
+
+ /**
+ * Remove server job.
+ *
+ * @param serverIp server IP address
+ * @param jobName job name
+ */
+ @DeleteMapping("/{serverIp}/jobs/{jobName}")
+ public void removeServerJob(@PathVariable("serverIp") final String serverIp, @PathVariable("jobName") final String jobName) {
+ jobAPIService.getJobOperatorAPI().remove(jobName, serverIp);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java
new file mode 100644
index 0000000..95c0869
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/filter/CORSFilter.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.filter;
+
+import org.springframework.http.HttpStatus;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * CORS filter.
+ */
+public final class CORSFilter implements Filter {
+
+ @Override
+ public void init(final FilterConfig filterConfig) {
+ }
+
+ @Override
+ public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
+ response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
+ response.setHeader("Access-Control-Max-Age", "3600");
+ response.setHeader("Access-Control-Allow-Credentials", "true");
+ response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
+ if ("OPTIONS".equals(request.getMethod())) {
+ response.setStatus(HttpStatus.OK.value());
+ } else {
+ filterChain.doFilter(request, response);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java
new file mode 100644
index 0000000..b01b109
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResult.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * Restful Response result.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public final class ResponseResult<T> implements Serializable {
+
+ private static final long serialVersionUID = 8144393142115317354L;
+
+ private boolean success = true;
+
+ private int errorCode;
+
+ private String errorMsg;
+
+ private T model;
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java
new file mode 100644
index 0000000..0422956
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/main/java/org/apache/shardingsphere/elasticjob/ui/web/response/ResponseResultUtil.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.web.response;
+
+import com.google.gson.Gson;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.elasticjob.ui.exception.JobConsoleException;
+
+/**
+ * Response result utility.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class ResponseResultUtil {
+
+ /**
+ * Build the successful response without data model.
+ *
+ * @return response result
+ */
+ public static ResponseResult success() {
+ return build(null);
+ }
+
+ /**
+ * Build the successful response with data model.
+ *
+ * @param model data model
+ * @param <T> data model type
+ * @return response result
+ */
+ public static <T> ResponseResult<T> build(final T model) {
+ ResponseResult<T> result = new ResponseResult<>();
+ result.setSuccess(true);
+ result.setModel(model);
+ return result;
+ }
+
+ /**
+ * Build the response from json.
+ *
+ * @param responseResultJson response result json string
+ * @return response result
+ */
+ public static ResponseResult buildFromJson(final String responseResultJson) {
+ return new Gson().fromJson(responseResultJson, ResponseResult.class);
+ }
+
+ /**
+ * Build the error response of illegal argument exception.
+ *
+ * @param errorMsg error message
+ * @return response result
+ */
+ public static ResponseResult handleIllegalArgumentException(final String errorMsg) {
+ ResponseResult result = new ResponseResult<>();
+ result.setSuccess(false);
+ result.setErrorCode(JobConsoleException.INVALID_PARAM);
+ result.setErrorMsg(errorMsg);
+ return result;
+ }
+
+ /**
+ * Build the error response of unauthorized exception.
+ *
+ * @param errorMsg error message
+ * @return response result
+ */
+ public static ResponseResult handleUnauthorizedException(final String errorMsg) {
+ ResponseResult result = new ResponseResult<>();
+ result.setSuccess(false);
+ result.setErrorCode(JobConsoleException.NO_RIGHT);
+ result.setErrorMsg(errorMsg);
+ return result;
+ }
+
+ /**
+ * Build the error response of ShardingSphere UI exception.
+ *
+ * @param exception ShardingSphere UI exception
+ * @return response result
+ */
+ public static ResponseResult handleShardingSphereUIException(final JobConsoleException exception) {
+ ResponseResult result = new ResponseResult<>();
+ result.setSuccess(false);
+ result.setErrorCode(exception.getErrorCode());
+ result.setErrorMsg(exception.getMessage());
+ return result;
+ }
+
+ /**
+ * Build the error response of uncaught exception.
+ *
+ * @param errorMsg error message
+ * @return response result
+ */
+ public static ResponseResult handleUncaughtException(final String errorMsg) {
+ ResponseResult result = new ResponseResult<>();
+ result.setSuccess(false);
+ result.setErrorCode(JobConsoleException.SERVER_ERROR);
+ result.setErrorMsg(errorMsg);
+ return result;
+ }
+
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
index 51e047a..f4f0513 100644
--- a/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
+++ b/shardingsphere-elasticjob-ui-backend/src/main/resources/application.properties
@@ -15,7 +15,16 @@
# limitations under the License.
#
-server.port=8088
+server.port=8899
-user.admin.username=admin
-user.admin.password=admin
+auth.root_username=root
+auth.root_password=root
+auth.guest_username=guest
+auth.guest_password=guest
+
+spring.datasource.default.driver-class-name=org.h2.Driver
+spring.datasource.default.url=jdbc:h2:mem:
+spring.datasource.default.username=sa
+spring.datasource.default.password=
+spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
+spring.jpa.show-sql=false
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java
new file mode 100644
index 0000000..558be6b
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTest.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.domain.Page;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Date;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+@Import(RDBJobEventSearchTestConfiguration.class)
+public final class RDBJobEventSearchTest {
+
+ @Autowired
+ private EventTraceHistoryService eventTraceHistoryService;
+
+ @Test
+ public void assertFindJobExecutionEventsWithPageSizeAndNumber() {
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest());
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(50, 1));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(50));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(100, 5));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(100));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(100, 6));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(0));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithErrorPageSizeAndNumber() {
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(-1, -1, null, null, null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithSort() {
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "ASC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "DESC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_99"));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithErrorSort() {
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "jobName", "ERROR_SORT", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, "notExistField", "ASC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithTime() {
+ Date now = new Date();
+ Date tenMinutesBefore = new Date(now.getTime() - 10 * 60 * 1000);
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, tenMinutesBefore, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, now, null));
+ assertThat(result.getTotalElements(), is(0L));
+ assertThat(result.getContent().size(), is(0));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, null, tenMinutesBefore));
+ assertThat(result.getTotalElements(), is(0L));
+ assertThat(result.getContent().size(), is(0));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, null, now));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1, null, null, tenMinutesBefore, now));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithFields() {
+ FindJobExecutionEventsRequest findJobExecutionEventsRequest = new FindJobExecutionEventsRequest(10, 1, null, null, null, null);
+ findJobExecutionEventsRequest.setIsSuccess(true);
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(findJobExecutionEventsRequest);
+ assertThat(result.getTotalElements(), is(250L));
+ assertThat(result.getContent().size(), is(10));
+ findJobExecutionEventsRequest.setIsSuccess(null);
+ findJobExecutionEventsRequest.setJobName("test_job_1");
+ result = eventTraceHistoryService.findJobExecutionEvents(findJobExecutionEventsRequest);
+ assertThat(result.getTotalElements(), is(1L));
+ assertThat(result.getContent().size(), is(1));
+ }
+
+ @Test
+ public void assertFindJobExecutionEventsWithErrorFields() {
+ Page<JobExecutionEvent> result = eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithPageSizeAndNumber() {
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(50, 1, null, null, null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(50));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(100, 5, null, null, null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(100));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(100, 6, null, null, null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(0));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithErrorPageSizeAndNumber() {
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(-1, -1));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithSort() {
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "ASC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "DESC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_99"));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithErrorSort() {
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "jobName", "ERROR_SORT", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ assertThat(result.getContent().get(0).getJobName(), is("test_job_1"));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, "notExistField", "ASC", null, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithTime() {
+ Date now = new Date();
+ Date tenMinutesBefore = new Date(now.getTime() - 10 * 60 * 1000);
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, tenMinutesBefore, null));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, now, null));
+ assertThat(result.getTotalElements(), is(0L));
+ assertThat(result.getContent().size(), is(0));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, tenMinutesBefore));
+ assertThat(result.getTotalElements(), is(0L));
+ assertThat(result.getContent().size(), is(0));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, null, now));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ result = eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1, null, null, tenMinutesBefore, now));
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithFields() {
+ FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest = new FindJobStatusTraceEventsRequest(10, 1);
+ findJobStatusTraceEventsRequest.setJobName("test_job_1");
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(findJobStatusTraceEventsRequest);
+ assertThat(result.getTotalElements(), is(1L));
+ assertThat(result.getContent().size(), is(1));
+ }
+
+ @Test
+ public void assertFindJobStatusTraceEventsWithErrorFields() {
+ FindJobStatusTraceEventsRequest findJobStatusTraceEventsRequest = new FindJobStatusTraceEventsRequest(10, 1);
+ Page<JobStatusTraceEvent> result = eventTraceHistoryService.findJobStatusTraceEvents(findJobStatusTraceEventsRequest);
+ assertThat(result.getTotalElements(), is(500L));
+ assertThat(result.getContent().size(), is(10));
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.java
new file mode 100644
index 0000000..16b5f08
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/search/RDBJobEventSearchTestConfiguration.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 org.apache.shardingsphere.elasticjob.ui.dao.search;
+
+import org.apache.shardingsphere.elasticjob.tracing.event.JobExecutionEvent;
+import org.apache.shardingsphere.elasticjob.tracing.event.JobStatusTraceEvent;
+import org.apache.shardingsphere.elasticjob.tracing.rdb.storage.RDBJobEventStorage;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobExecutionEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.dto.request.FindJobStatusTraceEventsRequest;
+import org.apache.shardingsphere.elasticjob.ui.service.EventTraceHistoryService;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.TestConfiguration;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+
+@TestConfiguration
+public class RDBJobEventSearchTestConfiguration implements InitializingBean {
+
+ @Autowired
+ private EventTraceHistoryService eventTraceHistoryService;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ initStorage();
+ }
+
+ private void initStorage() throws SQLException {
+ eventTraceHistoryService.findJobExecutionEvents(new FindJobExecutionEventsRequest(10, 1));
+ eventTraceHistoryService.findJobStatusTraceEvents(new FindJobStatusTraceEventsRequest(10, 1));
+ RDBJobEventStorage storage = new RDBJobEventStorage(dataSource);
+ for (int i = 1; i <= 500L; i++) {
+ JobExecutionEvent startEvent = new JobExecutionEvent("localhost", "127.0.0.1", "fake_task_id", "test_job_" + i, JobExecutionEvent.ExecutionSource.NORMAL_TRIGGER, 0);
+ storage.addJobExecutionEvent(startEvent);
+ if (i % 2 == 0) {
+ JobExecutionEvent successEvent = startEvent.executionSuccess();
+ storage.addJobExecutionEvent(successEvent);
+ }
+ storage.addJobStatusTraceEvent(new JobStatusTraceEvent(
+ "test_job_" + i,
+ "fake_failed_failover_task_id",
+ "fake_slave_id",
+ JobStatusTraceEvent.Source.LITE_EXECUTOR,
+ "FAILOVER",
+ "0",
+ JobStatusTraceEvent.State.TASK_FAILED,
+ "message is empty."
+ ));
+ }
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.java
new file mode 100644
index 0000000..f5f0419
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/dao/statistics/rdb/RDBStatisticRepositoryTest.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 org.apache.shardingsphere.elasticjob.ui.dao.statistics.rdb;
+
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.JobRegisterStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.JobRunningStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.StatisticInterval;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.TaskResultStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.dao.statistics.TaskRunningStatisticsRepository;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRegisterStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.JobRunningStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskResultStatistics;
+import org.apache.shardingsphere.elasticjob.ui.domain.TaskRunningStatistics;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.util.Date;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+@SpringBootTest
+@RunWith(SpringJUnit4ClassRunner.class)
+public class RDBStatisticRepositoryTest {
+
+ @Autowired
+ private TaskResultStatisticsRepository taskResultStatisticsRepository;
+
+ @Autowired
+ private TaskRunningStatisticsRepository taskRunningStatisticsRepository;
+
+ @Autowired
+ private JobRegisterStatisticsRepository jobRegisterStatisticsRepository;
+
+ @Autowired
+ private JobRunningStatisticsRepository jobRunningStatisticsRepository;
+
+ @Test
+ public void assertAddTaskResultStatistics() {
+ for (StatisticInterval each : StatisticInterval.values()) {
+ TaskResultStatistics taskResultStatistics = new TaskResultStatistics(100L, 0L, each.name(), new Date());
+ assertTrue(taskResultStatistics.equals(taskResultStatisticsRepository.save(taskResultStatistics)));
+ }
+ }
+
+ @Test
+ public void assertAddTaskRunningStatistics() {
+ TaskRunningStatistics taskRunningStatistics = new TaskRunningStatistics(100, new Date());
+ assertTrue(taskRunningStatistics.equals(taskRunningStatisticsRepository.save(taskRunningStatistics)));
+ }
+
+ @Test
+ public void assertAddJobRunningStatistics() {
+ JobRunningStatistics jobRunningStatistics = new JobRunningStatistics(100, new Date());
+ assertTrue(jobRunningStatistics.equals(jobRunningStatisticsRepository.save(jobRunningStatistics)));
+ }
+
+ @Test
+ public void assertAddJobRegisterStatistics() {
+ JobRegisterStatistics jobRegisterStatistics = new JobRegisterStatistics(100, new Date());
+ assertTrue(jobRegisterStatistics.equals(jobRegisterStatisticsRepository.save(jobRegisterStatistics)));
+ }
+
+ @Test
+ public void assertFindTaskResultStatisticsWhenTableIsEmpty() {
+ Date now = new Date();
+ assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.MINUTE.name()).size(), is(0));
+ assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.HOUR.name()).size(), is(0));
+ assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, StatisticInterval.DAY.name()).size(), is(0));
+ }
+
+ @Test
+ public void assertFindTaskResultStatisticsWithDifferentFromDate() {
+ Date now = new Date();
+ Date yesterday = getYesterday();
+ for (StatisticInterval each : StatisticInterval.values()) {
+ taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 0L, each.name(), yesterday));
+ taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 0L, each.name(), now));
+ assertThat(taskResultStatisticsRepository.findTaskResultStatistics(yesterday, each.name()).size(), is(2));
+ assertThat(taskResultStatisticsRepository.findTaskResultStatistics(now, each.name()).size(), is(1));
+ }
+ }
+
+ @Test
+ public void assertGetSummedTaskResultStatisticsWhenTableIsEmpty() {
+ for (StatisticInterval each : StatisticInterval.values()) {
+ TaskResultStatistics po = taskResultStatisticsRepository.getSummedTaskResultStatistics(new Date(), each.name());
+ assertThat(po.getSuccessCount(), nullValue());
+ assertThat(po.getFailedCount(), nullValue());
+ }
+ }
+
+ @Test
+ public void assertGetSummedTaskResultStatistics() {
+ for (StatisticInterval each : StatisticInterval.values()) {
+ Date date = new Date();
+ taskResultStatisticsRepository.save(new TaskResultStatistics(100L, 2L, each.name(), date));
+ taskResultStatisticsRepository.save(new TaskResultStatistics(200L, 5L, each.name(), date));
+ TaskResultStatistics po = taskResultStatisticsRepository.getSummedTaskResultStatistics(date, each.name());
+ assertThat(po.getSuccessCount(), is(300L));
+ assertThat(po.getFailedCount(), is(7L));
+ }
+ }
+
+ @Test
+ public void assertFindTaskRunningStatisticsWhenTableIsEmpty() {
+ assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(new Date()).size(), is(0));
+ }
+
+ @Test
+ public void assertFindTaskRunningStatisticsWithDifferentFromDate() {
+ Date now = new Date();
+ Date yesterday = getYesterday();
+ taskRunningStatisticsRepository.deleteAll();
+ taskRunningStatisticsRepository.save(new TaskRunningStatistics(100, yesterday));
+ taskRunningStatisticsRepository.save(new TaskRunningStatistics(100, now));
+ assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(yesterday).size(), is(2));
+ assertThat(taskRunningStatisticsRepository.findTaskRunningStatistics(now).size(), is(1));
+ }
+
+ @Test
+ public void assertFindJobRunningStatisticsWhenTableIsEmpty() {
+ assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(new Date()).size(), is(0));
+ }
+
+ @Test
+ public void assertFindJobRunningStatisticsWithDifferentFromDate() {
+ Date now = new Date();
+ Date yesterday = getYesterday();
+ jobRunningStatisticsRepository.deleteAll();
+ jobRunningStatisticsRepository.save(new JobRunningStatistics(100, yesterday));
+ jobRunningStatisticsRepository.save(new JobRunningStatistics(100, now));
+ assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(yesterday).size(), is(2));
+ assertThat(jobRunningStatisticsRepository.findJobRunningStatistics(now).size(), is(1));
+ }
+
+ @Test
+ public void assertFindJobRegisterStatisticsWhenTableIsEmpty() {
+ assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(new Date()).size(), is(0));
+ }
+
+ @Test
+ public void assertFindJobRegisterStatisticsWithDifferentFromDate() {
+ Date now = new Date();
+ Date yesterday = getYesterday();
+ jobRegisterStatisticsRepository.save(new JobRegisterStatistics(100, yesterday));
+ jobRegisterStatisticsRepository.save(new JobRegisterStatistics(100, now));
+ assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(yesterday).size(), is(2));
+ assertThat(jobRegisterStatisticsRepository.findJobRegisterStatistics(now).size(), is(1));
+ }
+
+ private Date getYesterday() {
+ return new Date(new Date().getTime() - 24 * 60 * 60 * 1000);
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.java b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.java
new file mode 100644
index 0000000..590c9f8
--- /dev/null
+++ b/shardingsphere-elasticjob-ui-backend/src/test/java/org/apache/shardingsphere/elasticjob/ui/util/HomeFolderUtilsTest.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 org.apache.shardingsphere.elasticjob.ui.util;
+
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+public final class HomeFolderUtilsTest {
+
+ private static final String HOME_FOLDER = System.getProperty("user.home") + File.separator + ".elasticjob-console" + File.separator;
+
+ @Test
+ public void assertGetFilePathInHomeFolder() {
+ assertThat(HomeFolderUtils.getFilePathInHomeFolder("test_file"), is(HOME_FOLDER + "test_file"));
+ }
+}
diff --git a/shardingsphere-elasticjob-ui-frontend/config/index.js b/shardingsphere-elasticjob-ui-frontend/config/index.js
index fdce0d8..38637c9 100644
--- a/shardingsphere-elasticjob-ui-frontend/config/index.js
+++ b/shardingsphere-elasticjob-ui-frontend/config/index.js
@@ -28,7 +28,7 @@ module.exports = {
assetsPublicPath: '/',
proxyTable: {
'/api': {
- target: 'http://localhost:8089',
+ target: 'http://localhost:8899',
changeOrigin: true,
pathRewrite: {
'^/api': '/api'
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
index cdd3b6e..ad569ac 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/en-US.js
@@ -20,38 +20,47 @@ export default {
home: 'Home',
menuData: [
{
- title: 'Config Center',
+ title: 'Global settings',
child: [
{
- title: 'Config Server',
- href: '/config-center'
+ title: 'Registry center',
+ href: '/registry-center'
},
{
- title: 'Rule Config',
- href: '/rule-config'
+ title: 'Event trace data source',
+ href: '/data-source'
}
]
},
{
- title: 'Registry Center',
+ title: 'Job operation',
child: [
{
- title: 'Registry Server',
- href: '/registry-center'
+ title: 'Job dimension',
+ href: '/operation-jobs'
},
{
- title: 'Runtime Status',
- href: '/runtime-status'
+ title: 'Server dimension',
+ href: '/operation-servers'
}
]
},
{
- title: 'Data scaling',
- href: '/data-scaling'
+ title: 'Job history',
+ child: [
+ {
+ title: 'Job trace',
+ href: '/history-trace'
+ },
+ {
+ title: 'History status',
+ href: '/history-status'
+ }
+ ]
},
{
- title: 'Cluster state',
- href: '/cluster-state'
+ title: 'Help',
+ href: '/job-help'
}
],
connected: 'Connected',
diff --git a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
index 7d16891..d860c3d 100644
--- a/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
+++ b/shardingsphere-elasticjob-ui-frontend/src/lang/zh-CN.js
@@ -20,38 +20,47 @@ export default {
home: '主页',
menuData: [
{
- title: '配置中心',
+ title: '全局配置',
child: [
{
- title: '服务列表',
- href: '/config-center'
+ title: '注册中心配置',
+ href: '/registry-center'
},
{
- title: '配置管理',
- href: '/rule-config'
+ title: '事件追踪数据源配置',
+ href: '/data-source'
}
]
},
{
- title: '注册中心',
+ title: '作业操作',
child: [
{
- title: '服务列表',
- href: '/registry-center'
+ title: '作业维度',
+ href: '/operation-jobs'
},
{
- title: '运行状态',
- href: '/runtime-status'
+ title: '服务器维度',
+ href: '/operation-servers'
}
]
},
{
- title: '数据扩容',
- href: '/data-scaling'
+ title: '作业历史',
+ child: [
+ {
+ title: '历史轨迹',
+ href: '/history-trace'
+ },
+ {
+ title: '历史状态',
+ href: '/history-status'
+ }
+ ]
},
{
- title: '节点状态',
- href: '/cluster-state'
+ title: '帮助',
+ href: '/job-help'
}
],
connect: '已连接',