You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ge...@apache.org on 2020/02/06 15:37:20 UTC

[incubator-iotdb] 02/05: add rest api.

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

geniuspig pushed a commit to branch http
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git

commit 262a3168c337d5f912782a27cc14754889ad548d
Author: zhutianci <zh...@gmail.com>
AuthorDate: Thu Feb 6 11:05:02 2020 +0800

    add rest api.
---
 server/pom.xml                                     |   5 +
 .../apache/iotdb/db/http/service/HttpService.java  |   5 -
 .../apache/iotdb/db/metrics/server/JettyUtil.java  |  25 +--
 .../iotdb/db/metrics/server/MetricsSystem.java     |  11 +-
 ...etricsServletSink.java => JsonServletSink.java} |  92 ++++-----
 .../apache/iotdb/db/metrics/ui/MetricsWebUI.java   |  25 ++-
 .../org/apache/iotdb/db/qp/QueryProcessor.java     |   6 +
 .../iotdb/db/rest/controller/RestController.java   | 207 +++++++++++++++++++++
 .../iotdb/db/{http => rest/model}/TimeValues.java  |   2 +-
 .../apache/iotdb/db/rest/service/RestService.java  | 177 ++++++++++++++++++
 .../QueryServlet.java => rest/util/RestUtil.java}  |  35 ++--
 .../apache/iotdb/db/service/MetricsService.java    |   7 +-
 .../src/main/resources/iotdb/ui/static/index.html  |   4 +-
 13 files changed, 487 insertions(+), 114 deletions(-)

diff --git a/server/pom.xml b/server/pom.xml
index b231975..180c31b 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -121,6 +121,11 @@
             <artifactId>stream</artifactId>
             <version>2.9.5</version>
         </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
+            <version>2.30</version>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/server/src/main/java/org/apache/iotdb/db/http/service/HttpService.java b/server/src/main/java/org/apache/iotdb/db/http/service/HttpService.java
deleted file mode 100644
index 87ba8ee..0000000
--- a/server/src/main/java/org/apache/iotdb/db/http/service/HttpService.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.apache.iotdb.db.http.service;
-
-public class HttpService {
-
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/metrics/server/JettyUtil.java b/server/src/main/java/org/apache/iotdb/db/metrics/server/JettyUtil.java
index ab2cff1..ce3a38d 100644
--- a/server/src/main/java/org/apache/iotdb/db/metrics/server/JettyUtil.java
+++ b/server/src/main/java/org/apache/iotdb/db/metrics/server/JettyUtil.java
@@ -33,7 +33,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
 
 public class JettyUtil {
 
-  public static ServletContextHandler createMetricsServletHandler(ObjectMapper mapper,MetricRegistry metricRegistry) {
+  public static ServletHolder createJsonServletHolder(ObjectMapper mapper,MetricRegistry metricRegistry) {
     HttpServlet httpServlet = new HttpServlet() {
       private static final long serialVersionUID = 1L;
 
@@ -56,27 +56,14 @@ public class JettyUtil {
         doGet(req, resp);
       }
     };
-    
-    return createServletHandler("/json", httpServlet, "/");
-  }
 
-  public static ServletContextHandler createServletHandler(String path, HttpServlet servlet, String pathSpec) {
-    ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
-    ServletHolder holder = new ServletHolder(servlet);
-    contextHandler.setContextPath(path);
-    contextHandler.addServlet(holder, pathSpec);
-    return contextHandler;
+    return new ServletHolder(httpServlet);
   }
 
-  public static ServletContextHandler createStaticHandler() {
-    ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
-    URL res = JettyUtil.class.getClassLoader().getResource("iotdb/ui/static");
-    HttpServlet servlet = new DefaultServlet();
-    ServletHolder holder = new ServletHolder(servlet);
-    holder.setInitParameter("resourceBase", Objects.requireNonNull(res).toString());
-    contextHandler.setContextPath("/static");
-    contextHandler.addServlet(holder, "/");
-    return contextHandler;
+  public static ServletHolder createStaticServletHolder() {
+    ServletHolder holder = new ServletHolder("static", DefaultServlet.class);
+    holder.setInitParameter("dirAllowed", "true");
+    return holder;
   }
 
   public static Server getJettyServer(List<ServletContextHandler> handlers, int port) {
diff --git a/server/src/main/java/org/apache/iotdb/db/metrics/server/MetricsSystem.java b/server/src/main/java/org/apache/iotdb/db/metrics/server/MetricsSystem.java
index 7872b14..cfc726a 100644
--- a/server/src/main/java/org/apache/iotdb/db/metrics/server/MetricsSystem.java
+++ b/server/src/main/java/org/apache/iotdb/db/metrics/server/MetricsSystem.java
@@ -15,12 +15,12 @@
 package org.apache.iotdb.db.metrics.server;
 
 import java.util.ArrayList;
-import org.apache.iotdb.db.metrics.sink.MetricsServletSink;
+import org.apache.iotdb.db.metrics.sink.JsonServletSink;
 import org.apache.iotdb.db.metrics.sink.Sink;
 import org.apache.iotdb.db.metrics.source.MetricsSource;
 import org.apache.iotdb.db.metrics.source.Source;
-import org.eclipse.jetty.servlet.ServletContextHandler;
 import com.codahale.metrics.MetricRegistry;
+import org.eclipse.jetty.servlet.ServletHolder;
 
 public class MetricsSystem {
 
@@ -40,8 +40,11 @@ public class MetricsSystem {
     return metricRegistry;
   }
 
-  public ServletContextHandler getServletHandlers() {
-    return new MetricsServletSink(metricRegistry).getHandler();
+  /**
+   * to get a json Servlet Holder
+   */
+  public ServletHolder getServletHolder() {
+    return new JsonServletSink(metricRegistry).getHolder();
   }
 
   public void start() {
diff --git a/server/src/main/java/org/apache/iotdb/db/metrics/sink/MetricsServletSink.java b/server/src/main/java/org/apache/iotdb/db/metrics/sink/JsonServletSink.java
similarity index 81%
rename from server/src/main/java/org/apache/iotdb/db/metrics/sink/MetricsServletSink.java
rename to server/src/main/java/org/apache/iotdb/db/metrics/sink/JsonServletSink.java
index c88e447..16003e5 100644
--- a/server/src/main/java/org/apache/iotdb/db/metrics/sink/MetricsServletSink.java
+++ b/server/src/main/java/org/apache/iotdb/db/metrics/sink/JsonServletSink.java
@@ -1,46 +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.iotdb.db.metrics.sink;
-
-import java.util.concurrent.TimeUnit;
-import org.apache.iotdb.db.metrics.server.JettyUtil;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.json.MetricsModule;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public class MetricsServletSink implements Sink {
-
-  private MetricRegistry registry;
-
-  public MetricsServletSink(MetricRegistry registry) {
-    this.registry = registry;
-  }
-
-  public ServletContextHandler getHandler() {
-    ObjectMapper mapper = new ObjectMapper()
-        .registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, false));
-    return JettyUtil.createMetricsServletHandler(mapper, registry);
-  }
-
-  @Override
-  public void start() {}
-
-  @Override
-  public void stop() {}
-
-  @Override
-  public void report() {}
-}
+/*
+ * 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.iotdb.db.metrics.sink;
+
+import java.util.concurrent.TimeUnit;
+import org.apache.iotdb.db.metrics.server.JettyUtil;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.json.MetricsModule;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+public class JsonServletSink implements Sink {
+
+  private MetricRegistry registry;
+
+  public JsonServletSink(MetricRegistry registry) {
+    this.registry = registry;
+  }
+
+  public ServletHolder getHolder() {
+    ObjectMapper mapper = new ObjectMapper()
+        .registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.MILLISECONDS, false));
+    return JettyUtil.createJsonServletHolder(mapper, registry);
+  }
+
+  @Override
+  public void start() {}
+
+  @Override
+  public void stop() {}
+
+  @Override
+  public void report() {}
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metrics/ui/MetricsWebUI.java b/server/src/main/java/org/apache/iotdb/db/metrics/ui/MetricsWebUI.java
index fb52267..31395ef 100644
--- a/server/src/main/java/org/apache/iotdb/db/metrics/ui/MetricsWebUI.java
+++ b/server/src/main/java/org/apache/iotdb/db/metrics/ui/MetricsWebUI.java
@@ -14,37 +14,34 @@
  */
 package org.apache.iotdb.db.metrics.ui;
 
-import java.util.ArrayList;
-import java.util.List;
 import org.apache.iotdb.db.metrics.server.JettyUtil;
 import org.apache.iotdb.db.metrics.server.QueryServlet;
-import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.servlet.ServletContextHandler;
 import com.codahale.metrics.MetricRegistry;
+import org.eclipse.jetty.servlet.ServletHolder;
 
 public class MetricsWebUI {
 
-  private List<ServletContextHandler> handlers = new ArrayList<>();
+  private ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS);
   private MetricRegistry metricRegistry;
 
   public MetricsWebUI(MetricRegistry metricRegistry) {
     this.metricRegistry = metricRegistry;
   }
 
-  public List<ServletContextHandler> getHandlers() {
-    return handlers;
-  }
-
   public void initialize() {
     MetricsPage masterPage = new MetricsPage(metricRegistry);
     QueryServlet queryServlet = new QueryServlet(masterPage);
-    ServletContextHandler staticHandler = JettyUtil.createStaticHandler();
-    ServletContextHandler queryHandler = JettyUtil.createServletHandler("/",queryServlet, "/");
-    handlers.add(staticHandler);
-    handlers.add(queryHandler);
+    handler.setContextPath("/metrics");
+    handler.setResourceBase(
+        String.valueOf(MetricsWebUI.class.getClassLoader().getResource("iotdb/ui/static")));
+    ServletHolder queryServletHolder = new ServletHolder(queryServlet);
+    handler.addServlet(queryServletHolder, "/query");
+    ServletHolder staticServletHolder = JettyUtil.createStaticServletHolder();
+    handler.addServlet(staticServletHolder, "/");
   }
 
-  public Server getServer(int port) {
-    return JettyUtil.getJettyServer(handlers, port);
+  public ServletContextHandler getHandler() {
+    return handler;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java b/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
index 69c0156..cb624fa 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/QueryProcessor.java
@@ -68,6 +68,12 @@ public class QueryProcessor {
     return physicalGenerator.transformToPhysicalPlan(operator);
   }
 
+  public PhysicalPlan logicalPlanToPhysicalPlan(Operator operator) throws QueryProcessException {
+    operator = logicalOptimize(operator, executor);
+    PhysicalGenerator physicalGenerator = new PhysicalGenerator(executor);
+    return physicalGenerator.transformToPhysicalPlan(operator);
+  }
+
 
   /**
    * given an unoptimized logical operator tree and return a optimized result.
diff --git a/server/src/main/java/org/apache/iotdb/db/rest/controller/RestController.java b/server/src/main/java/org/apache/iotdb/db/rest/controller/RestController.java
new file mode 100644
index 0000000..c0ed5f8
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/rest/controller/RestController.java
@@ -0,0 +1,207 @@
+/*
+ * 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.iotdb.db.rest.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.auth.authorizer.IAuthorizer;
+import org.apache.iotdb.db.auth.authorizer.LocalFileAuthorizer;
+import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.exception.storageGroup.StorageGroupException;
+import org.apache.iotdb.db.rest.model.TimeValues;
+import org.apache.iotdb.db.rest.service.RestService;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * It’s used for mapping http request.
+ */
+
+@Path("/")
+public class RestController {
+
+  private static final Logger logger = LoggerFactory.getLogger(RestController.class);
+  private RestService restService = new RestService();
+
+  /**
+   * http request to login IoTDB
+   * @param username username for login IoTDB
+   * @param password password for login IoTDB
+   */
+
+  @Path("/login/{username}&&{password}")
+  @POST
+  public void login(@PathParam("username") String username, @PathParam("password") String password)
+      throws AuthException {
+    logger.info("{}: receive http request from username {}", IoTDBConstant.GLOBAL_DB_NAME,
+        username);
+    IAuthorizer authorizer = LocalFileAuthorizer.getInstance();
+    boolean status = authorizer.login(username, password);
+    if (status) {
+      restService.setUsername(username);
+      logger.info("{}: Login successfully. User : {}", IoTDBConstant.GLOBAL_DB_NAME, username);
+    } else {
+      throw new AuthException("Wrong login password");
+    }
+  }
+
+  /**
+   *
+   * @param request this request will be in json format.
+   * @param response this response will be in json format.
+   * @return json in String
+   */
+  @Path("/query")
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  @Consumes(MediaType.APPLICATION_JSON)
+  public String query(HttpServletRequest request, HttpServletResponse response) {
+    String targetStr = "target";
+    response.setStatus(200);
+    try {
+      JSONObject jsonObject = getRequestBodyJson(request);
+      assert jsonObject != null;
+      JSONObject range = (JSONObject) jsonObject.get("range");
+      Pair<String, String> timeRange = new Pair<>((String) range.get("from"), (String) range.get("to"));
+      JSONArray array = (JSONArray) jsonObject.get("targets"); // []
+      JSONArray result = new JSONArray();
+      for (int i = 0; i < array.size(); i++) {
+        JSONObject object = (JSONObject) array.get(i); // {}
+        if (!object.containsKey(targetStr)) {
+          return "[]";
+        }
+        String target = (String) object.get(targetStr);
+        String type = getJsonType(jsonObject);
+        JSONObject obj = new JSONObject();
+        obj.put("target", target);
+        if (type.equals("table")) {
+          setJsonTable(obj, target, timeRange);
+        } else if (type.equals("timeserie")) {
+          setJsonTimeseries(obj, target, timeRange);
+        }
+        result.add(i, obj);
+      }
+      logger.info("query finished");
+      return result.toString();
+    } catch (Exception e) {
+      logger.error("/query failed", e);
+    }
+    return null;
+  }
+
+  /**
+   * get request body JSON.
+   *
+   * @param request http request
+   * @return request JSON
+   * @throws JSONException JSONException
+   */
+  private JSONObject getRequestBodyJson(HttpServletRequest request) throws JSONException {
+    try {
+      BufferedReader br = request.getReader();
+      StringBuilder sb = new StringBuilder();
+      String line;
+      while ((line = br.readLine()) != null) {
+        sb.append(line);
+      }
+      return JSON.parseObject(sb.toString());
+    } catch (IOException e) {
+      logger.error("getRequestBodyJson failed", e);
+    }
+    return null;
+  }
+
+  /**
+   * get JSON type of input JSON object.
+   *
+   * @param jsonObject JSON Object
+   * @return type (string)
+   * @throws JSONException JSONException
+   */
+  private String getJsonType(JSONObject jsonObject) throws JSONException {
+    JSONArray array = (JSONArray) jsonObject.get("targets"); // []
+    JSONObject object = (JSONObject) array.get(0); // {}
+    return (String) object.get("type");
+  }
+
+  private void setJsonTable(JSONObject obj, String target,
+      Pair<String, String> timeRange)
+      throws JSONException, StorageEngineException, QueryFilterOptimizationException,
+      MetadataException, IOException, StorageGroupException, SQLException, QueryProcessException, AuthException {
+    List<TimeValues> timeValues = restService.querySeries(target, timeRange);
+    JSONArray columns = new JSONArray();
+    JSONObject column = new JSONObject();
+    column.put("text", "Time");
+    column.put("type", "time");
+    columns.add(column);
+    column = new JSONObject();
+    column.put("text", "Number");
+    column.put("type", "number");
+    columns.add(column);
+    obj.put("columns", columns);
+    JSONArray values = new JSONArray();
+    for (TimeValues tv : timeValues) {
+      JSONArray value = new JSONArray();
+      value.add(tv.getTime());
+      value.add(tv.getValue());
+      values.add(value);
+    }
+    obj.put("values", values);
+  }
+
+  private void setJsonTimeseries(JSONObject obj, String target,
+      Pair<String, String> timeRange)
+      throws JSONException, StorageEngineException, QueryFilterOptimizationException,
+      MetadataException, IOException, StorageGroupException, SQLException, QueryProcessException, AuthException {
+    List<TimeValues> timeValues = restService.querySeries(target, timeRange);
+    logger.info("query size: {}", timeValues.size());
+    JSONArray dataPoints = new JSONArray();
+    for (TimeValues tv : timeValues) {
+      long time = tv.getTime();
+      String value = tv.getValue();
+      JSONArray jsonArray = new JSONArray();
+      jsonArray.add(value);
+      jsonArray.add(time);
+      dataPoints.add(jsonArray);
+    }
+    obj.put("datapoints", dataPoints);
+  }
+
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/TimeValues.java b/server/src/main/java/org/apache/iotdb/db/rest/model/TimeValues.java
similarity index 96%
rename from server/src/main/java/org/apache/iotdb/db/http/TimeValues.java
rename to server/src/main/java/org/apache/iotdb/db/rest/model/TimeValues.java
index 8c7059d..49290b0 100644
--- a/server/src/main/java/org/apache/iotdb/db/http/TimeValues.java
+++ b/server/src/main/java/org/apache/iotdb/db/rest/model/TimeValues.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.iotdb.db.http;
+package org.apache.iotdb.db.rest.model;
 
 public class TimeValues {
 
diff --git a/server/src/main/java/org/apache/iotdb/db/rest/service/RestService.java b/server/src/main/java/org/apache/iotdb/db/rest/service/RestService.java
new file mode 100644
index 0000000..3843555
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/rest/service/RestService.java
@@ -0,0 +1,177 @@
+/*
+ * 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.iotdb.db.rest.service;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.auth.AuthorityChecker;
+import org.apache.iotdb.db.conf.IoTDBConstant;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.path.PathException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.exception.runtime.SQLParserException;
+import org.apache.iotdb.db.exception.storageGroup.StorageGroupException;
+import org.apache.iotdb.db.metadata.MManager;
+import org.apache.iotdb.db.qp.QueryProcessor;
+import org.apache.iotdb.db.qp.constant.DatetimeUtils;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.qp.executor.QueryProcessExecutor;
+import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromOperator;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
+import org.apache.iotdb.db.query.context.QueryContext;
+import org.apache.iotdb.db.query.control.QueryResourceManager;
+import org.apache.iotdb.db.rest.model.TimeValues;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.read.common.Path;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RestService {
+
+  protected QueryProcessor processor = new QueryProcessor(new QueryProcessExecutor());
+  private static final Logger logger = LoggerFactory.getLogger(RestService.class);
+  private static final String INFO_NOT_LOGIN = "{}: Not login.";
+  private String username;
+
+
+  public List<TimeValues> querySeries(String s, Pair<String, String> timeRange)
+      throws QueryProcessException, StorageGroupException, AuthException, MetadataException, QueryFilterOptimizationException, SQLException, StorageEngineException, IOException {
+    String from = timeRange.left;
+    String to = timeRange.right;
+    String suffixPath = s.substring(s.lastIndexOf('.') + 1);
+    String prefixPath = s.substring(0, s.lastIndexOf('.'));
+    String sql = "SELECT " + suffixPath + " FROM root."
+        + prefixPath + " WHERE time > " + from + " and time < " + to;
+    logger.info(sql);
+    QueryOperator queryOperator = generateOperator(suffixPath, prefixPath, timeRange);
+    QueryPlan plan = (QueryPlan) processor.logicalPlanToPhysicalPlan(queryOperator);
+    List<Path> paths = plan.getPaths();
+    if (!checkLogin()) {
+      logger.info(INFO_NOT_LOGIN, IoTDBConstant.GLOBAL_DB_NAME);
+    }
+
+    // check seriesPath exists
+    if (paths.isEmpty()) {
+      throw new PathException("The path doesn't exist");
+    }
+
+    // check file level set
+    try {
+      checkFileLevelSet(paths);
+    } catch (StorageGroupException e) {
+      logger.error("meet error while checking file level.", e);
+      throw new StorageGroupException(e.getMessage());
+    }
+
+    // check permissions
+    if (!checkAuthorization(paths, plan)) {
+      throw new AuthException("Don't have permissions");
+    }
+
+    QueryContext context = new QueryContext(QueryResourceManager.getInstance().assignQueryId(true));
+    QueryDataSet queryDataSet = processor.getExecutor().processQuery(plan, context);
+    String[] args;
+    List<TimeValues> list = new ArrayList<>();
+    while(queryDataSet.hasNext()) {
+      TimeValues timeValues = new TimeValues();
+      args = queryDataSet.next().toString().split("\t");
+      timeValues.setTime(Long.parseLong(args[1]));
+      timeValues.setValue(args[0]);
+      list.add(timeValues);
+    }
+    return list;
+  }
+
+  private boolean checkLogin() {
+    return username != null;
+  }
+
+  private boolean checkAuthorization(List<Path> paths, PhysicalPlan plan) throws AuthException {
+    return AuthorityChecker.check(username, paths, plan.getOperatorType(), null);
+  }
+
+  private void checkFileLevelSet(List<Path> paths) throws StorageGroupException {
+    MManager.getInstance().checkFileLevel(paths);
+  }
+
+
+  /**
+   * generate select statement operator
+   */
+  private QueryOperator generateOperator(String suffixPath, String prefixPath, Pair<String, String> timeRange) {
+    FilterOperator binaryOp = new FilterOperator(SQLConstant.KW_AND);
+    binaryOp.addChildOperator(
+        new BasicFunctionOperator(SQLConstant.GREATERTHAN,
+            new Path(SQLConstant.RESERVED_TIME),
+            String.valueOf(parseTimeFormat(timeRange.left))
+        )
+    );
+    binaryOp.addChildOperator(
+        new BasicFunctionOperator(SQLConstant.LESSTHAN,
+            new Path(SQLConstant.RESERVED_TIME),
+            String.valueOf(parseTimeFormat(timeRange.right))
+        )
+    );
+    QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
+    SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
+    selectOp.addSelectPath(new Path(suffixPath));
+    FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
+    fromOp.addPrefixTablePath(new Path(prefixPath));
+    queryOp.setFilterOperator(binaryOp);
+    queryOp.setSelectOperator(selectOp);
+    queryOp.setFromOperator(fromOp);
+    return queryOp;
+  }
+
+  /**
+   * function for parsing time format.
+   */
+  private long parseTimeFormat(String timestampStr) throws SQLParserException {
+    if (timestampStr == null || timestampStr.trim().equals("")) {
+      throw new SQLParserException("input timestamp cannot be empty");
+    }
+    if (timestampStr.equalsIgnoreCase(SQLConstant.NOW_FUNC)) {
+      return System.currentTimeMillis();
+    }
+    try {
+      return DatetimeUtils.convertDatetimeStrToLong(timestampStr, IoTDBDescriptor.getInstance().getConfig().getZoneID());
+    } catch (Exception e) {
+      throw new SQLParserException(String
+          .format("Input time format %s error. "
+              + "Input like yyyy-MM-dd HH:mm:ss, yyyy-MM-ddTHH:mm:ss or "
+              + "refer to user document for more info.", timestampStr));
+    }
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/QueryServlet.java b/server/src/main/java/org/apache/iotdb/db/rest/util/RestUtil.java
similarity index 52%
rename from server/src/main/java/org/apache/iotdb/db/http/QueryServlet.java
rename to server/src/main/java/org/apache/iotdb/db/rest/util/RestUtil.java
index d042663..5c0b4aa 100644
--- a/server/src/main/java/org/apache/iotdb/db/http/QueryServlet.java
+++ b/server/src/main/java/org/apache/iotdb/db/rest/util/RestUtil.java
@@ -16,29 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.db.http;
+package org.apache.iotdb.db.rest.util;
 
-import java.io.IOException;
-import java.io.PrintWriter;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.glassfish.jersey.servlet.ServletContainer;
 
-public class QueryServlet extends HttpServlet {
+public class RestUtil {
+  public static ServletContextHandler getRestContextHandler() {
+    ServletContextHandler ctx =
+        new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
 
-  @Override
-  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
-      throws ServletException, IOException {
-    PrintWriter out = resp.getWriter();
-    resp.setContentType("application/json");
-    resp.setCharacterEncoding("UTF-8");
-
-  }
-
-  @Override
-  protected void doPost(HttpServletRequest req, HttpServletResponse resp)
-      throws ServletException, IOException {
-    super.doPost(req, resp);
+    ctx.setContextPath("/rest");
+    ServletHolder serHol = ctx.addServlet(ServletContainer.class, "/*");
+    serHol.setInitParameter("jersey.config.server.provider.packages",
+        "org.apache.iotdb.db.rest.controller");
+    serHol.setInitOrder(1);
+    return ctx;
   }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/service/MetricsService.java b/server/src/main/java/org/apache/iotdb/db/service/MetricsService.java
index e2b6e22..cc8d544 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/MetricsService.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/MetricsService.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketAddress;
+import java.util.Arrays;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -30,9 +31,11 @@ import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.exception.StartupException;
+import org.apache.iotdb.db.metrics.server.JettyUtil;
 import org.apache.iotdb.db.metrics.server.MetricsSystem;
 import org.apache.iotdb.db.metrics.server.ServerArgument;
 import org.apache.iotdb.db.metrics.ui.MetricsWebUI;
+import org.apache.iotdb.db.rest.util.RestUtil;
 import org.eclipse.jetty.server.Server;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -85,9 +88,9 @@ public class MetricsService implements MetricsServiceMBean, IService {
     int port = getMetricsPort();
     MetricsSystem metricsSystem = new MetricsSystem(new ServerArgument(port));
     MetricsWebUI metricsWebUI = new MetricsWebUI(metricsSystem.getMetricRegistry());
-    metricsWebUI.getHandlers().add(metricsSystem.getServletHandlers());
+    metricsWebUI.getHandler().addServlet(metricsSystem.getServletHolder(), "/json");
     metricsWebUI.initialize();
-    server = metricsWebUI.getServer(port);
+    server = JettyUtil.getJettyServer(Arrays.asList(metricsWebUI.getHandler(), RestUtil.getRestContextHandler()), 8181);
     metricsSystem.start();
     try {
       executorService.execute(new MetricsServiceThread(server));
diff --git a/server/src/main/resources/iotdb/ui/static/index.html b/server/src/main/resources/iotdb/ui/static/index.html
index 68e7881..6b85ced 100644
--- a/server/src/main/resources/iotdb/ui/static/index.html
+++ b/server/src/main/resources/iotdb/ui/static/index.html
@@ -18,7 +18,7 @@ limitations under the License.
 <html>
 <head>
 <meta http-equiv="Content-type" content="text/html; charset=utf-8">
-<link rel="stylesheet" href="/static/webui.css" type="text/css">
+<link rel="stylesheet" href="webui.css" type="text/css">
 <title>IotDB Metrics Server</title>
 </head>
 <body>
@@ -27,7 +27,7 @@ limitations under the License.
             <div class="brand">
                 <h3 style="vertical-align: middle; display: inline-block;">
                     <a href="" style="text-decoration: none">
-                        <img src="/static/iotdb-logo.png">
+                        <img src="iotdb-logo.png">
                         <span class="version" style="margin-right: 15px;">{version}</span>
                     </a>
                     IOTDB Metrics Server