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/09/09 12:29:21 UTC
[incubator-iotdb] branch http_v2 created (now 527d6b9)
This is an automated email from the ASF dual-hosted git repository.
geniuspig pushed a change to branch http_v2
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git.
at 527d6b9 basic structure
This branch includes the following new commits:
new 527d6b9 basic structure
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[incubator-iotdb] 01/01: basic structure
Posted by ge...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
geniuspig pushed a commit to branch http_v2
in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git
commit 527d6b99a2ce7f336b2bc8bfe81f283bfb644155
Author: zhutianci <zh...@gmail.com>
AuthorDate: Wed Sep 9 20:28:48 2020 +0800
basic structure
---
.../org/apache/iotdb/db/concurrent/ThreadName.java | 1 +
.../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 23 ++
.../iotdb/db/exception/UnsupportedHttpMethod.java | 10 +
.../iotdb/db/http/constant/HttpConstant.java | 60 +++++
.../org/apache/iotdb/db/http/core/HttpServer.java | 64 +++++
.../iotdb/db/http/core/HttpSnoopServerHandler.java | 87 +++++++
.../db/http/core/HttpSnoopServerInitializer.java | 32 +++
.../org/apache/iotdb/db/http/handler/Handler.java | 39 ++++
.../iotdb/db/http/handler/InsertHandler.java | 66 ++++++
.../apache/iotdb/db/http/handler/QueryHandler.java | 72 ++++++
.../db/http/handler/StorageGroupsHandlers.java | 100 ++++++++
.../iotdb/db/http/handler/TimeSeriesHandler.java | 145 ++++++++++++
.../apache/iotdb/db/http/handler/UsersHandler.java | 46 ++++
.../apache/iotdb/db/http/parser/QueryParser.java | 90 +++++++
.../org/apache/iotdb/db/http/router/Router.java | 100 ++++++++
.../org/apache/iotdb/db/http/utils/URIUtils.java | 17 ++
.../java/org/apache/iotdb/db/metadata/MTree.java | 2 +-
.../main/java/org/apache/iotdb/db/qp/Planner.java | 5 +
.../org/apache/iotdb/db/service/HTTPService.java | 199 ++++++++++++++++
.../apache/iotdb/db/service/HTTPServiceMBean.java | 28 +++
.../java/org/apache/iotdb/db/service/IoTDB.java | 3 +
.../org/apache/iotdb/db/service/ServiceType.java | 1 +
.../db/engine/modification/DeletionQueryTest.java | 3 +-
.../org/apache/iotdb/db/http/HttpHandlerTest.java | 5 +
.../org/apache/iotdb/db/http/HttpRouterTest.java | 259 +++++++++++++++++++++
25 files changed, 1455 insertions(+), 2 deletions(-)
diff --git a/server/src/main/java/org/apache/iotdb/db/concurrent/ThreadName.java b/server/src/main/java/org/apache/iotdb/db/concurrent/ThreadName.java
index 6a0a81e..ea97077 100644
--- a/server/src/main/java/org/apache/iotdb/db/concurrent/ThreadName.java
+++ b/server/src/main/java/org/apache/iotdb/db/concurrent/ThreadName.java
@@ -19,6 +19,7 @@
package org.apache.iotdb.db.concurrent;
public enum ThreadName {
+ HTTP_SERVICE("HTTPServiceImpl"),
METRICS_SERVICE("Metrics-ServerServiceImpl"),
RPC_SERVICE("RPC-ServerServiceImpl"),
RPC_CLIENT("RPC-Client"),
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 0be9d3d..68afdd3 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -72,6 +72,13 @@ public class IoTDBConfig {
private boolean enableMetricService = false;
/**
+ * Port which the http service listens to
+ */
+ private int httpPort = 8282;
+
+ private boolean enableHTTPService = false;
+
+ /**
* whether to enable the mqtt service.
*/
private boolean enableMQTTService = false;
@@ -805,6 +812,22 @@ public class IoTDBConfig {
return enableMetricService;
}
+ public int getHTTPPort() {
+ return httpPort;
+ }
+
+ public void setHTTPPort(int httpPort) {
+ this.httpPort = httpPort;
+ }
+
+ public boolean isEnableHTTPService() {
+ return enableHTTPService;
+ }
+
+ public void setEnableHTTPService(boolean enableHTTPService) {
+ this.enableHTTPService = enableHTTPService;
+ }
+
public void setEnableMetricService(boolean enableMetricService) {
this.enableMetricService = enableMetricService;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/exception/UnsupportedHttpMethod.java b/server/src/main/java/org/apache/iotdb/db/exception/UnsupportedHttpMethod.java
new file mode 100644
index 0000000..cdf34c0
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/exception/UnsupportedHttpMethod.java
@@ -0,0 +1,10 @@
+package org.apache.iotdb.db.exception;
+
+public class UnsupportedHttpMethod extends Exception {
+
+ private static final long serialVersionUID = 8484450962351247739L;
+
+ public UnsupportedHttpMethod(String message) {
+ super(message);
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/constant/HttpConstant.java b/server/src/main/java/org/apache/iotdb/db/http/constant/HttpConstant.java
new file mode 100644
index 0000000..0ee235b
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/constant/HttpConstant.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.http.constant;
+
+public class HttpConstant {
+
+ //router
+ public static final String STORAGE_GROUPS = "/storageGroups";
+ public static final String TIME_SERIES = "/timeSeries";
+ public static final String USER_LOGIN = "/user/login";
+ public static final String USER_LOGOUT = "/user/logout";
+ public static final String QUERY = "/query";
+ public static final String INSERT = "/insert";
+
+ public static final char QUESTION_MARK = '?';
+ public static final String USERNAME = "username";
+ public static final String PASSWORD = "password";
+ public static final String SUCCESSFUL_OPERATION = "successful operation";
+ public static final String RESULT = "result";
+ public static final String STORAGE_GROUP = "storage group";
+ public static final String TTL = "TTL";
+ public static final String TIME_SERIES_JSON = "timeSeries";
+ public static final String ALIAS = "alias";
+ public static final String DATATYPE = "dataType";
+ public static final String ENCODING = "encoding";
+ public static final String COMPRESSION = "compression";
+ public static final String KEY = "key";
+ public static final String VALUE = "value";
+ public static final String PROPERTIES = "properties";
+ public static final String TAGS = "tags";
+ public static final String ATTRIBUTES = "attributes";
+ public static final String NULL = "null";
+
+ public static final String DEVICE_ID = "deviceId";
+ public static final String MEASUREMENTS = "measurements";
+ public static final String TIMESTAMPS = "timestamps";
+ public static final String VALUES = "values";
+ public static final String RANGE = "range";
+ public static final String FROM = "from";
+ public static final String SELECT = "select";
+ public static final String START = "start";
+ public static final String END = "end";
+ public static final String ERROR = "error";
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/core/HttpServer.java b/server/src/main/java/org/apache/iotdb/db/http/core/HttpServer.java
new file mode 100644
index 0000000..79be2d2
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/core/HttpServer.java
@@ -0,0 +1,64 @@
+package org.apache.iotdb.db.http.core;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.logging.LogLevel;
+import io.netty.handler.logging.LoggingHandler;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.SelfSignedCertificate;
+
+public class HttpServer {
+
+ private static final boolean SSL = System.getProperty("ssl") != null;
+ private final int port;
+ private ServerBootstrap b;
+
+
+ public HttpServer(int port){
+ this.port = port;
+ b = new ServerBootstrap();
+ }
+
+ public void start() throws Exception{
+ // Configure SSL.
+ final SslContext sslCtx;
+ if (SSL) {
+ SelfSignedCertificate ssc = new SelfSignedCertificate();
+ sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
+ } else {
+ sslCtx = null;
+ }
+
+ // Configure the server.
+ EventLoopGroup bossGroup = new NioEventLoopGroup(1);
+ EventLoopGroup workerGroup = new NioEventLoopGroup();
+ try {
+ b.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .handler(new LoggingHandler(LogLevel.INFO))
+ .childHandler(new HttpSnoopServerInitializer(sslCtx));
+
+ Channel ch = b.bind(port).sync().channel();
+
+ System.err.println("Open your web browser and navigate to " +
+ (SSL? "https" : "http") + "://127.0.0.1:" + port + '/');
+
+ ch.closeFuture().sync();
+ } finally {
+ bossGroup.shutdownGracefully();
+ workerGroup.shutdownGracefully();
+ }
+ }
+
+ public void stop() throws InterruptedException {
+ ChannelFuture f = b.bind().sync();
+// Call this once you want to stop accepting new connections.
+ f.channel().close().sync();
+ }
+
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerHandler.java b/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerHandler.java
new file mode 100644
index 0000000..6a96b89
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerHandler.java
@@ -0,0 +1,87 @@
+package org.apache.iotdb.db.http.core;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.DefaultFullHttpResponse;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.HttpHeaderNames;
+import io.netty.handler.codec.http.HttpHeaderValues;
+import io.netty.handler.codec.http.HttpObject;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponseStatus;
+import io.netty.handler.codec.http.HttpUtil;
+import io.netty.util.CharsetUtil;
+import org.apache.iotdb.db.http.constant.HttpConstant;
+import org.apache.iotdb.db.http.router.Router;
+
+public class HttpSnoopServerHandler extends SimpleChannelInboundHandler<Object> {
+
+ private FullHttpRequest request;
+
+ private Router router = new Router();
+
+ @Override
+ public void channelReadComplete(ChannelHandlerContext ctx) {
+ ctx.flush();
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
+ HttpResponseStatus status;
+ if (msg instanceof HttpRequest) {
+ FullHttpRequest request = this.request = (FullHttpRequest) msg;
+ JSON result;
+ try {
+ result = router.route(request.method(), request.uri(),
+ JSON.parseObject(request.content().toString(CharsetUtil.UTF_8)));
+ status = OK;
+ } catch (Exception e) {
+ result = new JSONObject();
+ ((JSONObject) result).put(HttpConstant.ERROR, e.getMessage());
+ status = INTERNAL_SERVER_ERROR;
+ }
+
+ writeResponse(request, ctx, result, status);
+ }
+ }
+
+ private void writeResponse(HttpObject currentObj, ChannelHandlerContext ctx, JSON json, HttpResponseStatus status) {
+
+ // Decide whether to close the connection or not.
+ boolean keepAlive = HttpUtil.isKeepAlive(request);
+ // Build the response object.
+ FullHttpResponse response = new DefaultFullHttpResponse(
+ HTTP_1_1, status,
+ Unpooled.copiedBuffer(json.toString(), CharsetUtil.UTF_8));
+
+ response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
+
+
+
+ if (keepAlive) {
+ // Add 'Content-Length' header only for a keep-alive connection.
+ response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
+ // Add keep alive header as per:
+ // - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
+ response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
+ }
+
+ // Write the response.
+ ctx.write(response);
+
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+ cause.printStackTrace();
+ ctx.close();
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerInitializer.java b/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerInitializer.java
new file mode 100644
index 0000000..78a8da0
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/core/HttpSnoopServerInitializer.java
@@ -0,0 +1,32 @@
+package org.apache.iotdb.db.http.core;
+
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpContentCompressor;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import io.netty.handler.ssl.SslContext;
+
+public class HttpSnoopServerInitializer extends ChannelInitializer<SocketChannel> {
+
+ private final SslContext sslCtx;
+
+ HttpSnoopServerInitializer(SslContext sslCtx) {
+ this.sslCtx = sslCtx;
+ }
+
+ @Override
+ public void initChannel(SocketChannel ch) {
+ ChannelPipeline p = ch.pipeline();
+ if (sslCtx != null) {
+ p.addLast(sslCtx.newHandler(ch.alloc()));
+ }
+ p.addLast(new HttpRequestDecoder());
+ p.addLast(new HttpObjectAggregator(1048576));
+ p.addLast(new HttpResponseEncoder());
+ p.addLast(new HttpContentCompressor());
+ p.addLast(new HttpSnoopServerHandler());
+ }
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/Handler.java b/server/src/main/java/org/apache/iotdb/db/http/handler/Handler.java
new file mode 100644
index 0000000..e45d0a1
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/Handler.java
@@ -0,0 +1,39 @@
+package org.apache.iotdb.db.http.handler;
+
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.qp.Planner;
+import org.apache.iotdb.db.qp.executor.IPlanExecutor;
+import org.apache.iotdb.db.qp.executor.PlanExecutor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class Handler {
+ protected static final Logger logger = LoggerFactory.getLogger(Handler.class);
+ protected static String username;
+ protected IPlanExecutor executor;
+ protected Planner processor;
+
+ Handler() {
+ try {
+ processor = new Planner();
+ executor = new PlanExecutor();
+ } catch (QueryProcessException e) {
+ logger.error(e.getMessage());
+ }
+ }
+
+ /**
+ * Check whether current user has logged in.
+ *
+ */
+ void checkLogin() throws AuthException{
+ if(username == null) {
+ throw new AuthException("didn't log in iotdb");
+ }
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/InsertHandler.java b/server/src/main/java/org/apache/iotdb/db/http/handler/InsertHandler.java
new file mode 100644
index 0000000..c1b55c7
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/InsertHandler.java
@@ -0,0 +1,66 @@
+package org.apache.iotdb.db.http.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.http.constant.HttpConstant;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+public class InsertHandler extends Handler{
+ public JSON handle(JSON json)
+ throws IllegalPathException, QueryProcessException,
+ StorageEngineException, StorageGroupNotSetException, AuthException {
+ checkLogin();
+ JSONArray array = (JSONArray) json;
+ for (Object o : array) {
+ JSONObject object = (JSONObject) o;
+ String deviceID = (String) object.get(HttpConstant.DEVICE_ID);
+ JSONArray measurements = (JSONArray) object.get(HttpConstant.MEASUREMENTS);
+ JSONArray timestamps = (JSONArray) object.get(HttpConstant.TIMESTAMPS);
+ JSONArray values = (JSONArray) object.get(HttpConstant.VALUES);
+ for(int i = 0; i < timestamps.size(); i++){
+ if (!insert(deviceID, (Integer) timestamps.get(i), getListString(measurements), (JSONArray)values.get(i))) {
+ throw new QueryProcessException(String.format("%s can't be inserted successfully", deviceID));
+ }
+ }
+ }
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return jsonObject;
+ }
+
+ public boolean insert(String deviceId, long time, List<String> measurements,
+ List<Object> values)
+ throws IllegalPathException, QueryProcessException, StorageEngineException, StorageGroupNotSetException {
+ InsertRowPlan plan = new InsertRowPlan();
+ plan.setDeviceId(new PartialPath(deviceId));
+ plan.setTime(time);
+ plan.setMeasurements(measurements.toArray(new String[0]));
+ plan.setDataTypes(new TSDataType[plan.getMeasurements().length]);
+ plan.setNeedInferType(true);
+ plan.setValues(values.toArray(new Object[0]));
+ return executor.processNonQuery(plan);
+ }
+
+ /**
+ * transform JsonArray to List<String>
+ */
+ private List<String> getListString(JSONArray jsonArray) {
+ List<String> list = new ArrayList<>();
+ for (Object o : jsonArray) {
+ list.add((String) o);
+ }
+ return list;
+ }
+
+
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/QueryHandler.java b/server/src/main/java/org/apache/iotdb/db/http/handler/QueryHandler.java
new file mode 100644
index 0000000..f4b0cd1
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/QueryHandler.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.http.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import java.io.IOException;
+import java.sql.SQLException;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.auth.AuthorityChecker;
+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.http.constant.HttpConstant;
+import org.apache.iotdb.db.http.parser.QueryParser;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+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.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.thrift.TException;
+
+public class QueryHandler extends Handler{
+ public JSON handle(JSON json)
+ throws QueryProcessException, MetadataException, AuthException,
+ TException, StorageEngineException, QueryFilterOptimizationException,
+ IOException, InterruptedException, SQLException {
+ checkLogin();
+ JSONObject jsonObject = (JSONObject) json;
+ JSONObject range = (JSONObject) jsonObject.get(HttpConstant.RANGE);
+ String prefixPath = (String) jsonObject.get(HttpConstant.FROM);
+ String suffixPath = (String) jsonObject.get(HttpConstant.SELECT);
+ Pair<String, String> timeRange = new Pair<>((String)range.get(HttpConstant.START), (String)range.get(HttpConstant.END));
+ QueryOperator queryOperator = QueryParser.generateOperator(suffixPath, prefixPath, timeRange);
+ QueryPlan plan = (QueryPlan) processor.logicalPlanToPhysicalPlan(queryOperator);
+ if(AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be queried by %s", prefixPath + TsFileConstant.PATH_SEPARATOR
+ + suffixPath, username));
+ }
+ JSONArray result = new JSONArray();
+ QueryDataSet dataSet = executor.processQuery(plan, new QueryContext(QueryResourceManager.getInstance().assignQueryId(true)));
+ while(dataSet.hasNext()) {
+ JSONArray row = new JSONArray();
+ for(Field field : dataSet.next().getFields()) {
+ row.add(field.getStringValue());
+ }
+ result.add(row);
+ }
+ return result;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/StorageGroupsHandlers.java b/server/src/main/java/org/apache/iotdb/db/http/handler/StorageGroupsHandlers.java
new file mode 100644
index 0000000..2468ffe
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/StorageGroupsHandlers.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.iotdb.db.http.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import io.netty.handler.codec.http.HttpMethod;
+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.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.UnsupportedHttpMethod;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.http.constant.HttpConstant;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.metadata.mnode.StorageGroupMNode;
+import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
+import org.apache.iotdb.db.qp.physical.sys.SetStorageGroupPlan;
+import org.apache.iotdb.db.service.IoTDB;
+
+public class StorageGroupsHandlers extends Handler {
+
+ public JSON handle(HttpMethod httpMethod, JSON json)
+ throws QueryProcessException, StorageEngineException
+ , StorageGroupNotSetException, AuthException
+ , IllegalPathException, UnsupportedHttpMethod {
+ checkLogin();
+ if (HttpMethod.GET.equals(httpMethod)) {
+ List<StorageGroupMNode> storageGroupMNodes = IoTDB.metaManager.getAllStorageGroupNodes();
+ JSONArray result = new JSONArray();
+ for (StorageGroupMNode storageGroupMNode : storageGroupMNodes) {
+ if (storageGroupMNode.getDataTTL() > 0 && storageGroupMNode.getDataTTL() < Long.MAX_VALUE) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.STORAGE_GROUP, storageGroupMNode.getFullPath());
+ jsonObject.put(HttpConstant.TTL, storageGroupMNode.getDataTTL());
+ result.add(jsonObject);
+ } else {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.STORAGE_GROUP, storageGroupMNode.getFullPath());
+ result.add(jsonObject);
+ }
+ }
+ return result;
+ } else if (HttpMethod.POST.equals(httpMethod)) {
+ JSONArray jsonArray = (JSONArray) json;
+ for(Object object : jsonArray) {
+ String storageGroup = (String) object;
+ SetStorageGroupPlan plan = new SetStorageGroupPlan(new PartialPath(storageGroup));
+ if(!AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be set by %s", storageGroup, username));
+ }
+ if(!executor.processNonQuery(plan)) {
+ throw new QueryProcessException(String.format("%s can't be set successfully", storageGroup));
+ }
+ }
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return jsonObject;
+ } else if(HttpMethod.DELETE.equals(httpMethod)) {
+ JSONArray jsonArray = (JSONArray) json;
+ List<PartialPath> storageGroups = new ArrayList<>();
+ for(Object object : jsonArray) {
+ String storageGroup = (String) object;
+ storageGroups.add(new PartialPath(storageGroup));
+ }
+ DeleteStorageGroupPlan plan = new DeleteStorageGroupPlan(storageGroups);
+ if(!AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be delete by %s", storageGroups, username));
+ }
+ if(!executor.processNonQuery(plan)) {
+ throw new QueryProcessException(String.format("%s can't be deleted successfully", storageGroups));
+ }
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return jsonObject;
+ } else {
+ throw new UnsupportedHttpMethod(httpMethod.toString());
+ }
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/TimeSeriesHandler.java b/server/src/main/java/org/apache/iotdb/db/http/handler/TimeSeriesHandler.java
new file mode 100644
index 0000000..4d008c4
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/TimeSeriesHandler.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.http.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import io.netty.handler.codec.http.HttpMethod;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.auth.AuthorityChecker;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.UnsupportedHttpMethod;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.http.constant.HttpConstant;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
+import org.apache.iotdb.db.query.context.QueryContext;
+import org.apache.iotdb.db.query.control.QueryResourceManager;
+import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.thrift.TException;
+
+public class TimeSeriesHandler extends Handler {
+ public JSON handle(HttpMethod httpMethod, JSON json)
+ throws AuthException, MetadataException, QueryProcessException,
+ StorageEngineException, TException, InterruptedException, QueryFilterOptimizationException, IOException, SQLException, UnsupportedHttpMethod {
+ checkLogin();
+ if (HttpMethod.POST.equals(httpMethod)) {
+ JSONArray jsonArray = (JSONArray) json;
+ for(Object object : jsonArray) {
+ JSONObject jsonObject = (JSONObject) object;
+ String path = (String) jsonObject.get(HttpConstant.TIME_SERIES_JSON);
+ String dataType = (String) jsonObject.get(HttpConstant.DATATYPE);
+ String encoding = (String) jsonObject.get(HttpConstant.ENCODING);
+ String alias = (String) jsonObject.get(HttpConstant.ALIAS);
+ String compression = (String) jsonObject.get(HttpConstant.COMPRESSION);
+ JSONArray properties = (JSONArray) jsonObject.get(HttpConstant.PROPERTIES);
+ JSONArray tags = (JSONArray) jsonObject.get(HttpConstant.TAGS);
+ JSONArray attributes = (JSONArray) jsonObject.get(HttpConstant.ATTRIBUTES);
+ CreateTimeSeriesPlan plan = new CreateTimeSeriesPlan(new PartialPath(path),
+ TSDataType.valueOf(dataType.toUpperCase()), TSEncoding.valueOf(encoding.toUpperCase()),
+ compression == null? TSFileDescriptor.getInstance().getConfig().getCompressor() : CompressionType.valueOf(compression.toUpperCase()),
+ jsonArrayToMap(properties), jsonArrayToMap(tags), jsonArrayToMap(attributes), alias);
+ if(!AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be created by %s", path, username));
+ }
+ if(!executor.processNonQuery(plan)) {
+ throw new QueryProcessException(String.format("%s can't be created successfully", path));
+ }
+ }
+ JSONObject result = new JSONObject();
+ result.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return result;
+ } else if(HttpMethod.GET.equals(httpMethod)) {
+ JSONArray jsonArray = (JSONArray) json;
+ JSONArray result = new JSONArray();
+ for(Object object : jsonArray) {
+ String path = (String) object;
+ ShowTimeSeriesPlan plan = new ShowTimeSeriesPlan(new PartialPath(path));
+ plan.setHasLimit(true);
+ if(!AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be gotten by %s", path, username));
+ }
+ long queryID = QueryResourceManager.getInstance().assignQueryId(false);
+ QueryDataSet dataSet = executor.processQuery(plan, new QueryContext(queryID));
+ while(dataSet.hasNext()) {
+ JSONArray row = new JSONArray();
+ RowRecord rowRecord = dataSet.next();
+ List<Field> fields = rowRecord.getFields();
+ for(Field field : fields) {
+ if(field != null) {
+ row.add(field.getStringValue());
+ } else {
+ row.add(HttpConstant.NULL);
+ }
+ }
+ result.add(row);
+ }
+ }
+ return result;
+ } else if(HttpMethod.DELETE.equals(httpMethod)) {
+ JSONArray jsonArray = (JSONArray) json;
+ List<PartialPath> timeSeries = new ArrayList<>();
+ for(Object object : jsonArray) {
+ String storageGroup = (String) object;
+ timeSeries.add(new PartialPath(storageGroup));
+ }
+ DeleteTimeSeriesPlan plan = new DeleteTimeSeriesPlan(timeSeries);
+ if(!AuthorityChecker.check(username, plan.getPaths(), plan.getOperatorType(), null)) {
+ throw new AuthException(String.format("%s can't be delete by %s", timeSeries, username));
+ }
+ if(!executor.processNonQuery(plan)) {
+ throw new QueryProcessException(String.format("%s can't be created successfully", timeSeries));
+ }
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return jsonObject;
+ }else {
+ throw new UnsupportedHttpMethod(httpMethod.toString());
+ }
+ }
+
+ private Map<String, String> jsonArrayToMap(JSONArray array) {
+ if(array == null) {
+ return null;
+ }
+ Map<String, String> map = new HashMap<>();
+ for(Object object : array) {
+ JSONObject json = (JSONObject) object;
+ map.put((String)json.get(HttpConstant.KEY), (String)json.get(HttpConstant.VALUE));
+ }
+ return map;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/handler/UsersHandler.java b/server/src/main/java/org/apache/iotdb/db/http/handler/UsersHandler.java
new file mode 100644
index 0000000..91a5974
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/handler/UsersHandler.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.iotdb.db.http.handler;
+
+import java.util.List;
+import java.util.Map;
+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.http.constant.HttpConstant;
+
+public class UsersHandler extends Handler{
+
+ public boolean userLogin(Map<String, List<String>> p) throws AuthException {
+ List<String> usernameList = p.get(HttpConstant.USERNAME);
+ List<String> passwordList = p.get(HttpConstant.PASSWORD);
+ IAuthorizer authorizer = LocalFileAuthorizer.getInstance();
+ username = usernameList.get(0);
+ return authorizer.login(usernameList.get(0), passwordList.get(0));
+ }
+
+ public boolean userLogout(Map<String, List<String>> p) throws AuthException {
+ List<String> usernameList = p.get(HttpConstant.USERNAME);
+ if(!usernameList.get(0).equals(username)) {
+ throw new AuthException("wrong username");
+ }
+ username = null;
+ return true;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/parser/QueryParser.java b/server/src/main/java/org/apache/iotdb/db/http/parser/QueryParser.java
new file mode 100644
index 0000000..97b9ad6
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/parser/QueryParser.java
@@ -0,0 +1,90 @@
+package org.apache.iotdb.db.http.parser;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.exception.runtime.SQLParserException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.constant.DatetimeUtils;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+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.tsfile.utils.Pair;
+
+public class QueryParser {
+ /**
+ * generate select statement operator
+ */
+ public static QueryOperator generateOperator(String suffixPath, String prefixPath,
+ Pair<String, String> timeRange) throws IllegalPathException {
+ FilterOperator binaryOp = new FilterOperator(SQLConstant.KW_AND);
+ long timeLeft;
+ long timeRight;
+ if(!NumberUtils.isDigits(timeRange.left)) {
+ timeLeft = parseTimeFormat(timeRange.left);
+ binaryOp.addChildOperator(
+ new BasicFunctionOperator(SQLConstant.GREATERTHAN,
+ new PartialPath(SQLConstant.RESERVED_TIME, false),
+ String.valueOf(timeLeft)
+ )
+ );
+ } else {
+ binaryOp.addChildOperator(
+ new BasicFunctionOperator(SQLConstant.GREATERTHAN,
+ new PartialPath(SQLConstant.RESERVED_TIME, false),
+ timeRange.left
+ )
+ );
+ }
+
+ if(!NumberUtils.isDigits(timeRange.right)) {
+ timeRight = parseTimeFormat(timeRange.right);
+ binaryOp.addChildOperator(
+ new BasicFunctionOperator(SQLConstant.LESSTHAN,
+ new PartialPath(SQLConstant.RESERVED_TIME, false),
+ String.valueOf(timeRight)
+ )
+ );
+ } else {
+ binaryOp.addChildOperator(
+ new BasicFunctionOperator(SQLConstant.LESSTHAN,
+ new PartialPath(SQLConstant.RESERVED_TIME, false),
+ timeRange.right
+ )
+ );
+ }
+ QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
+ SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT);
+ selectOp.addSelectPath(new PartialPath(suffixPath));
+ FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
+ fromOp.addPrefixTablePath(new PartialPath(prefixPath));
+ queryOp.setFilterOperator(binaryOp);
+ queryOp.setSelectOperator(selectOp);
+ queryOp.setFromOperator(fromOp);
+ return queryOp;
+ }
+
+ /**
+ * function for parsing time format.
+ */
+ private static long parseTimeFormat(String timestampStr) {
+ 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));
+ }
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/http/router/Router.java b/server/src/main/java/org/apache/iotdb/db/http/router/Router.java
new file mode 100644
index 0000000..e7c5c49
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/router/Router.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.iotdb.db.http.router;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import io.netty.handler.codec.http.HttpMethod;
+import io.netty.handler.codec.http.QueryStringDecoder;
+import java.io.IOException;
+import java.sql.SQLException;
+import org.apache.iotdb.db.auth.AuthException;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.UnsupportedHttpMethod;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.http.constant.HttpConstant;
+import org.apache.iotdb.db.http.handler.InsertHandler;
+import org.apache.iotdb.db.http.handler.QueryHandler;
+import org.apache.iotdb.db.http.handler.StorageGroupsHandlers;
+import org.apache.iotdb.db.http.handler.TimeSeriesHandler;
+import org.apache.iotdb.db.http.handler.UsersHandler;
+import org.apache.iotdb.db.http.utils.URIUtils;
+import org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
+import org.apache.thrift.TException;
+
+/**
+ * Router that contains information about both route matching and return json.
+ */
+public class Router {
+
+ /**
+ * matching url and return JSON
+ * @param method http method
+ * @param uri uri will be matched
+ * @param json request JSON Object
+ * @return JSON object, may be a JSONArray or JSONObject
+ */
+ public JSON route(HttpMethod method, String uri, JSON json)
+ throws AuthException, MetadataException, QueryProcessException
+ , StorageEngineException, UnsupportedHttpMethod, SQLException, InterruptedException, QueryFilterOptimizationException, IOException, TException {
+ QueryStringDecoder decoder = new QueryStringDecoder(uri);
+ uri = URIUtils.removeParameter(uri);
+ UsersHandler usersHandler;
+ switch (uri) {
+ case HttpConstant.STORAGE_GROUPS:
+ StorageGroupsHandlers storageGroupsHandlers = new StorageGroupsHandlers();
+ return storageGroupsHandlers.handle(method, json);
+ case HttpConstant.TIME_SERIES:
+ TimeSeriesHandler timeSeriesHandler = new TimeSeriesHandler();
+ return timeSeriesHandler.handle(method, json);
+ case HttpConstant.USER_LOGIN:
+ usersHandler = new UsersHandler();
+ if (usersHandler.userLogin(decoder.parameters())) {
+ JSONObject result = new JSONObject();
+ result.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return result;
+ } else {
+ throw new AuthException(String.format("%s can't log in", usersHandler.getUsername()));
+ }
+ case HttpConstant.USER_LOGOUT:
+ usersHandler = new UsersHandler();
+ if (usersHandler.userLogout(decoder.parameters())) {
+ JSONObject result = new JSONObject();
+ result.put(HttpConstant.RESULT, HttpConstant.SUCCESSFUL_OPERATION);
+ return result;
+ } else {
+ throw new AuthException(String.format("%s can't log out", usersHandler.getUsername()));
+ }
+ case HttpConstant.QUERY:
+ QueryHandler queryHandler = new QueryHandler();
+ return queryHandler.handle(json);
+ case HttpConstant.INSERT:
+ InsertHandler insertHandler = new InsertHandler();
+ return insertHandler.handle(json);
+ case "":
+ JSONObject result = new JSONObject();
+ result.put(HttpConstant.RESULT, "Hello, IoTDB");
+ return result;
+ default:
+ throw new UnsupportedHttpMethod(String.format("%s can't be found" , uri));
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/iotdb/db/http/utils/URIUtils.java b/server/src/main/java/org/apache/iotdb/db/http/utils/URIUtils.java
new file mode 100644
index 0000000..8dd38e7
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/http/utils/URIUtils.java
@@ -0,0 +1,17 @@
+package org.apache.iotdb.db.http.utils;
+
+import org.apache.iotdb.db.http.constant.HttpConstant;
+
+public class URIUtils {
+ public static String removeParameter(String uri) {
+ int index = uri.indexOf(HttpConstant.QUESTION_MARK);
+ if(index < 0) {
+ if(uri.charAt(uri.length() - 1) == '/') {
+ return uri.substring(0, uri.length() - 1);
+ }
+ } else {
+ return uri.substring(0, index);
+ }
+ return uri;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
index 0a044e3..ff71794 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MTree.java
@@ -584,7 +584,7 @@ public class MTree implements Serializable {
List<Pair<PartialPath, String[]>> res = getAllMeasurementSchema(plan);
List<PartialPath> paths = new ArrayList<>();
for (Pair<PartialPath, String[]> p : res) {
- if (prePath.getMeasurement().equals(p.right[0])) {
+ if (p.right[0] != null) {
p.left.setMeasurementAlias(p.right[0]);
}
paths.add(p.left);
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java
index eacd5e9..619d0e9 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java
@@ -64,6 +64,11 @@ public class Planner {
return physicalGenerator.transformToPhysicalPlan(operator);
}
+ public PhysicalPlan logicalPlanToPhysicalPlan(Operator operator) throws QueryProcessException {
+ operator = logicalOptimize(operator);
+ PhysicalGenerator physicalGenerator = new PhysicalGenerator();
+ 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/service/HTTPService.java b/server/src/main/java/org/apache/iotdb/db/service/HTTPService.java
new file mode 100644
index 0000000..cb25203
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/service/HTTPService.java
@@ -0,0 +1,199 @@
+/*
+ * 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.service;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import org.apache.iotdb.db.concurrent.ThreadName;
+import org.apache.iotdb.db.concurrent.WrappedRunnable;
+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.http.core.HttpServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HTTPService implements HTTPServiceMBean, IService {
+
+ private static final Logger logger = LoggerFactory.getLogger(HTTPService.class);
+ private final String mbeanName = String.format("%s:%s=%s", IoTDBConstant.IOTDB_PACKAGE,
+ IoTDBConstant.JMX_TYPE, getID().getJmxName());
+
+ private HttpServer server;
+ private ExecutorService executorService;
+ private CountDownLatch startLatch;
+
+ public static HTTPService getInstance() {
+ return HTTPServiceHolder.INSTANCE;
+ }
+
+ @Override
+ public ServiceType getID() {
+ return ServiceType.HTTP_SERVICE;
+ }
+
+ @Override
+ public int getHTTPPort() {
+ IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
+ return config.getHTTPPort();
+ }
+
+ @Override
+ public void start() {
+ if (!IoTDBDescriptor.getInstance().getConfig().isEnableHTTPService()) {
+ return;
+ }
+ try {
+ startService();
+ JMXService.registerMBean(getInstance(), mbeanName);
+ } catch (Exception e) {
+ logger.error("Failed to start {} because: ", this.getID().getName(), e);
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (!IoTDBDescriptor.getInstance().getConfig().isEnableHTTPService()) {
+ return;
+ }
+ stopService();
+ JMXService.deregisterMBean(mbeanName);
+ }
+
+ @Override
+ public synchronized void startService() {
+ if (!IoTDBDescriptor.getInstance().getConfig().isEnableHTTPService()) {
+ return;
+ }
+ logger.info("{}: start {}...", IoTDBConstant.GLOBAL_DB_NAME, this.getID().getName());
+ executorService = Executors.newSingleThreadExecutor();
+ int port = getHTTPPort();
+ server = new HttpServer(port);
+ try {
+ reset();
+ executorService.execute(new HTTPServiceThread(server, startLatch));
+ logger.info("{}: start {} successfully, listening on ip {} port {}",
+ IoTDBConstant.GLOBAL_DB_NAME, this.getID().getName(),
+ IoTDBDescriptor.getInstance().getConfig().getRpcAddress(),
+ IoTDBDescriptor.getInstance().getConfig().getHTTPPort());
+ startLatch.await();
+ } catch (NullPointerException | InterruptedException e) {
+ //issue IOTDB-415, we need to stop the service.
+ logger.error("{}: start {} failed, listening on ip {} port {}",
+ IoTDBConstant.GLOBAL_DB_NAME, this.getID().getName(),
+ IoTDBDescriptor.getInstance().getConfig().getRpcAddress(),
+ IoTDBDescriptor.getInstance().getConfig().getHTTPPort());
+ Thread.currentThread().interrupt();
+ stopService();
+ }
+ }
+
+ private void reset() {
+ startLatch = new CountDownLatch(1);
+ }
+
+ @Override
+ public void restartService(){
+ stopService();
+ startService();
+ }
+
+ @Override
+ public void stopService() {
+ if (!IoTDBDescriptor.getInstance().getConfig().isEnableHTTPService()) {
+ return;
+ }
+ logger.info("{}: closing {}...", IoTDBConstant.GLOBAL_DB_NAME, this.getID().getName());
+ try {
+ if (server != null) {
+ server.stop();
+ server = null;
+ }
+ if (executorService != null) {
+ executorService.shutdown();
+ if (!executorService.awaitTermination(
+ 3000, TimeUnit.MILLISECONDS)) {
+ executorService.shutdownNow();
+ }
+ executorService = null;
+ }
+ reset();
+ } catch (Exception e) {
+ logger
+ .error("{}: close {} failed because {}", IoTDBConstant.GLOBAL_DB_NAME, getID().getName(),
+ e.getMessage());
+ executorService.shutdownNow();
+ }
+ checkAndWaitPortIsClosed();
+ logger.info("{}: close {} successfully", IoTDBConstant.GLOBAL_DB_NAME, this.getID().getName());
+ }
+
+ private void checkAndWaitPortIsClosed() {
+ SocketAddress socketAddress = new InetSocketAddress("localhost", getHTTPPort());
+ boolean isClose = false;
+ try(Socket socket = new Socket()) {
+ socket.connect(socketAddress, 1000);
+ } catch (IOException e) {
+ logger.debug("Close port successfully.");
+ isClose = true;
+ } finally {
+ if (!isClose) {
+ logger.error("Port {} can not be closed.", getHTTPPort());
+ }
+ }
+ }
+
+ private static class HTTPServiceHolder {
+
+ private static final HTTPService INSTANCE = new HTTPService();
+
+ private HTTPServiceHolder() {}
+ }
+
+ private class HTTPServiceThread extends WrappedRunnable {
+
+ private HttpServer server;
+ private CountDownLatch threadStartLatch;
+
+ HTTPServiceThread(HttpServer server, CountDownLatch threadStartLatch) {
+ this.server = server;
+ this.threadStartLatch = threadStartLatch;
+ }
+
+ @Override
+ public void runMayThrow() {
+ try {
+ Thread.currentThread().setName(ThreadName.HTTP_SERVICE.getName());
+ server.start();
+ threadStartLatch.countDown();
+ } catch (@SuppressWarnings("squid:S2142") InterruptedException e1) {
+ //we do not sure why InterruptedException happens, but it indeed occurs in Travis WinOS
+ logger.error(e1.getMessage(), e1);
+ } catch (Exception e) {
+ logger.error("{}: failed to start {}, because ", IoTDBConstant.GLOBAL_DB_NAME, getID().getName(), e);
+ }
+ }
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/service/HTTPServiceMBean.java b/server/src/main/java/org/apache/iotdb/db/service/HTTPServiceMBean.java
new file mode 100644
index 0000000..d54dea8
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/service/HTTPServiceMBean.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.iotdb.db.service;
+
+
+public interface HTTPServiceMBean {
+
+ int getHTTPPort();
+
+ void startService();
+
+ void restartService();
+
+ void stopService();
+
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java b/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java
index bf846f4..6dc7dd3 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/IoTDB.java
@@ -120,6 +120,9 @@ public class IoTDB implements IoTDBMBean {
if (IoTDBDescriptor.getInstance().getConfig().isEnableMQTTService()) {
registerManager.register(MQTTService.getInstance());
}
+ if(IoTDBDescriptor.getInstance().getConfig().isEnableHTTPService()) {
+ registerManager.register(HTTPService.getInstance());
+ }
logger.info("IoTDB is set up, now may some sgs are not ready, please wait several seconds...");
diff --git a/server/src/main/java/org/apache/iotdb/db/service/ServiceType.java b/server/src/main/java/org/apache/iotdb/db/service/ServiceType.java
index ad1569b..e1ed1dc 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/ServiceType.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/ServiceType.java
@@ -25,6 +25,7 @@ public enum ServiceType {
STORAGE_ENGINE_SERVICE("Storage Engine ServerService", ""),
JMX_SERVICE("JMX ServerService", "JMX ServerService"),
METRICS_SERVICE("Metrics ServerService","MetricsService"),
+ HTTP_SERVICE("HTTP ServerService","HTTPService"),
RPC_SERVICE("RPC ServerService", "RPCService"),
MQTT_SERVICE("MQTTService", ""),
MONITOR_SERVICE("Monitor ServerService", "Monitor"),
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
index f11443f..16d7416 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/modification/DeletionQueryTest.java
@@ -69,7 +69,8 @@ public class DeletionQueryTest {
@Before
public void setup() throws MetadataException {
EnvironmentUtils.envSetUp();
- deviceMNode = new MNode(null, processorName);
+ String test = "test";
+ deviceMNode = new MNode(null, test);
IoTDB.metaManager.setStorageGroup(new PartialPath(processorName));
for (int i = 0; i < 10; i++) {
deviceMNode.addChild(measurements[i], new MeasurementMNode(null, null, null, null));
diff --git a/server/src/test/java/org/apache/iotdb/db/http/HttpHandlerTest.java b/server/src/test/java/org/apache/iotdb/db/http/HttpHandlerTest.java
new file mode 100644
index 0000000..dbea83a
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/http/HttpHandlerTest.java
@@ -0,0 +1,5 @@
+package org.apache.iotdb.db.http;
+
+public class HttpHandlerTest {
+
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/http/HttpRouterTest.java b/server/src/test/java/org/apache/iotdb/db/http/HttpRouterTest.java
new file mode 100644
index 0000000..08b985e
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/http/HttpRouterTest.java
@@ -0,0 +1,259 @@
+package org.apache.iotdb.db.http;
+
+import static org.apache.iotdb.db.utils.EnvironmentUtils.TEST_QUERY_CONTEXT;
+import static org.junit.Assert.assertEquals;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import io.netty.handler.codec.http.HttpMethod;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import org.apache.iotdb.db.engine.StorageEngine;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.http.router.Router;
+import org.apache.iotdb.db.metadata.MManager;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.metadata.mnode.MNode;
+import org.apache.iotdb.db.metadata.mnode.MeasurementMNode;
+import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
+import org.apache.iotdb.db.qp.physical.crud.RawDataQueryPlan;
+import org.apache.iotdb.db.query.executor.QueryRouter;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.write.record.TSRecord;
+import org.apache.iotdb.tsfile.write.record.datapoint.DoubleDataPoint;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class HttpRouterTest {
+
+ private String processorName = "root.test";
+ private static String[] measurements = new String[10];
+ static {
+ for (int i = 0; i < 10; i++) {
+ measurements[i] = "m" + i;
+ }
+ }
+
+ private MNode deviceMNode;
+ private TSDataType dataType = TSDataType.DOUBLE;
+ private TSEncoding encoding = TSEncoding.PLAIN;
+ private static MManager mmanager = null;
+ private static Router router;
+ private static final String SUCCESSFUL_RESPONSE = "{\"result\":\"successful operation\"}";
+ private QueryRouter queryRouter = new QueryRouter();
+
+ @Before
+ public void before() {
+ EnvironmentUtils.envSetUp();
+ mmanager = IoTDB.metaManager;
+ router = new Router();
+ }
+
+ @After
+ public void after() throws IOException, StorageEngineException {
+ EnvironmentUtils.cleanEnv();
+ }
+
+
+ @Test
+ public void setStorageGroupsByHttp() throws Exception{
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.add("root.ln");
+ jsonArray.add("root.sg");
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.POST, "/storageGroups", jsonArray).toString());
+ Assert.assertEquals("[root.ln, root.sg]",mmanager.getAllStorageGroupPaths().toString());
+ }
+
+ @Test
+ public void getStorageGroupsByHttp() throws Exception {
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ mmanager.setStorageGroup(new PartialPath("root.ln"));
+ mmanager.setStorageGroup(new PartialPath("root.sg"));
+ Assert.assertEquals("[{\"storage group\":\"root.ln\"},{\"storage group\":\"root.sg\"}]", router.route(HttpMethod.GET, "/storageGroups", null).toString());
+ }
+
+ @Test
+ public void deleteStorageGroupsByHttp()
+ throws Exception {
+ prepareData();
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.add(processorName);
+ Assert.assertEquals(1, mmanager.getAllStorageGroupPaths().size());
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ router.route(HttpMethod.DELETE, "/storageGroups", jsonArray);
+ Assert.assertEquals(0, mmanager.getAllStorageGroupPaths().size());
+ }
+
+ @Test
+ public void createTimeSeriesByHttp() throws Exception{
+ JSONArray jsonArray = new JSONArray();
+ JSONObject timeSeries1 = new JSONObject();
+
+ timeSeries1.put("timeSeries", "root.sg.d1.s1");
+ timeSeries1.put("alias", "temperature");
+ timeSeries1.put("dataType", "DOUBLE");
+ timeSeries1.put("encoding", "PLAIN");
+
+ JSONArray props = new JSONArray();
+ JSONObject keyValue = new JSONObject();
+ keyValue.put("key", "hello");
+ keyValue.put("value", "world");
+ props.add(keyValue);
+
+ // same props
+ timeSeries1.put("properties", props);
+ timeSeries1.put("tags", props);
+ timeSeries1.put("attributes", props);
+
+ JSONObject timeSeries2 = new JSONObject();
+ timeSeries2.put("timeSeries", "root.sg.d1.s2");
+ timeSeries2.put("dataType", "DOUBLE");
+ timeSeries2.put("encoding", "PLAIN");
+
+ jsonArray.add(timeSeries1);
+ jsonArray.add(timeSeries2);
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.POST, "/timeSeries", jsonArray).toString());
+ List<PartialPath> paths = mmanager.getAllTimeseriesPathWithAlias(new PartialPath("root.sg.*"));
+ Assert.assertEquals("root.sg.d1.temperature" ,paths.get(0).getFullPathWithAlias());
+ Assert.assertEquals("root.sg.d1.s2", paths.get(1).getFullPath());
+ }
+
+ @Test
+ public void deleteTimeSeriesByHttp() throws Exception{
+ prepareData();
+ JSONArray timeSeries = new JSONArray();
+ for (String measurement : measurements) {
+ timeSeries.add(processorName + TsFileConstant.PATH_SEPARATOR + measurement);
+ }
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.DELETE, "/timeSeries", timeSeries).toString());
+ List<PartialPath> pathList = new ArrayList<>();
+ pathList.add(new PartialPath(processorName + TsFileConstant.PATH_SEPARATOR + measurements[3]));
+ pathList.add(new PartialPath(processorName + TsFileConstant.PATH_SEPARATOR + measurements[4]));
+ pathList.add(new PartialPath(processorName + TsFileConstant.PATH_SEPARATOR + measurements[5]));
+ List<TSDataType> dataTypes = new ArrayList<>();
+ dataTypes.add(dataType);
+ dataTypes.add(dataType);
+ dataTypes.add(dataType);
+
+ RawDataQueryPlan queryPlan = new RawDataQueryPlan();
+ queryPlan.setDeduplicatedDataTypes(dataTypes);
+ queryPlan.setDeduplicatedPaths(pathList);
+ QueryDataSet dataSet = queryRouter.rawDataQuery(queryPlan, TEST_QUERY_CONTEXT);
+ int count = 0;
+ while (dataSet.hasNext()) {
+ dataSet.next();
+ count++;
+ }
+ assertEquals(0, count);
+ }
+
+ @Test
+ public void getTimeSeriesByHttp() throws Exception{
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ mmanager.setStorageGroup(new PartialPath("root.laptop"));
+ CompressionType compressionType = TSFileDescriptor.getInstance().getConfig().getCompressor();
+ mmanager.createTimeseries(new PartialPath("root.laptop.d1.s1"), TSDataType.valueOf("INT32"),
+ TSEncoding.valueOf("RLE"), compressionType, Collections.emptyMap());
+ mmanager.createTimeseries(new PartialPath("root.laptop.d1.1_2"), TSDataType.INT32, TSEncoding.RLE,
+ TSFileDescriptor.getInstance().getConfig().getCompressor(), new HashMap<>());
+ mmanager.createTimeseries(new PartialPath("root.laptop.d1.\"1.2.3\""), TSDataType.INT32, TSEncoding.RLE,
+ TSFileDescriptor.getInstance().getConfig().getCompressor(), new HashMap<>());
+
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.add("root.laptop.*");
+ Assert.assertEquals("[[\"root.laptop.d1.s1\",\"null\",\"root.laptop\",\"INT32\",\"RLE\",\"SNAPPY\"]"
+ + ",[\"root.laptop.d1.1_2\",\"null\",\"root.laptop\",\"INT32\",\"RLE\",\"SNAPPY\"]"
+ + ",[\"root.laptop.d1.\\\"1.2.3\\\"\",\"null\",\"root.laptop\",\"INT32\",\"RLE\",\"SNAPPY\"]]",
+ router.route(HttpMethod.GET, "/timeSeries", jsonArray).toString());
+ }
+
+ @Test
+ public void insertByHttp() throws Exception{
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.GET, "/user/login?username=root&password=root", null).toString());
+ JSONArray inserts = new JSONArray();
+ JSONObject insert = new JSONObject();
+ insert.put("deviceId", "root.ln.wf01.wt01");
+ JSONArray measurements = new JSONArray();
+ measurements.add("temperature");
+ measurements.add("status");
+ measurements.add("hardware");
+ insert.put("measurements", measurements);
+ JSONArray timestamps = new JSONArray();
+ JSONArray values = new JSONArray();
+ for(int i = 0; i < 6; i++) {
+ timestamps.add(i);
+ JSONArray value = new JSONArray();
+ value.add(i);
+ value.add(true);
+ value.add(i);
+ values.add(value);
+ }
+ insert.put("timestamps", timestamps);
+ insert.put("values", values);
+ inserts.add(insert);
+ Assert.assertEquals(SUCCESSFUL_RESPONSE, router.route(HttpMethod.POST, "/insert", inserts).toString());
+
+ List<PartialPath> pathList = new ArrayList<>();
+ pathList.add(new PartialPath("root.ln.wf01.wt01.temperature"));
+ pathList.add(new PartialPath("root.ln.wf01.wt01.status"));
+ pathList.add(new PartialPath("root.ln.wf01.wt01.hardware"));
+ List<TSDataType> dataTypes = new ArrayList<>();
+ dataTypes.add(TSDataType.FLOAT);
+ dataTypes.add(TSDataType.BOOLEAN);
+ dataTypes.add(TSDataType.FLOAT);
+
+ RawDataQueryPlan queryPlan = new RawDataQueryPlan();
+ queryPlan.setDeduplicatedDataTypes(dataTypes);
+ queryPlan.setDeduplicatedPaths(pathList);
+ QueryDataSet dataSet = queryRouter.rawDataQuery(queryPlan, TEST_QUERY_CONTEXT);
+ int count = 0;
+ while (dataSet.hasNext()) {
+ dataSet.next();
+ count++;
+ }
+ Assert.assertEquals(6, count);
+ }
+
+ private void prepareData() throws MetadataException, StorageEngineException {
+ String test = "test";
+ deviceMNode = new MNode(null, test);
+ IoTDB.metaManager.setStorageGroup(new PartialPath(processorName));
+ for (int i = 0; i < 10; i++) {
+ deviceMNode.addChild(measurements[i], new MeasurementMNode(null, null, null, null));
+ IoTDB.metaManager.createTimeseries(new PartialPath(processorName + TsFileConstant.PATH_SEPARATOR + measurements[i]), dataType,
+ encoding, TSFileDescriptor.getInstance().getConfig().getCompressor(), Collections.emptyMap());
+ }
+ for (int i = 1; i <= 100; i++) {
+ TSRecord record = new TSRecord(i, processorName);
+ for (int j = 0; j < 10; j++) {
+ record.addTuple(new DoubleDataPoint(measurements[j], i * 1.0));
+ }
+ insertToStorageEngine(record);
+ }
+ }
+
+ private void insertToStorageEngine(TSRecord record)
+ throws StorageEngineException, IllegalPathException {
+ InsertRowPlan insertRowPlan = new InsertRowPlan(record);
+ insertRowPlan.setDeviceMNode(deviceMNode);
+ StorageEngine.getInstance().insert(insertRowPlan);
+ }
+
+}