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

liuxun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 293d9ce  SUBMARINE-500. Add metric param instance to the 
submarine-server rest
293d9ce is described below

commit 293d9ce78ce79314ddf41dfe50d9cc0d6d2a7078
Author: JohnTing <[email protected]>
AuthorDate: Fri Jun 26 14:01:56 2020 +0800

    SUBMARINE-500. Add metric param instance to the submarine-server rest
    
    ### What is this PR for?
    Add  metric, param instance from submarine/store/database/models.py  to the 
submarine-server rest api
    
    A few sentences describing the overall goals of the pull request's commits.
    First time? Check out the contributing guide - 
https://submarine.apache.org/contribution/contributions.html
    
    ### What type of PR is it?
    Feature
    
    ### Todos
    * [x] - metric rest api
    * [x] - param rest api
    * [x] - database
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-500
    
    ### How should this be tested?
    https://travis-ci.org/github/JohnTing/submarine/builds/698241108
    
    ### Screenshots (if appropriate)
    
![image](https://user-images.githubusercontent.com/19265751/85010278-535a7480-b192-11ea-9061-80afcc63febb.png)
    
![image](https://user-images.githubusercontent.com/19265751/85010343-708f4300-b192-11ea-9fe7-a6366760a65f.png)
    
![image](https://user-images.githubusercontent.com/19265751/85010398-83a21300-b192-11ea-9390-fa5bde68595f.png)
    
![image](https://user-images.githubusercontent.com/19265751/85010888-5f930180-b193-11ea-9ff5-99284cf42723.png)
    
![image](https://user-images.githubusercontent.com/19265751/85010930-6caff080-b193-11ea-9862-51195a66208c.png)
    
![image](https://user-images.githubusercontent.com/19265751/85010944-733e6800-b193-11ea-8852-a0642c781bdf.png)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? Yes/No
    
    Author: JohnTing <[email protected]>
    
    Closes #311 from JohnTing/SUBMARINE-500 and squashes the following commits:
    
    f8587df [JohnTing] Merge branch 'master' into SUBMARINE-500
    1371412 [JohnTing] Handling conflicts
    b27135d [JohnTing] Selective del value
    63c5959 [JohnTing] change
    b647d03 [JohnTing] change
    d2180cc [JohnTing] Try to fix the test
    2fd49bf [JohnTing] change
    4840f9f [JohnTing] change
    64818f8 [JohnTing] change, add DB Records
    c91fa13 [JohnTing] Merge branch 'SUBMARINE-500' of 
https://github.com/JohnTing/submarine into SUBMARINE-500
    42a71fd [JohnTing] change
    022db40 [JohnTing] Update docs/database/submarine.sql
    e85532b [JohnTing] Update docs/database/submarine.sql
    f10bdac [JohnTing] Merge branch 'SUBMARINE-500' of 
https://github.com/JohnTing/submarine into SUBMARINE-500
    5fee4e9 [JohnTing] change metric_key & param_key to key
    9fe7044 [JohnTing] change metric_key & param_key to key
    53cd9aa [JohnTing] change
    7758f49 [JohnTing] delete extra blank line.
    5a93793 [JohnTing] Make changes based on liuxunorg's review
    c52e28a [JohnTing] fix database
    934f8f6 [JohnTing] change database
    8f4da68 [JohnTing] change list
    32ee98d [JohnTing] test8
    f2fa7f8 [JohnTing] test7 del createby and updateby
    bb51b89 [JohnTing] test6
    3c81e7c [JohnTing] selectByPrimaryKeySelective
    7253a30 [JohnTing] test3
    495a20a [JohnTing] clean
    92743ca [JohnTing] sql
    b914791 [JohnTing] clean
    d6f75d8 [JohnTing] test2
    7cec6a5 [JohnTing] test1
    11a4a7c [JohnTing] sql
    55a012d [JohnTing] fix
    f8e978e [JohnTing] wip
    3865351 [JohnTing] wip
    b8ebcf0 [JohnTing] wip
    2199fb5 [JohnTing] test
    5b25f8c [JohnTing] wip
    1149e03 [JohnTing] wip
    c6117ce [JohnTing] wip
    8c15fd6 [JohnTing] wip
    5e408c3 [JohnTing] wip
    53802d3 [JohnTing] WIP
    4a6825b [JohnTing] WIP
---
 docs/database/submarine-data.sql                   |  18 +++
 docs/database/submarine.sql                        |  29 ++++
 .../server/workbench/database/entity/Metric.java   | 100 ++++++++++++
 .../server/workbench/database/entity/Param.java    |  68 +++++++++
 .../workbench/database/mappers/MetricMapper.java   |  39 +++++
 .../workbench/database/mappers/ParamMapper.java    |  39 +++++
 .../workbench/database/service/MetricService.java  | 125 +++++++++++++++
 .../workbench/database/service/ParamService.java   | 119 +++++++++++++++
 .../server/workbench/rest/MetricRestApi.java       | 169 +++++++++++++++++++++
 .../server/workbench/rest/ParamRestApi.java        | 165 ++++++++++++++++++++
 .../src/main/resources/mybatis-config.xml          |   2 +
 .../submarine/database/mappers/MetricMapper.xml    | 112 ++++++++++++++
 .../submarine/database/mappers/ParamMapper.xml     |  93 ++++++++++++
 .../database/service/MetricServiceTest.java        | 125 +++++++++++++++
 .../database/service/ParamServiceTest.java         | 110 ++++++++++++++
 15 files changed, 1313 insertions(+)

diff --git a/docs/database/submarine-data.sql b/docs/database/submarine-data.sql
index 86bb5c1..2c230ab 100644
--- a/docs/database/submarine-data.sql
+++ b/docs/database/submarine-data.sql
@@ -60,3 +60,21 @@ INSERT INTO `sys_user` VALUES 
('e9ca23d68d884d4ebb19d07889727dae', 'admin', 'adm
 -- Records of team
 -- ----------------------------
 INSERT INTO `team` VALUES ('e9ca23d68d884d4ebb19d07889721234', 'admin', 
'Submarine', 'admin', '2020-05-06 14:00:05', 'Jack', '2020-05-06 14:00:14');
+
+-- ----------------------------
+-- Records of metrics
+-- ----------------------------
+INSERT INTO `metrics` (`id`, `key`, `value`, `worker_index`, `timestamp`, 
`step`, `is_nan`, `job_name`) VALUES
+(13, 'score', 0.666667, 'worker-1', 1569139525097, 0, 0, 'application_1234'),
+(14, 'score', 0.666667, 'worker-1', 1569149139731, 0, 0, 'application_1234'),
+(15, 'score', 0.666667, 'worker-1', 1569169376482, 0, 0, 'application_1234'),
+(16, 'score', 0.666667, 'worker-1', 1569236290721, 0, 0, 'application_1234'),
+(17, 'score', 0.666667, 'worker-1', 1569236466722, 0, 0, 'application_1234');
+
+-- ----------------------------
+-- Records of params
+-- ----------------------------
+INSERT INTO `params` (`id`, `key`, `value`, `worker_index`, `job_name`) VALUES
+(14, 'max_iter', '100', 'worker-1', 'application_123651651'),
+(15, 'n_jobs', '5', 'worker-1', 'application_123456898'),
+(16, 'alpha', '20', 'worker-1', 'application_123456789');
diff --git a/docs/database/submarine.sql b/docs/database/submarine.sql
index 6fd3e9e..729aed5 100644
--- a/docs/database/submarine.sql
+++ b/docs/database/submarine.sql
@@ -219,3 +219,32 @@ CREATE TABLE `job` (
   `update_time` datetime default NULL COMMENT 'last update time',
   PRIMARY KEY  (`id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+  
+-- ----------------------------
+-- Table structure for metric
+-- ----------------------------
+DROP TABLE IF EXISTS `metrics`;
+CREATE TABLE `metrics` (
+  `id` int NOT NULL AUTO_INCREMENT,
+  `key` varchar(190) NOT NULL COMMENT 'Metric key: `String` (limit 190 
characters). Part of *Primary Key* for ``metrics`` table.',
+  `value` float NOT NULL COMMENT 'Metric value: `Float`. Defined as *Non-null* 
in schema.',
+  `worker_index` varchar(32) NOT NULL COMMENT 'Metric worker_index: `String` 
(limit 32 characters). Part of *Primary Key* for\r\n    ``metrics`` table.',
+  `timestamp` bigint(20) NOT NULL COMMENT 'Timestamp recorded for this metric 
entry: `BigInteger`. Part of *Primary Key* for   ``metrics`` table.',
+  `step` bigint(11) NOT NULL COMMENT 'Step recorded for this metric entry: 
`BigInteger`.',
+  `is_nan` int(11) NOT NULL COMMENT 'True if the value is in fact NaN.',
+  `job_name` varchar(32) NOT NULL COMMENT 'JOB NAME to which this metric 
belongs to: Part of *Primary Key* for ``metrics`` table.',
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Table structure for param
+-- ----------------------------
+DROP TABLE IF EXISTS `params`;
+CREATE TABLE `params` (
+  `id` int NOT NULL AUTO_INCREMENT,
+  `key` varchar(190) NOT NULL COMMENT '`String` (limit 190 characters). Part 
of *Primary Key* for ``params`` table.',
+  `value` varchar(32) NOT NULL COMMENT '`String` (limit 190 characters). 
Defined as *Non-null* in schema.',
+  `worker_index` varchar(32) NOT NULL COMMENT '`String` (limit 32 characters). 
Part of *Primary Key* for\r\n    ``metrics`` table.',
+  `job_name` varchar(32) NOT NULL COMMENT 'JOB NAME to which this parameter 
belongs to: Part of *Primary Key* for ``params`` table.',
+  PRIMARY KEY  (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Metric.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Metric.java
new file mode 100644
index 0000000..b4d806b
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Metric.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.submarine.server.workbench.database.entity;
+
+import java.math.BigInteger;
+
+/*
+# 
+-------+----------+--------------+---------------+------+--------+------------------+
+# | key   | value    | worker_index | timestamp     | step | is_nan | job_name 
        |
+# 
+-------+----------+--------------+---------------+------+--------+------------------+
+# | score | 0.666667 | worker-1     | 1569139525097 |    0 |      0 | 
application_1234 |
+# | score | 0.666667 | worker-1     | 1569149139731 |    0 |      0 | 
application_1234 |
+# | score | 0.666667 | worker-1     | 1569169376482 |    0 |      0 | 
application_1234 |
+# | score | 0.666667 | worker-1     | 1569236290721 |    0 |      0 | 
application_1234 |
+# | score | 0.666667 | worker-1     | 1569236466722 |    0 |      0 | 
application_1234 |
+# 
+-------+----------+--------------+---------------+------+--------+------------------+
+*/
+
+public class Metric extends BaseEntity {
+
+  private String key;
+  private Float value;
+  private String workerIndex;
+  private BigInteger timestamp;
+  private Integer step;
+  private Integer isNan;
+  private String jobName;
+
+  public String getKey() {
+    return this.key;
+  }
+
+  public void setKey(String key) {
+    this.key = key;
+  }
+
+  public Float getValue() {
+    return this.value;
+  }
+
+  public void setValue(Float value) {
+    this.value = value;
+  }
+
+  public String getWorkerIndex() {
+    return this.workerIndex;
+  }
+
+  public void setWorkerIndex(String workerIndex) {
+    this.workerIndex = workerIndex;
+  }
+
+  public BigInteger getTimestamp() {
+    return this.timestamp;
+  }
+
+  public void setTimestamp(BigInteger timestamp) {
+    this.timestamp = timestamp;
+  }
+
+  public Integer getStep() {
+    return this.step;
+  }
+
+  public void setStep(Integer step) {
+    this.step = step;
+  }
+
+  public Integer getIsNan() {
+    return this.isNan;
+  }
+
+  public void setIsNan(Integer isNan) {
+    this.isNan = isNan;
+  }
+
+  public String getJobName() {
+    return this.jobName;
+  }
+
+  public void setJobName(String jobName) {
+    this.jobName = jobName;
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Param.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Param.java
new file mode 100644
index 0000000..3078775
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/entity/Param.java
@@ -0,0 +1,68 @@
+/*
+ * 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.submarine.server.workbench.database.entity;
+
+/*
+# +----------+-------+--------------+-----------------------+
+# | key      | value | worker_index | job_name              |
+# +----------+-------+--------------+-----------------------+
+# | max_iter | 100   | worker-1     | application_123651651 |
+# | n_jobs   | 5     | worker-1     | application_123456898 |
+# | alpha    | 20    | worker-1     | application_123456789 |
+# +----------+-------+--------------+-----------------------+
+*/
+
+public class Param extends BaseEntity {
+  String key;
+  String value;
+  String workerIndex;
+  String jobName;
+
+  public String getKey() {
+    return this.key;
+  }
+
+  public void setKey(String key) {
+    this.key = key;
+  }
+
+  public String getValue() {
+    return this.value;
+  }
+
+  public void setValue(String value) {
+    this.value = value;
+  }
+
+  public String getWorkerIndex() {
+    return this.workerIndex;
+  }
+
+  public void setWorkerIndex(String workerIndex) {
+    this.workerIndex = workerIndex;
+  }
+
+  public String getJobName() {
+    return this.jobName;
+  }
+
+  public void setJobName(String jobName) {
+    this.jobName = jobName;
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/MetricMapper.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/MetricMapper.java
new file mode 100644
index 0000000..3d4c7c8
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/MetricMapper.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.submarine.server.workbench.database.mappers;
+
+import java.util.List;
+
+import org.apache.submarine.server.workbench.database.entity.Metric;
+
+public interface MetricMapper {
+
+  List<Metric> selectAll();
+
+  int deleteById(String id);
+
+  int insert(Metric metric);
+  
+  Metric selectById(String id);
+
+  int update(Metric metric);
+
+  List<Metric> selectByPrimaryKeySelective(Metric metric);
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/ParamMapper.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/ParamMapper.java
new file mode 100644
index 0000000..759905d
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/mappers/ParamMapper.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.submarine.server.workbench.database.mappers;
+
+import java.util.List;
+
+import org.apache.submarine.server.workbench.database.entity.Param;
+
+public interface ParamMapper {
+
+  List<Param> selectAll();
+
+  int deleteById(String id);
+
+  int insert(Param param);
+  
+  Param selectById(String id);
+
+  int update(Param param);
+
+  List<Param> selectByPrimaryKeySelective(Param param);
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/MetricService.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/MetricService.java
new file mode 100644
index 0000000..b5b3cd6
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/MetricService.java
@@ -0,0 +1,125 @@
+/*
+ * 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.submarine.server.workbench.database.service;
+
+import org.apache.submarine.server.workbench.database.MyBatisUtil;
+import org.apache.submarine.server.workbench.database.entity.Metric;
+import org.apache.submarine.server.workbench.database.mappers.MetricMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import org.apache.ibatis.session.SqlSession;
+
+public class MetricService {
+  private static final Logger LOG = 
LoggerFactory.getLogger(MetricService.class);
+
+  public MetricService() {
+  }
+
+  public List<Metric> selectAll() throws Exception {
+    List<Metric> result;
+    LOG.info("Metric selectAll");
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      result = mapper.selectAll();
+      sqlSession.commit();
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return result;
+  }
+  
+  public boolean deleteById(String id) throws Exception {
+    LOG.info("Metric deleteByPrimaryKey {}", id);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      mapper.deleteById(id);
+      sqlSession.commit();
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+
+  public boolean insert(Metric metric) throws Exception {
+    LOG.info("Metric insert {}", metric);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      mapper.insert(metric);
+      sqlSession.commit();
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+
+  public Metric selectById(String id) throws Exception {
+    LOG.info("Metric selectByPrimaryKey {}", id);
+    Metric metric;
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      metric = mapper.selectById(id);
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return metric;
+  }
+  
+  public boolean update(Metric metric) throws Exception {
+    LOG.info("Metric update {}", metric);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      mapper.update(metric);
+      sqlSession.commit();
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+
+  public List<Metric> selectByPrimaryKeySelective(Metric metric) throws 
Exception {
+    List<Metric> result;
+    LOG.info("Metric selectByPrimaryKeySelective");
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      MetricMapper mapper = sqlSession.getMapper(MetricMapper.class);
+      result = mapper.selectByPrimaryKeySelective(metric);
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return result;
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/ParamService.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/ParamService.java
new file mode 100644
index 0000000..0e59947
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/service/ParamService.java
@@ -0,0 +1,119 @@
+/*
+ * 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.submarine.server.workbench.database.service;
+
+import java.util.List;
+
+import org.apache.ibatis.session.SqlSession;
+import org.apache.submarine.server.workbench.database.MyBatisUtil;
+import org.apache.submarine.server.workbench.database.entity.Param;
+import org.apache.submarine.server.workbench.database.mappers.ParamMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ParamService {
+  
+  private static final Logger LOG = 
LoggerFactory.getLogger(ParamService.class);
+
+  public List<Param> selectAll() throws Exception {
+    LOG.info("Param selectAll");
+    List<Param> params;
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      params = mapper.selectAll();
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return params;
+  }
+  
+  public boolean deleteById(String id) throws Exception {
+    LOG.info("Param deleteById {}", id);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      mapper.deleteById(id);
+      sqlSession.commit();
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+
+  public boolean insert(Param param) throws Exception {
+    LOG.info("Param insert {}", param);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      mapper.insert(param);
+      sqlSession.commit();
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+  
+  public Param selectById(String id) throws Exception {
+    LOG.info("Param selectById {}", id);
+    Param param;
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      param = mapper.selectById(id);
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return param;
+  }
+
+  public boolean update(Param param) throws Exception {
+    LOG.info("Param update {}", param);
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      mapper.update(param);
+      sqlSession.commit();
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return true;
+  }
+
+  public List<Param> selectByPrimaryKeySelective(Param param) throws Exception 
{
+    List<Param> result;
+    LOG.info("Param selectByPrimaryKeySelective");
+
+    try (SqlSession sqlSession = MyBatisUtil.getSqlSession()) {
+      ParamMapper mapper = sqlSession.getMapper(ParamMapper.class);
+      result = mapper.selectByPrimaryKeySelective(param);
+
+    } catch (Exception e) {
+      LOG.error(e.getMessage(), e);
+      throw new Exception(e);
+    }
+    return result;
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/MetricRestApi.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/MetricRestApi.java
new file mode 100644
index 0000000..caa2f9f
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/MetricRestApi.java
@@ -0,0 +1,169 @@
+/*
+ * 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.submarine.server.workbench.rest;
+
+import org.apache.submarine.server.workbench.annotation.SubmarineApi;
+import org.apache.submarine.server.workbench.database.entity.Metric;
+import org.apache.submarine.server.workbench.database.service.MetricService;
+import org.apache.submarine.server.response.JsonResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+
+@Path("/metric")
+@Produces("application/json")
+@Singleton
+public class MetricRestApi {
+  private static final Logger LOG = 
LoggerFactory.getLogger(LoginRestApi.class);
+  MetricService metricService = new MetricService();
+
+  @Inject
+  public MetricRestApi() {
+  }
+
+  /*
+  # 
+-------+----------+--------------+---------------+------+--------+------------------+
+  # | key   | value    | worker_index | timestamp     | step | is_nan | 
job_name         |
+  # 
+-------+----------+--------------+---------------+------+--------+------------------+
+  # | score | 0.666667 | worker-1     | 1569139525097 |    0 |      0 | 
application_1234 |
+  # | score | 0.666667 | worker-1     | 1569149139731 |    0 |      0 | 
application_1234 |
+  # | score | 0.666667 | worker-1     | 1569169376482 |    0 |      0 | 
application_1234 |
+  # | score | 0.666667 | worker-1     | 1569236290721 |    0 |      0 | 
application_1234 |
+  # | score | 0.666667 | worker-1     | 1569236466722 |    0 |      0 | 
application_1234 |
+  # 
+-------+----------+--------------+---------------+------+--------+------------------+
+  */
+
+  @GET
+  @Path("/list")
+  @SubmarineApi
+  public Response listMetric(@QueryParam("metricKey") String metricKey,
+                              @QueryParam("value") Float value,
+                              @QueryParam("workerIndex") String workerIndex,
+                              @QueryParam("timestamp") BigInteger timestamp,
+                              @QueryParam("step") Integer step,
+                              @QueryParam("isNan") Integer isNan,
+                              @QueryParam("jobName") String jobName,
+                              @QueryParam("id") String id) {
+
+    Metric metric = new Metric();
+    metric.setKey(metricKey);
+    metric.setValue(value);
+    metric.setWorkerIndex(workerIndex);
+    metric.setTimestamp(timestamp);
+    metric.setStep(step);
+    metric.setIsNan(isNan);
+    metric.setJobName(jobName);
+    metric.setId(id);
+
+    LOG.info("listMetric ({})", metric);
+
+    List<Metric> metrics;
+    try {
+      metrics = metricService.selectByPrimaryKeySelective(metric);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<List<Metric>>(Response.Status.OK).success(true).result(metrics).build();
+  }
+
+  @GET
+  @Path("/{id}")
+  @SubmarineApi
+  public Response getMetric(@PathParam("id") String id) {
+    Metric metric;
+    try {
+      metric = metricService.selectById(id);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).build();
+    }
+    return new 
JsonResponse.Builder<Metric>(Response.Status.OK).success(true).result(metric).build();
+  }
+
+  @POST
+  @Path("/add")
+  @SubmarineApi
+  public Response postMetric(Metric metric) {
+    boolean result = false;
+    try {
+      result = metricService.insert(metric);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @DELETE
+  @Path("/delete")
+  @SubmarineApi
+  public Response deleteMetric(@QueryParam("id") String id) {
+    boolean result = false;
+    try {
+      result = metricService.deleteById(id);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @PUT
+  @Path("/edit")
+  @SubmarineApi
+  public Response putMetric(Metric metric) {
+    boolean result = false;
+    try {
+      result = metricService.update(metric);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @POST
+  @Path("/selective")
+  @SubmarineApi
+  public Response selectByPrimaryKeySelective(Metric metric) {
+    List<Metric> metrics;
+    try {
+      metrics = metricService.selectByPrimaryKeySelective(metric);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<List<Metric>>(Response.Status.OK).success(true).result(metrics).build();
+  }
+}
diff --git 
a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ParamRestApi.java
 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ParamRestApi.java
new file mode 100644
index 0000000..9af5556
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ParamRestApi.java
@@ -0,0 +1,165 @@
+/*
+ * 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.submarine.server.workbench.rest;
+
+import org.apache.submarine.server.workbench.annotation.SubmarineApi;
+import org.apache.submarine.server.workbench.database.entity.Param;
+import org.apache.submarine.server.workbench.database.service.ParamService;
+import org.apache.submarine.server.response.JsonResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+
+@Path("/param")
+@Produces("application/json")
+@Singleton
+public class ParamRestApi {
+  private static final Logger LOG = 
LoggerFactory.getLogger(LoginRestApi.class);
+  ParamService paramService = new ParamService();
+
+  @Inject
+  public ParamRestApi() {
+  }
+
+  /*
+  # +----------+-------+--------------+-----------------------+
+  # | key      | value | worker_index | job_name              |
+  # +----------+-------+--------------+-----------------------+
+  # | max_iter | 100   | worker-1     | application_123651651 |
+  # | n_jobs   | 5     | worker-1     | application_123456898 |
+  # | alpha    | 20    | worker-1     | application_123456789 |
+  # +----------+-------+--------------+-----------------------+
+  */
+
+  @GET
+  @Path("/list")
+  @SubmarineApi
+  public Response listParam(@QueryParam("id") String id, 
+                            @QueryParam("paramKey") String paramKey, 
+                            @QueryParam("value") String value, 
+                            @QueryParam("workerIndex") String workerIndex, 
+                            @QueryParam("jobName") String jobName) {
+    
+    Param param = new Param();
+    param.setId(id);
+    param.setKey(paramKey);
+    param.setValue(value);
+    param.setWorkerIndex(workerIndex);
+    param.setJobName(jobName);
+
+    LOG.info("listParam ({})", param);
+    
+    List<Param> params;
+    try {
+      params = paramService.selectByPrimaryKeySelective(param);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<List<Param>>(Response.Status.OK).success(true).result(params).build();
+  }
+
+  @GET
+  @Path("/{id}")
+  @SubmarineApi
+  public Response getParam(@PathParam("id") String id) {
+    LOG.info("getParam ({})", id);
+    
+    Param param;
+    try {
+      param = paramService.selectById(id);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Param>(Response.Status.OK).success(true).result(param).build();
+  }
+
+  @POST
+  @Path("/add")
+  @SubmarineApi
+  public Response postParam(Param param) {
+    LOG.info("postParam ({})", param);
+    boolean result = false;
+    try {
+      result = paramService.insert(param);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @DELETE
+  @Path("/delete")
+  @SubmarineApi
+  public Response deleteParam(@QueryParam("id") String id) {
+    LOG.info("deleteParam ({})", id);
+    boolean result = false;
+    try {
+      result = paramService.deleteById(id);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @PUT
+  @Path("/edit")
+  @SubmarineApi
+  public Response putParam(Param param) {
+    LOG.info("putParam ({})", param);
+    boolean result = false;
+    try {
+      result = paramService.update(param);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(true).result(result).build();
+  }
+
+  @POST
+  @Path("/selective")
+  @SubmarineApi
+  public Response selectByPrimaryKeySelective(Param metric) {
+    List<Param> params;
+    try {
+      params = paramService.selectByPrimaryKeySelective(metric);
+    } catch (Exception e) {
+      LOG.error(e.toString());
+      return new 
JsonResponse.Builder<Boolean>(Response.Status.OK).success(false).build();
+    }
+    return new 
JsonResponse.Builder<List<Param>>(Response.Status.OK).success(true).result(params).build();
+  }
+}
diff --git a/submarine-server/server-core/src/main/resources/mybatis-config.xml 
b/submarine-server/server-core/src/main/resources/mybatis-config.xml
index d2958d3..62a4201 100755
--- a/submarine-server/server-core/src/main/resources/mybatis-config.xml
+++ b/submarine-server/server-core/src/main/resources/mybatis-config.xml
@@ -64,5 +64,7 @@
     <mapper 
resource='org/apache/submarine/database/mappers/ProjectMapper.xml'/>
     <mapper 
resource='org/apache/submarine/database/mappers/ProjectFilesMapper.xml'/>
     <mapper resource='org/apache/submarine/database/mappers/JobMapper.xml'/>
+    <mapper resource='org/apache/submarine/database/mappers/MetricMapper.xml'/>
+    <mapper resource='org/apache/submarine/database/mappers/ParamMapper.xml'/>
   </mappers>
 </configuration>
diff --git 
a/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/MetricMapper.xml
 
b/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/MetricMapper.xml
new file mode 100644
index 0000000..bcd711b
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/MetricMapper.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd";>
+<mapper 
namespace="org.apache.submarine.server.workbench.database.mappers.MetricMapper">
+  <resultMap id="BaseEntityResultMap" 
type="org.apache.submarine.server.workbench.database.entity.BaseEntity">
+    <id property="id" column="id"/>
+  </resultMap>
+
+  <resultMap id="resultMap" 
type="org.apache.submarine.server.workbench.database.entity.Metric" 
extends="BaseEntityResultMap">
+    <result column="key" jdbcType="VARCHAR" property="key" />
+    <result column="value" jdbcType="FLOAT" property="value" />
+    <result column="worker_index" jdbcType="VARCHAR" property="workerIndex" />
+    <result column="timestamp" jdbcType="BIGINT" property="timestamp" />
+    <result column="step" jdbcType="INTEGER" property="step" />
+    <result column="is_nan" jdbcType="INTEGER" property="isNan" />
+    <result column="job_name" jdbcType="VARCHAR" property="jobName" />
+  </resultMap>
+
+  <!-- key is reserved word in mysql -->
+  <sql id="Base_Column_List">
+    id, `key`, value, worker_index, timestamp, step, is_nan, job_name
+  </sql>
+
+  <select id="selectAll" parameterType="java.lang.String" 
resultMap="resultMap">
+    select
+    <include refid="Base_Column_List" />
+    from metrics
+    where 1 = 1
+  </select>
+
+  <select id="selectById" parameterType="java.lang.String" 
resultMap="resultMap">
+    select
+    <include refid="Base_Column_List" />
+    from metrics
+    where id = #{id,jdbcType=VARCHAR}
+  </select>
+
+  <delete id="deleteById" parameterType="java.lang.String">
+    delete from metrics
+    where id = #{id,jdbcType=VARCHAR}
+  </delete>
+
+  <insert id="insert" 
parameterType="org.apache.submarine.server.workbench.database.entity.Metric"
+          useGeneratedKeys="true" keyProperty="id">
+    insert into metrics (`key`, value, worker_index, timestamp,
+      step, is_nan, job_name)
+    values (#{key,jdbcType=VARCHAR}, 
+      #{value,jdbcType=FLOAT},
+      #{workerIndex,jdbcType=VARCHAR}, 
+      #{timestamp,jdbcType=BIGINT}, 
+      #{step,jdbcType=INTEGER},
+      #{isNan,jdbcType=INTEGER}, 
+      #{jobName,jdbcType=VARCHAR})
+  </insert>
+  
+  <update id="update" 
parameterType="org.apache.submarine.server.workbench.database.entity.Metric">
+    update metrics
+    set `key` = #{key,jdbcType=VARCHAR},
+      value = #{value,jdbcType=FLOAT},
+      worker_index = #{workerIndex,jdbcType=VARCHAR},
+      timestamp = #{timestamp,jdbcType=BIGINT},
+      step = #{step,jdbcType=INTEGER},
+      is_nan = #{isNan,jdbcType=INTEGER},
+      job_name = #{jobName,jdbcType=VARCHAR}
+    where id = #{id,jdbcType=VARCHAR}
+  </update>
+  
+  <select id="selectByPrimaryKeySelective" parameterType="java.lang.String" 
resultMap="resultMap">
+  select
+  <include refid="Base_Column_List" />
+  from metrics
+  where 1 = 1
+    <if test="key != null">
+      AND `key` = #{key,jdbcType=VARCHAR}
+    </if>
+    <if test="workerIndex != null">
+      AND worker_index = #{workerIndex,jdbcType=VARCHAR}
+    </if>
+    <if test="timestamp != null">
+      AND timestamp = #{timestamp,jdbcType=BIGINT}
+    </if>
+    <if test="step != null">
+      AND step = #{step,jdbcType=INTEGER}
+    </if>
+    <if test="isNan != null">
+      AND is_nan = #{isNan,jdbcType=INTEGER}
+    </if>
+    <if test="jobName != null">
+      AND job_name = #{jobName,jdbcType=VARCHAR}
+    </if>
+    <if test="id != null">
+      AND id = #{id,jdbcType=VARCHAR}
+    </if>
+  </select>
+</mapper>
diff --git 
a/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/ParamMapper.xml
 
b/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/ParamMapper.xml
new file mode 100644
index 0000000..41c5cd2
--- /dev/null
+++ 
b/submarine-server/server-core/src/main/resources/org/apache/submarine/database/mappers/ParamMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd";>
+<mapper 
namespace="org.apache.submarine.server.workbench.database.mappers.ParamMapper">
+  <resultMap id="BaseEntityResultMap" 
type="org.apache.submarine.server.workbench.database.entity.BaseEntity">
+    <id property="id" column="id"/>
+  </resultMap>
+
+  <resultMap id="resultMap" 
type="org.apache.submarine.server.workbench.database.entity.Param" 
extends="BaseEntityResultMap">
+    <result column="key" jdbcType="VARCHAR" property="key" />
+    <result column="value" jdbcType="FLOAT" property="value" />
+    <result column="worker_index" jdbcType="VARCHAR" property="workerIndex" />
+    <result column="job_name" jdbcType="VARCHAR" property="jobName" />
+  </resultMap>
+
+  <!-- key is reserved word in mysql -->
+  <sql id="Base_Column_List">
+    id, `key`, value, worker_index, job_name
+  </sql>
+
+  <select id="selectAll" parameterType="java.lang.String" 
resultMap="resultMap">
+    select
+    <include refid="Base_Column_List" />
+    from params
+    where 1 = 1
+  </select>
+
+  <select id="selectById" parameterType="java.lang.String" 
resultMap="resultMap">
+    select
+    <include refid="Base_Column_List" />
+    from params
+    where id = #{id,jdbcType=VARCHAR}
+  </select>
+
+  <delete id="deleteById" parameterType="java.lang.String">
+    delete from params
+    where id = #{id,jdbcType=VARCHAR}
+  </delete>
+
+  <insert id="insert" 
parameterType="org.apache.submarine.server.workbench.database.entity.Param"
+          useGeneratedKeys="true" keyProperty="id">
+    insert into params (`key`, value, worker_index, job_name)
+    values (#{key,jdbcType=VARCHAR}, 
+      #{value,jdbcType=FLOAT},
+      #{workerIndex,jdbcType=VARCHAR}, 
+      #{jobName,jdbcType=VARCHAR})
+  </insert>
+
+  <update id="update" 
parameterType="org.apache.submarine.server.workbench.database.entity.Param">
+    update params
+    set `key` = #{key,jdbcType=VARCHAR},
+      value = #{value,jdbcType=FLOAT},
+      worker_index = #{workerIndex,jdbcType=VARCHAR},
+      job_name = #{jobName,jdbcType=VARCHAR}
+    where id = #{id,jdbcType=VARCHAR}
+  </update>
+
+  <select id="selectByPrimaryKeySelective" parameterType="java.lang.String" 
resultMap="resultMap">
+    select
+    <include refid="Base_Column_List" />
+    from params
+    where 1 = 1
+      <if test="key != null">
+        AND `key` = #{key,jdbcType=VARCHAR}
+      </if>
+      <if test="workerIndex != null">
+        AND worker_index = #{workerIndex,jdbcType=VARCHAR}
+      </if>
+      <if test="jobName != null">
+        AND job_name = #{jobName,jdbcType=VARCHAR}
+      </if>
+      <if test="id != null">
+        AND id = #{id,jdbcType=VARCHAR}
+      </if>
+   </select>
+</mapper>
diff --git 
a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/MetricServiceTest.java
 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/MetricServiceTest.java
new file mode 100644
index 0000000..d3623d8
--- /dev/null
+++ 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/MetricServiceTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.submarine.server.workbench.database.service;
+
+import org.apache.submarine.server.workbench.database.entity.Metric;
+import org.junit.After;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.math.BigInteger;
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class MetricServiceTest {
+  private static final Logger LOG = 
LoggerFactory.getLogger(MetricServiceTest.class);
+  MetricService metricService = new MetricService();
+
+  @After
+  public void removeAllRecord() throws Exception {
+    List<Metric> metricList = metricService.selectAll();
+    LOG.info("jobList.size():{}", metricList.size());
+    for (Metric metric : metricList) {
+      metricService.deleteById(metric.getId());
+    }
+  }
+
+  @Test
+  public void testSelect() throws Exception {
+    Metric metric = new Metric();
+    metric.setKey("test_score");
+    metric.setValue((float) 0.666667);
+    metric.setWorkerIndex("test_worker-1");
+    metric.setTimestamp(new BigInteger("1569139525097"));
+    metric.setStep(0);
+    metric.setIsNan(0);
+    metric.setJobName("test_application_1234");
+    boolean result = metricService.insert(metric);
+    assertTrue(result);
+    List<Metric> metricList = metricService.selectAll();
+
+    assertEquals(metricList.size(), 1);
+
+    Metric metricDb = metricList.get(0);
+    compareMetrics(metric, metricDb);
+    
+    Metric metricDb2 = 
metricService.selectByPrimaryKeySelective(metric).get(0);
+    compareMetrics(metric, metricDb2);
+  }
+
+  @Test
+  public void testUpdate() throws Exception {
+    Metric metric = new Metric();
+    metric.setKey("test_score");
+    metric.setValue((float) 0.666667);
+    metric.setWorkerIndex("test_worker-2");
+    metric.setTimestamp(new BigInteger("1569139525098"));
+    metric.setStep(0);
+    metric.setIsNan(0);
+    metric.setJobName("test_application_1234");
+    boolean result = metricService.insert(metric);
+    assertTrue(result);
+
+    metric.setKey("test_scoreNew");
+    metric.setValue((float) 0.766667);
+    metric.setWorkerIndex("test_worker-New");
+    metric.setTimestamp(new BigInteger("2569139525098"));
+    metric.setStep(1);
+    metric.setIsNan(1);
+    metric.setJobName("test_application_1234New");
+
+    boolean editResult = metricService.update(metric);
+    assertTrue(editResult);
+    
+    Metric metricDb2 = 
metricService.selectByPrimaryKeySelective(metric).get(0);
+    compareMetrics(metric, metricDb2);
+  }
+
+  @Test
+  public void testDelete() throws Exception {
+    Metric metric = new Metric();
+    metric.setKey("test_score");
+    metric.setValue((float) 0.666667);
+    metric.setWorkerIndex("test_worker-2");
+    metric.setTimestamp(new BigInteger("1569139525098"));
+    metric.setStep(0);
+    metric.setIsNan(0);
+    metric.setJobName("test_application_1234");
+    boolean result = metricService.insert(metric);
+    assertTrue(result);
+
+    Metric metricDb2 = 
metricService.selectByPrimaryKeySelective(metric).get(0);
+    boolean deleteResult = metricService.deleteById(metricDb2.getId());
+    assertTrue(deleteResult);
+  }
+
+  private void compareMetrics(Metric metric, Metric metricDb) {
+    assertEquals(metric.getId(), metricDb.getId());
+    assertEquals(metric.getIsNan(), metricDb.getIsNan());
+    assertEquals(metric.getJobName(), metricDb.getJobName());
+    assertEquals(metric.getKey(), metricDb.getKey());
+    assertEquals(metric.getStep(), metricDb.getStep());
+    assertEquals(metric.getTimestamp(), metricDb.getTimestamp());
+    assertEquals(metric.getValue(), metricDb.getValue());
+    assertEquals(metric.getWorkerIndex(), metricDb.getWorkerIndex());
+  }
+}
diff --git 
a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/ParamServiceTest.java
 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/ParamServiceTest.java
new file mode 100644
index 0000000..a6f0058
--- /dev/null
+++ 
b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/service/ParamServiceTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.submarine.server.workbench.database.service;
+
+import org.apache.submarine.server.workbench.database.entity.Param;
+import org.junit.After;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ParamServiceTest {
+  private static final Logger LOG = 
LoggerFactory.getLogger(ParamServiceTest.class);
+  ParamService paramService = new ParamService();
+
+  @After
+  public void removeAllRecord() throws Exception {
+    List<Param> paramList = paramService.selectAll();
+    LOG.info("paramList.size():{}", paramList.size());
+    for (Param param : paramList) {
+      paramService.deleteById(param.getId());
+    }
+  }
+
+  @Test
+  public void testSelect() throws Exception {
+    Param param = new Param();
+    param.setKey("test_score");
+    param.setValue("199");
+    param.setWorkerIndex("test_worker-1");
+    param.setJobName("test_application_123651651");
+    boolean result = paramService.insert(param);
+    assertTrue(result);
+    List<Param> paramList = paramService.selectAll();
+
+    assertEquals(paramList.size(), 1);
+
+    Param paramDb = paramList.get(0);
+    compareParams(param, paramDb);
+    
+    Param paramDb2 = paramService.selectByPrimaryKeySelective(param).get(0);
+    compareParams(param, paramDb2);
+  }
+
+  @Test
+  public void testUpdate() throws Exception {
+    Param param = new Param();
+    param.setKey("test_score");
+    param.setValue("100");
+    param.setWorkerIndex("test_worker-2");
+    param.setJobName("test_application_1234");
+    boolean result = paramService.insert(param);
+    assertTrue(result);
+
+    param.setKey("scoreNew");
+    param.setValue("100");
+    param.setWorkerIndex("worker-New");
+    param.setJobName("application_1234New");
+    boolean editResult = paramService.update(param);
+    assertTrue(editResult);
+    
+    Param paramDb2 = paramService.selectByPrimaryKeySelective(param).get(0);
+    compareParams(param, paramDb2);
+  }
+
+  @Test
+  public void testDelete() throws Exception {
+    Param param = new Param();
+    param.setKey("test_score");
+    param.setValue("100");
+    param.setWorkerIndex("test_worker-2");
+    param.setJobName("test_application_1234");
+
+    boolean result = paramService.insert(param);
+    assertTrue(result);
+
+    Param paramDb2 = paramService.selectByPrimaryKeySelective(param).get(0);
+
+    boolean deleteResult = paramService.deleteById(paramDb2.getId());
+    assertTrue(deleteResult);
+  }
+
+  private void compareParams(Param param, Param paramDb) {
+    assertEquals(param.getId(), paramDb.getId());
+    assertEquals(param.getJobName(), paramDb.getJobName());
+    assertEquals(param.getKey(), paramDb.getKey());
+    assertEquals(param.getValue(), paramDb.getValue());
+    assertEquals(param.getWorkerIndex(), paramDb.getWorkerIndex());
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to