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