You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ka...@apache.org on 2017/05/24 10:42:56 UTC
[25/50] [abbrv] kylin git commit: KYLIN-2632 Refactor REST API for
better convention
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/QueryController.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/QueryController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/QueryController.java
index 99447a1..b6e2d45 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/controller/QueryController.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller/QueryController.java
@@ -39,6 +39,7 @@ import org.apache.kylin.rest.service.QueryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -61,9 +62,10 @@ public class QueryController extends BasicController {
private static final Logger logger = LoggerFactory.getLogger(QueryController.class);
@Autowired
+ @Qualifier("queryService")
private QueryService queryService;
- @RequestMapping(value = "/query", method = RequestMethod.POST)
+ @RequestMapping(value = "/query", method = RequestMethod.POST, produces = { "application/json" })
@ResponseBody
public SQLResponse query(@RequestBody SQLRequest sqlRequest) {
return queryService.doQueryWithCache(sqlRequest);
@@ -76,7 +78,7 @@ public class QueryController extends BasicController {
return queryService.doQueryWithCache(sqlRequest);
}
- @RequestMapping(value = "/saved_queries", method = RequestMethod.POST)
+ @RequestMapping(value = "/saved_queries", method = RequestMethod.POST, produces = { "application/json" })
@ResponseBody
public void saveQuery(@RequestBody SaveSqlRequest sqlRequest) throws IOException {
String creator = SecurityContextHolder.getContext().getAuthentication().getName();
@@ -85,21 +87,21 @@ public class QueryController extends BasicController {
queryService.saveQuery(creator, newQuery);
}
- @RequestMapping(value = "/saved_queries/{id}", method = RequestMethod.DELETE)
+ @RequestMapping(value = "/saved_queries/{id}", method = RequestMethod.DELETE, produces = { "application/json" })
@ResponseBody
public void removeQuery(@PathVariable String id) throws IOException {
String creator = SecurityContextHolder.getContext().getAuthentication().getName();
queryService.removeQuery(creator, id);
}
- @RequestMapping(value = "/saved_queries", method = RequestMethod.GET)
+ @RequestMapping(value = "/saved_queries", method = RequestMethod.GET, produces = { "application/json" })
@ResponseBody
public List<Query> getQueries() throws IOException {
String creator = SecurityContextHolder.getContext().getAuthentication().getName();
return queryService.getQueries(creator);
}
- @RequestMapping(value = "/query/format/{format}", method = RequestMethod.GET)
+ @RequestMapping(value = "/query/format/{format}", method = RequestMethod.GET, produces = { "application/json" })
@ResponseBody
public void downloadQueryResult(@PathVariable String format, SQLRequest sqlRequest, HttpServletResponse response) {
SQLResponse result = queryService.doQueryWithCache(sqlRequest);
@@ -129,7 +131,7 @@ public class QueryController extends BasicController {
}
}
- @RequestMapping(value = "/tables_and_columns", method = RequestMethod.GET)
+ @RequestMapping(value = "/tables_and_columns", method = RequestMethod.GET, produces = { "application/json" })
@ResponseBody
public List<TableMeta> getMetadata(MetaRequest metaRequest) {
try {
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/StreamingController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
index 407ee2e..b0bb02a 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
@@ -39,6 +39,7 @@ import org.apache.kylin.source.kafka.config.KafkaConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -63,13 +64,18 @@ public class StreamingController extends BasicController {
private static final Logger logger = LoggerFactory.getLogger(StreamingController.class);
@Autowired
+ @Qualifier("streamingMgmtService")
private StreamingService streamingService;
+
@Autowired
+ @Qualifier("kafkaMgmtService")
private KafkaConfigService kafkaConfigService;
+
@Autowired
+ @Qualifier("tableService")
private TableService tableService;
- @RequestMapping(value = "/getConfig", method = { RequestMethod.GET })
+ @RequestMapping(value = "/getConfig", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
public List<StreamingConfig> getStreamings(@RequestParam(value = "table", required = false) String table, @RequestParam(value = "limit", required = false) Integer limit, @RequestParam(value = "offset", required = false) Integer offset) {
try {
@@ -80,7 +86,7 @@ public class StreamingController extends BasicController {
}
}
- @RequestMapping(value = "/getKfkConfig", method = { RequestMethod.GET })
+ @RequestMapping(value = "/getKfkConfig", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
public List<KafkaConfig> getKafkaConfigs(@RequestParam(value = "kafkaConfigName", required = false) String kafkaConfigName, @RequestParam(value = "limit", required = false) Integer limit, @RequestParam(value = "offset", required = false) Integer offset) {
try {
@@ -96,7 +102,7 @@ public class StreamingController extends BasicController {
* create Streaming Schema
* @throws java.io.IOException
*/
- @RequestMapping(value = "", method = { RequestMethod.POST })
+ @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { "application/json" })
@ResponseBody
public StreamingRequest saveStreamingConfig(@RequestBody StreamingRequest streamingRequest) {
@@ -170,7 +176,7 @@ public class StreamingController extends BasicController {
return streamingRequest;
}
- @RequestMapping(value = "", method = { RequestMethod.PUT })
+ @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { "application/json" })
@ResponseBody
public StreamingRequest updateStreamingConfig(@RequestBody StreamingRequest streamingRequest) throws JsonProcessingException {
StreamingConfig streamingConfig = deserializeSchemalDesc(streamingRequest);
@@ -201,7 +207,7 @@ public class StreamingController extends BasicController {
return streamingRequest;
}
- @RequestMapping(value = "/{configName}", method = { RequestMethod.DELETE })
+ @RequestMapping(value = "/{configName}", method = { RequestMethod.DELETE }, produces = { "application/json" })
@ResponseBody
public void deleteConfig(@PathVariable String configName) throws IOException {
StreamingConfig config = streamingService.getStreamingManager().getStreamingConfig(configName);
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/TableController.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/TableController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/TableController.java
index ac4ee2f..9785db2 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/controller/TableController.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller/TableController.java
@@ -35,6 +35,7 @@ import org.apache.kylin.rest.service.TableService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -56,6 +57,7 @@ public class TableController extends BasicController {
private static final Logger logger = LoggerFactory.getLogger(TableController.class);
@Autowired
+ @Qualifier("tableService")
private TableService tableService;
/**
@@ -64,7 +66,7 @@ public class TableController extends BasicController {
* @return Table metadata array
* @throws IOException
*/
- @RequestMapping(value = "", method = { RequestMethod.GET })
+ @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
public List<TableDesc> getTableDesc(@RequestParam(value = "ext", required = false) boolean withExt, @RequestParam(value = "project", required = true) String project) throws IOException {
try {
@@ -81,7 +83,7 @@ public class TableController extends BasicController {
* @return Table metadata array
* @throws IOException
*/
- @RequestMapping(value = "/{tableName:.+}", method = { RequestMethod.GET })
+ @RequestMapping(value = "/{tableName:.+}", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
public TableDesc getTableDesc(@PathVariable String tableName) {
TableDesc table = tableService.getTableDescByName(tableName, false);
@@ -90,7 +92,7 @@ public class TableController extends BasicController {
return table;
}
- @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.POST })
+ @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.POST }, produces = { "application/json" })
@ResponseBody
public Map<String, String[]> loadHiveTables(@PathVariable String tables, @PathVariable String project, @RequestBody HiveTableRequest request) throws IOException {
String submitter = SecurityContextHolder.getContext().getAuthentication().getName();
@@ -119,7 +121,7 @@ public class TableController extends BasicController {
return result;
}
- @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.DELETE })
+ @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.DELETE }, produces = { "application/json" })
@ResponseBody
public Map<String, String[]> unLoadHiveTables(@PathVariable String tables, @PathVariable String project) {
Set<String> unLoadSuccess = Sets.newHashSet();
@@ -148,7 +150,7 @@ public class TableController extends BasicController {
* @return Table metadata array
* @throws IOException
*/
- @RequestMapping(value = "/{tableNames}/cardinality", method = { RequestMethod.PUT })
+ @RequestMapping(value = "/{tableNames}/cardinality", method = { RequestMethod.PUT }, produces = { "application/json" })
@ResponseBody
public CardinalityRequest generateCardinality(@PathVariable String tableNames, @RequestBody CardinalityRequest request) throws IOException {
String submitter = SecurityContextHolder.getContext().getAuthentication().getName();
@@ -170,7 +172,7 @@ public class TableController extends BasicController {
* @return Hive databases list
* @throws IOException
*/
- @RequestMapping(value = "/hive", method = { RequestMethod.GET })
+ @RequestMapping(value = "/hive", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
private List<String> showHiveDatabases() throws IOException {
try {
@@ -187,7 +189,7 @@ public class TableController extends BasicController {
* @return Hive table list
* @throws IOException
*/
- @RequestMapping(value = "/hive/{database}", method = { RequestMethod.GET })
+ @RequestMapping(value = "/hive/{database}", method = { RequestMethod.GET }, produces = { "application/json" })
@ResponseBody
private List<String> showHiveTables(@PathVariable String database) throws IOException {
try {
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/UserController.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller/UserController.java b/server-base/src/main/java/org/apache/kylin/rest/controller/UserController.java
index b0336db..9182a3e 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/controller/UserController.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller/UserController.java
@@ -18,12 +18,14 @@
package org.apache.kylin.rest.controller;
+import java.io.IOException;
import java.util.List;
import org.apache.kylin.rest.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
@@ -44,14 +46,15 @@ public class UserController extends BasicController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
+ @Qualifier("userService")
UserService userService;
- @RequestMapping(value = "/authentication", method = RequestMethod.POST, produces = "application/json")
+ @RequestMapping(value = "/authentication", method = RequestMethod.POST, produces = { "application/json" })
public UserDetails authenticate() {
return authenticatedUser();
}
- @RequestMapping(value = "/authentication", method = RequestMethod.GET, produces = "application/json")
+ @RequestMapping(value = "/authentication", method = RequestMethod.GET, produces = { "application/json" })
public UserDetails authenticatedUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
@@ -73,8 +76,8 @@ public class UserController extends BasicController {
return null;
}
- @RequestMapping(value = "/authentication/authorities", method = RequestMethod.GET, produces = "application/json")
- public List<String> getAuthorities() {
+ @RequestMapping(value = "/authentication/authorities", method = RequestMethod.GET, produces = { "application/json" })
+ public List<String> getAuthorities() throws IOException {
return userService.listUserAuthorities();
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/AccessControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/AccessControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/AccessControllerV2.java
new file mode 100644
index 0000000..3258de9
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/AccessControllerV2.java
@@ -0,0 +1,135 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+
+import org.apache.kylin.common.persistence.AclEntity;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.AccessRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.security.AclPermissionFactory;
+import org.apache.kylin.rest.service.AccessService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.acls.model.Acl;
+import org.springframework.security.acls.model.Permission;
+import org.springframework.security.acls.model.Sid;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * @author xduo
+ *
+ */
+@Controller
+@RequestMapping(value = "/access")
+public class AccessControllerV2 extends BasicController {
+
+ @Autowired
+ @Qualifier("accessService")
+ private AccessService accessService;
+
+ /**
+ * Get access entry list of a domain object
+ *
+ * @param uuid
+ * @return
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getAccessEntitiesV2(@RequestHeader("Accept-Language") String lang, @PathVariable String type, @PathVariable String uuid) {
+ MsgPicker.setMsg(lang);
+
+ AclEntity ae = accessService.getAclEntity(type, uuid);
+ Acl acl = accessService.getAcl(ae);
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, accessService.generateAceResponses(acl), "");
+ }
+
+ /**
+ * Grant a new access on a domain object to a user/role
+ *
+ * @param accessRequest
+ */
+
+ @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.POST }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse grantV2(@RequestHeader("Accept-Language") String lang, @PathVariable String type, @PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
+ MsgPicker.setMsg(lang);
+
+ AclEntity ae = accessService.getAclEntity(type, uuid);
+ Sid sid = accessService.getSid(accessRequest.getSid(), accessRequest.isPrincipal());
+ Permission permission = AclPermissionFactory.getPermission(accessRequest.getPermission());
+ Acl acl = accessService.grant(ae, permission, sid);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, accessService.generateAceResponses(acl), "");
+ }
+
+ /**
+ * Update a access on a domain object
+ *
+ * @param accessRequest
+ */
+
+ @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse updateV2(@RequestHeader("Accept-Language") String lang, @PathVariable String type, @PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
+ MsgPicker.setMsg(lang);
+
+ AclEntity ae = accessService.getAclEntity(type, uuid);
+ Permission permission = AclPermissionFactory.getPermission(accessRequest.getPermission());
+ Acl acl = accessService.update(ae, accessRequest.getAccessEntryId(), permission);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, accessService.generateAceResponses(acl), "");
+ }
+
+ /**
+ * Revoke access on a domain object from a user/role
+ *
+ * @param accessRequest
+ */
+
+ @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.DELETE }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse revokeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String type, @PathVariable String uuid, AccessRequest accessRequest) {
+ MsgPicker.setMsg(lang);
+
+ AclEntity ae = accessService.getAclEntity(type, uuid);
+ Acl acl = accessService.revoke(ae, accessRequest.getAccessEntryId());
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, accessService.generateAceResponses(acl), "");
+ }
+
+ /**
+ * @param accessService
+ */
+ public void setAccessService(AccessService accessService) {
+ this.accessService = accessService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/AdminControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/AdminControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/AdminControllerV2.java
new file mode 100644
index 0000000..02195ad
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/AdminControllerV2.java
@@ -0,0 +1,106 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.MetricsRequest;
+import org.apache.kylin.rest.request.UpdateConfigRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.AdminService;
+import org.apache.kylin.rest.service.CubeServiceV2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * Admin Controller is defined as Restful API entrance for UI.
+ *
+ * @author jianliu
+ *
+ */
+@Controller
+@RequestMapping(value = "/admin")
+public class AdminControllerV2 extends BasicController {
+
+ @Autowired
+ @Qualifier("adminService")
+ private AdminService adminService;
+
+ @Autowired
+ @Qualifier("cubeMgmtServiceV2")
+ private CubeServiceV2 cubeMgmtServiceV2;
+
+ @RequestMapping(value = "/env", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getEnvV2(@RequestHeader("Accept-Language") String lang) throws ConfigurationException {
+ MsgPicker.setMsg(lang);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, adminService.getEnv(), "");
+ }
+
+ @RequestMapping(value = "/config", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getConfigV2(@RequestHeader("Accept-Language") String lang) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, adminService.getConfigAsString(), "");
+ }
+
+ @RequestMapping(value = "/metrics/cubes", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse cubeMetricsV2(@RequestHeader("Accept-Language") String lang, MetricsRequest request) {
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeMgmtServiceV2.calculateMetrics(request), "");
+ }
+
+ @RequestMapping(value = "/storage", method = { RequestMethod.DELETE }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void cleanupStorageV2(@RequestHeader("Accept-Language") String lang) {
+ MsgPicker.setMsg(lang);
+
+ adminService.cleanupStorage();
+ }
+
+ @RequestMapping(value = "/config", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void updateKylinConfigV2(@RequestHeader("Accept-Language") String lang, @RequestBody UpdateConfigRequest updateConfigRequest) {
+ MsgPicker.setMsg(lang);
+
+ KylinConfig.getInstanceFromEnv().setProperty(updateConfigRequest.getKey(), updateConfigRequest.getValue());
+ }
+
+ public void setAdminService(AdminService adminService) {
+ this.adminService = adminService;
+ }
+
+ public void setCubeMgmtService(CubeServiceV2 cubeMgmtService) {
+ this.cubeMgmtServiceV2 = cubeMgmtService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/CacheControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/CacheControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/CacheControllerV2.java
new file mode 100644
index 0000000..3cd5abd
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/CacheControllerV2.java
@@ -0,0 +1,91 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.metadata.cachesync.Broadcaster;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.service.CacheService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * CubeController is defined as Restful API entrance for UI.
+ *
+ * @author jianliu
+ */
+@Controller
+@RequestMapping(value = "/cache")
+public class CacheControllerV2 extends BasicController {
+
+ @SuppressWarnings("unused")
+ private static final Logger logger = LoggerFactory.getLogger(CacheControllerV2.class);
+
+ @Autowired
+ @Qualifier("cacheService")
+ private CacheService cacheService;
+
+ /**
+ * Announce wipe cache to all cluster nodes
+ */
+
+ @RequestMapping(value = "/announce/{entity}/{cacheKey}/{event}", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void announceWipeCacheV2(@RequestHeader("Accept-Language") String lang, @PathVariable String entity, @PathVariable String event, @PathVariable String cacheKey) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ cacheService.annouceWipeCache(entity, event, cacheKey);
+ }
+
+ /**
+ * Wipe cache on this node
+ */
+
+ @RequestMapping(value = "/{entity}/{cacheKey}/{event}", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void wipeCacheV2(@RequestHeader("Accept-Language") String lang, @PathVariable String entity, @PathVariable String event, @PathVariable String cacheKey) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ cacheService.notifyMetadataChange(entity, Broadcaster.Event.getEvent(event), cacheKey);
+ }
+
+ @RequestMapping(value = "/announce/config", method = { RequestMethod.POST }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void hotLoadKylinConfigV2(@RequestHeader("Accept-Language") String lang) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ KylinConfig.getInstanceFromEnv().hotLoadKylinProperties();
+ cacheService.notifyMetadataChange(Broadcaster.SYNC_ALL, Broadcaster.Event.UPDATE, Broadcaster.SYNC_ALL);
+ }
+
+ public void setCacheService(CacheService cacheService) {
+ this.cacheService = cacheService;
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeControllerV2.java
new file mode 100644
index 0000000..05d99f5
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeControllerV2.java
@@ -0,0 +1,755 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.cube.CubeInstance;
+import org.apache.kylin.cube.CubeManager;
+import org.apache.kylin.cube.CubeSegment;
+import org.apache.kylin.cube.model.AggregationGroup;
+import org.apache.kylin.cube.model.CubeBuildTypeEnum;
+import org.apache.kylin.cube.model.CubeDesc;
+import org.apache.kylin.dimension.DimensionEncodingFactory;
+import org.apache.kylin.engine.EngineFactory;
+import org.apache.kylin.job.JobInstance;
+import org.apache.kylin.job.JoinedFlatTable;
+import org.apache.kylin.metadata.model.DataModelDesc;
+import org.apache.kylin.metadata.model.IJoinedFlatTableDesc;
+import org.apache.kylin.metadata.model.ISourceAware;
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.metadata.realization.RealizationStatusEnum;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.exception.BadRequestException;
+import org.apache.kylin.rest.msg.Message;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.CubeRequest;
+import org.apache.kylin.rest.request.JobBuildRequest;
+import org.apache.kylin.rest.request.JobBuildRequest2;
+import org.apache.kylin.rest.response.CubeInstanceResponse;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.GeneralResponse;
+import org.apache.kylin.rest.response.HBaseResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.CubeServiceV2;
+import org.apache.kylin.rest.service.JobService;
+import org.apache.kylin.rest.service.ModelServiceV2;
+import org.apache.kylin.rest.service.ProjectServiceV2;
+import org.apache.kylin.source.kafka.util.KafkaClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.google.common.collect.Lists;
+
+/**
+ * CubeController is defined as Restful API entrance for UI.
+ */
+@Controller
+@RequestMapping(value = "/cubes")
+public class CubeControllerV2 extends BasicController {
+ private static final Logger logger = LoggerFactory.getLogger(CubeControllerV2.class);
+
+ public static final char[] VALID_CUBENAME = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
+
+ @Autowired
+ @Qualifier("cubeMgmtServiceV2")
+ private CubeServiceV2 cubeServiceV2;
+
+ @Autowired
+ @Qualifier("jobService")
+ private JobService jobService;
+
+ @Autowired
+ @Qualifier("projectServiceV2")
+ private ProjectServiceV2 projectServiceV2;
+
+ @Autowired
+ @Qualifier("modelMgmtServiceV2")
+ private ModelServiceV2 modelServiceV2;
+
+ @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getCubesPaging(@RequestHeader("Accept-Language") String lang, @RequestParam(value = "cubeName", required = false) String cubeName, @RequestParam(value = "modelName", required = false) String modelName, @RequestParam(value = "projectName", required = false) String projectName, @RequestParam(value = "pageOffset", required = false, defaultValue = "0") Integer pageOffset, @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+ MsgPicker.setMsg(lang);
+
+ HashMap<String, Object> data = new HashMap<String, Object>();
+ List<CubeInstanceResponse> cubeInstanceResponses = new ArrayList<CubeInstanceResponse>();
+ List<CubeInstance> cubes = cubeServiceV2.listAllCubes(cubeName, projectName, modelName);
+
+ int offset = pageOffset * pageSize;
+ int limit = pageSize;
+
+ if (cubes.size() <= offset) {
+ offset = cubes.size();
+ limit = 0;
+ }
+
+ if ((cubes.size() - offset) < limit) {
+ limit = cubes.size() - offset;
+ }
+
+ for (CubeInstance cube : cubes.subList(offset, offset + limit)) {
+ CubeInstanceResponse cubeInstanceResponse = new CubeInstanceResponse(cube);
+ cubeInstanceResponse.setPartitionDateStart(cube.getDescriptor().getPartitionDateStart());
+
+ String getModelName = modelName == null ? cube.getDescriptor().getModelName() : modelName;
+ cubeInstanceResponse.setModel(getModelName);
+
+ DataModelDesc getModel = modelServiceV2.getMetadataManager().getDataModelDesc(getModelName);
+ cubeInstanceResponse.setPartitionDateColumn(getModel.getPartitionDesc().getPartitionDateColumn());
+
+ cubeInstanceResponse.setIs_streaming(getModel.getRootFactTable().getTableDesc().getSourceType() == ISourceAware.ID_STREAMING);
+
+ if (projectName != null)
+ cubeInstanceResponse.setProject(projectName);
+ else {
+ List<ProjectInstance> projectInstances = projectServiceV2.listProjects(null, null);
+ for (ProjectInstance projectInstance : projectInstances) {
+ if (projectInstance.containsModel(getModelName))
+ cubeInstanceResponse.setProject(projectInstance.getName());
+ }
+ }
+
+ cubeInstanceResponses.add(cubeInstanceResponse);
+ }
+ data.put("cubes", cubeInstanceResponses);
+ data.put("size", cubes.size());
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+ }
+
+ @RequestMapping(value = "validEncodings", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getValidEncodingsV2(@RequestHeader("Accept-Language") String lang) {
+ MsgPicker.setMsg(lang);
+
+ Map<String, Integer> encodings = DimensionEncodingFactory.getValidEncodings();
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, encodings, "");
+ }
+
+ @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ CubeInstanceResponse cubeInstanceResponse = new CubeInstanceResponse(cube);
+ cubeInstanceResponse.setPartitionDateStart(cube.getDescriptor().getPartitionDateStart());
+
+ String modelName = cube.getDescriptor().getModelName();
+ cubeInstanceResponse.setModel(modelName);
+
+ DataModelDesc model = modelServiceV2.getMetadataManager().getDataModelDesc(modelName);
+ cubeInstanceResponse.setPartitionDateColumn(model.getPartitionDesc().getPartitionDateColumn());
+
+ cubeInstanceResponse.setIs_streaming(model.getRootFactTable().getTableDesc().getSourceType() == ISourceAware.ID_STREAMING);
+
+ List<ProjectInstance> projectInstances = projectServiceV2.listProjects(null, null);
+ for (ProjectInstance projectInstance : projectInstances) {
+ if (projectInstance.containsModel(modelName))
+ cubeInstanceResponse.setProject(projectInstance.getName());
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeInstanceResponse, "");
+ }
+
+ /**
+ * Get hive SQL of the cube
+ *
+ * @param cubeName Cube Name
+ * @return
+ * @throws UnknownHostException
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/sql", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getSqlV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ IJoinedFlatTableDesc flatTableDesc = EngineFactory.getJoinedFlatTableDesc(cube.getDescriptor());
+ String sql = JoinedFlatTable.generateSelectDataStatement(flatTableDesc);
+
+ GeneralResponse response = new GeneralResponse();
+ response.setProperty("sql", sql);
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, response, "");
+ }
+
+ /**
+ * Update cube notify list
+ *
+ * @param cubeName
+ * @param notifyList
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/notify_list", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void updateNotifyListV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody List<String> notifyList) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ cubeServiceV2.updateCubeNotifyList(cube, notifyList);
+
+ }
+
+ @RequestMapping(value = "/{cubeName}/cost", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse updateCubeCostV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody Integer cost) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.updateCubeCost(cube, cost), "");
+ }
+
+ /**
+ * Force rebuild a cube's lookup table snapshot
+ *
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/segs/{segmentName}/refresh_lookup", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse rebuildLookupSnapshotV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @PathVariable String segmentName, @RequestBody String lookupTable) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ final CubeManager cubeMgr = cubeServiceV2.getCubeManager();
+ final CubeInstance cube = cubeMgr.getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.rebuildLookupSnapshot(cube, segmentName, lookupTable), "");
+ }
+
+ /**
+ * Delete a cube segment
+ *
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/segs/{segmentName}", method = { RequestMethod.DELETE }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse deleteSegmentV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @PathVariable String segmentName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ CubeSegment segment = cube.getSegment(segmentName, null);
+ if (segment == null) {
+ throw new BadRequestException(String.format(msg.getSEG_NOT_FOUND(), segmentName));
+ }
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.deleteSegment(cube, segmentName), "");
+ }
+
+ /** Build/Rebuild a cube segment */
+
+ /** Build/Rebuild a cube segment */
+ @RequestMapping(value = "/{cubeName}/build", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse buildV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody JobBuildRequest req) throws IOException {
+ return rebuildV2(lang, cubeName, req);
+ }
+
+ /** Build/Rebuild a cube segment */
+
+ @RequestMapping(value = "/{cubeName}/rebuild", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse rebuildV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody JobBuildRequest req) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, buildInternalV2(cubeName, req.getStartTime(), req.getEndTime(), 0, 0, null, null, req.getBuildType(), req.isForce() || req.isForceMergeEmptySegment()), "");
+ }
+
+ /** Build/Rebuild a cube segment by source offset */
+
+ @RequestMapping(value = "/{cubeName}/build_streaming", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse build2V2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody JobBuildRequest2 req) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ boolean existKafkaClient = false;
+ try {
+ Class<?> clazz = Class.forName("org.apache.kafka.clients.consumer.KafkaConsumer");
+ if (clazz != null) {
+ existKafkaClient = true;
+ }
+ } catch (ClassNotFoundException e) {
+ existKafkaClient = false;
+ }
+ if (!existKafkaClient) {
+ throw new BadRequestException(msg.getKAFKA_DEP_NOT_FOUND());
+ }
+ return rebuild2V2(lang, cubeName, req);
+ }
+
+ /** Build/Rebuild a cube segment by source offset */
+ @RequestMapping(value = "/{cubeName}/rebuild_streaming", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse rebuild2V2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody JobBuildRequest2 req) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, buildInternalV2(cubeName, 0, 0, req.getSourceOffsetStart(), req.getSourceOffsetEnd(), req.getSourcePartitionOffsetStart(), req.getSourcePartitionOffsetEnd(), req.getBuildType(), req.isForce()), "");
+ }
+
+ private JobInstance buildInternalV2(String cubeName, long startTime, long endTime, //
+ long startOffset, long endOffset, Map<Integer, Long> sourcePartitionOffsetStart, Map<Integer, Long> sourcePartitionOffsetEnd, String buildType, boolean force) throws IOException {
+ Message msg = MsgPicker.getMsg();
+
+ String submitter = SecurityContextHolder.getContext().getAuthentication().getName();
+ CubeInstance cube = jobService.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ if (cube.getStatus() != null && cube.getStatus().equals("DRAFT")) {
+ throw new BadRequestException(msg.getBUILD_DRAFT_CUBE());
+ }
+ return jobService.submitJob(cube, startTime, endTime, startOffset, endOffset, //
+ sourcePartitionOffsetStart, sourcePartitionOffsetEnd, CubeBuildTypeEnum.valueOf(buildType), force, submitter);
+ }
+
+ @RequestMapping(value = "/{cubeName}/disable", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse disableCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.disableCube(cube), "");
+
+ }
+
+ @RequestMapping(value = "/{cubeName}/purge", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse purgeCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.purgeCube(cube), "");
+ }
+
+ @RequestMapping(value = "/{cubeName}/clone", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse cloneCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName, @RequestBody CubeRequest cubeRequest) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ String newCubeName = cubeRequest.getCubeName();
+ String project = cubeRequest.getProject();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ if (cube.getStatus() == RealizationStatusEnum.DESCBROKEN) {
+ throw new BadRequestException(String.format(msg.getCLONE_BROKEN_CUBE(), cubeName));
+ }
+ if (!StringUtils.containsOnly(newCubeName, VALID_CUBENAME)) {
+ logger.info("Invalid Cube name {}, only letters, numbers and underline supported.", newCubeName);
+ throw new BadRequestException(String.format(msg.getINVALID_CUBE_NAME(), cubeName));
+ }
+
+ CubeDesc cubeDesc = cube.getDescriptor();
+ CubeDesc newCubeDesc = CubeDesc.getCopyOf(cubeDesc);
+
+ newCubeDesc.setName(newCubeName);
+
+ CubeInstance newCube;
+ newCube = cubeServiceV2.createCubeAndDesc(newCubeName, project, newCubeDesc);
+
+ //reload to avoid shallow clone
+ cubeServiceV2.getCubeDescManager().reloadCubeDescLocal(newCubeName);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, newCube, "");
+ }
+
+ @RequestMapping(value = "/{cubeName}/enable", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse enableCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.enableCube(cube), "");
+ }
+
+ @RequestMapping(value = "/{cubeName}", method = { RequestMethod.DELETE }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void deleteCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (null == cube) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ //drop Cube
+ cubeServiceV2.deleteCube(cube);
+
+ }
+
+ /**
+ * update CubDesc
+ *
+ * @return Table metadata array
+ * @throws JsonProcessingException
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse updateCubeDescV2(@RequestHeader("Accept-Language") String lang, @RequestBody CubeRequest cubeRequest) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ CubeDesc desc = deserializeCubeDescV2(cubeRequest);
+ cubeServiceV2.validateCubeDesc(desc, false);
+
+ boolean createNew = cubeServiceV2.unifyCubeDesc(desc, false);
+
+ String projectName = (null == cubeRequest.getProject()) ? ProjectInstance.DEFAULT_PROJECT_NAME : cubeRequest.getProject();
+
+ desc = cubeServiceV2.updateCubeToResourceStore(desc, projectName, createNew, false);
+
+ String descData = JsonUtil.writeValueAsIndentString(desc);
+ GeneralResponse data = new GeneralResponse();
+ data.setProperty("uuid", desc.getUuid());
+ data.setProperty("cubeDescData", descData);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+ }
+
+ @RequestMapping(value = "/draft", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse updateCubeDescDraftV2(@RequestHeader("Accept-Language") String lang, @RequestBody CubeRequest cubeRequest) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ CubeDesc desc = deserializeCubeDescV2(cubeRequest);
+ cubeServiceV2.validateCubeDesc(desc, true);
+
+ boolean createNew = cubeServiceV2.unifyCubeDesc(desc, true);
+
+ String projectName = (null == cubeRequest.getProject()) ? ProjectInstance.DEFAULT_PROJECT_NAME : cubeRequest.getProject();
+
+ desc = cubeServiceV2.updateCubeToResourceStore(desc, projectName, createNew, true);
+
+ String descData = JsonUtil.writeValueAsIndentString(desc);
+ GeneralResponse data = new GeneralResponse();
+ data.setProperty("uuid", desc.getUuid());
+ data.setProperty("cubeDescData", descData);
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+ }
+
+ /**
+ * get Hbase Info
+ *
+ * @return true
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/hbase", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getHBaseInfoV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ List<HBaseResponse> hbase = new ArrayList<HBaseResponse>();
+
+ CubeInstance cube = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cube == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ List<CubeSegment> segments = cube.getSegments();
+
+ for (CubeSegment segment : segments) {
+ String tableName = segment.getStorageLocationIdentifier();
+ HBaseResponse hr = null;
+
+ // Get info of given table.
+ try {
+ hr = cubeServiceV2.getHTableInfo(tableName);
+ } catch (IOException e) {
+ logger.error("Failed to calculate size of HTable \"" + tableName + "\".", e);
+ }
+
+ if (null == hr) {
+ logger.info("Failed to calculate size of HTable \"" + tableName + "\".");
+ hr = new HBaseResponse();
+ }
+
+ hr.setTableName(tableName);
+ hr.setDateRangeStart(segment.getDateRangeStart());
+ hr.setDateRangeEnd(segment.getDateRangeEnd());
+ hr.setSegmentName(segment.getName());
+ hr.setSegmentUUID(segment.getUuid());
+ hr.setSegmentStatus(segment.getStatus().toString());
+ hr.setSourceCount(segment.getInputRecords());
+ if (segment.isSourceOffsetsOn()) {
+ hr.setSourceOffsetStart(segment.getSourceOffsetStart());
+ hr.setSourceOffsetEnd(segment.getSourceOffsetEnd());
+ }
+ hbase.add(hr);
+ }
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, hbase, "");
+ }
+
+ /**
+ * get cube segment holes
+ *
+ * @return a list of CubeSegment, each representing a hole
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getHolesV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+
+ checkCubeNameV2(cubeName);
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.getCubeManager().calculateHoles(cubeName), "");
+ }
+
+ /**
+ * fill cube segment holes
+ *
+ * @return a list of JobInstances to fill the holes
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse fillHolesV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+
+ checkCubeNameV2(cubeName);
+
+ List<JobInstance> jobs = Lists.newArrayList();
+ List<CubeSegment> holes = cubeServiceV2.getCubeManager().calculateHoles(cubeName);
+
+ if (holes.size() == 0) {
+ logger.info("No hole detected for cube '" + cubeName + "'");
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, jobs, "");
+ }
+
+ boolean isOffsetOn = holes.get(0).isSourceOffsetsOn();
+ for (CubeSegment hole : holes) {
+ if (isOffsetOn == true) {
+ JobBuildRequest2 request = new JobBuildRequest2();
+ request.setBuildType(CubeBuildTypeEnum.BUILD.toString());
+ request.setSourceOffsetStart(hole.getSourceOffsetStart());
+ request.setSourcePartitionOffsetStart(hole.getSourcePartitionOffsetStart());
+ request.setSourceOffsetEnd(hole.getSourceOffsetEnd());
+ request.setSourcePartitionOffsetEnd(hole.getSourcePartitionOffsetEnd());
+ try {
+ JobInstance job = (JobInstance) build2V2(lang, cubeName, request).data;
+ jobs.add(job);
+ } catch (Exception e) {
+ // it may exceed the max allowed job number
+ logger.info("Error to submit job for hole '" + hole.toString() + "', skip it now.", e);
+ continue;
+ }
+ } else {
+ JobBuildRequest request = new JobBuildRequest();
+ request.setBuildType(CubeBuildTypeEnum.BUILD.toString());
+ request.setStartTime(hole.getDateRangeStart());
+ request.setEndTime(hole.getDateRangeEnd());
+
+ try {
+ JobInstance job = (JobInstance) buildV2(lang, cubeName, request).data;
+ jobs.add(job);
+ } catch (Exception e) {
+ // it may exceed the max allowed job number
+ logger.info("Error to submit job for hole '" + hole.toString() + "', skip it now.", e);
+ continue;
+ }
+ }
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, jobs, "");
+ }
+
+ /**
+ * Initiate the very beginning of a streaming cube. Will seek the latest offests of each partition from streaming
+ * source (kafka) and record in the cube descriptor; In the first build job, it will use these offests as the start point.
+ * @param cubeName
+ * @return
+ */
+
+ @RequestMapping(value = "/{cubeName}/init_start_offsets", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse initStartOffsetsV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) throws IOException {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ checkCubeNameV2(cubeName);
+ CubeInstance cubeInstance = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cubeInstance.getSourceType() != ISourceAware.ID_STREAMING) {
+ throw new BadRequestException(String.format(msg.getNOT_STREAMING_CUBE(), cubeName));
+ }
+
+ final GeneralResponse response = new GeneralResponse();
+ final Map<Integer, Long> startOffsets = KafkaClient.getLatestOffsets(cubeInstance);
+ CubeDesc desc = cubeInstance.getDescriptor();
+ desc.setPartitionOffsetStart(startOffsets);
+ cubeServiceV2.getCubeDescManager().updateCubeDesc(desc);
+ response.setProperty("result", "success");
+ response.setProperty("offsets", startOffsets.toString());
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, response, "");
+ }
+
+ /**
+ * Calculate Cuboid Combination based on the AggreationGroup definition.
+ *
+ * @param aggregationGroupStr
+ * @return number of cuboid, -1 if failed
+ */
+
+ @RequestMapping(value = "aggregationgroups/cuboid", method = RequestMethod.POST, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse calculateCuboidCombinationV2(@RequestHeader("Accept-Language") String lang, @RequestBody String aggregationGroupStr) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ AggregationGroup aggregationGroup = deserializeAggregationGroupV2(aggregationGroupStr);
+ if (aggregationGroup != null) {
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, aggregationGroup.calculateCuboidCombination(), "");
+ } else
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, -1, "");
+ }
+
+ @RequestMapping(value = "/checkNameAvailability/{cubeName}", method = RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse checkNameAvailabilityV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, cubeServiceV2.checkNameAvailability(cubeName), "");
+ }
+
+ private CubeDesc deserializeCubeDescV2(CubeRequest cubeRequest) throws IOException {
+ Message msg = MsgPicker.getMsg();
+
+ CubeDesc desc = null;
+ try {
+ logger.debug("Saving cube " + cubeRequest.getCubeDescData());
+ desc = JsonUtil.readValue(cubeRequest.getCubeDescData(), CubeDesc.class);
+ } catch (JsonParseException e) {
+ logger.error("The cube definition is not valid.", e);
+ throw new BadRequestException(msg.getINVALID_CUBE_DEFINITION());
+ } catch (JsonMappingException e) {
+ logger.error("The cube definition is not valid.", e);
+ throw new BadRequestException(msg.getINVALID_CUBE_DEFINITION());
+ }
+ return desc;
+ }
+
+ private AggregationGroup deserializeAggregationGroupV2(String aggregationGroupStr) throws IOException {
+ AggregationGroup aggreationGroup = null;
+ try {
+ logger.debug("Parsing AggregationGroup " + aggregationGroupStr);
+ aggreationGroup = JsonUtil.readValue(aggregationGroupStr, AggregationGroup.class);
+ } catch (JsonParseException e) {
+ logger.error("The AggregationGroup definition is not valid.", e);
+ } catch (JsonMappingException e) {
+ logger.error("The AggregationGroup definition is not valid.", e);
+ }
+ return aggreationGroup;
+ }
+
+ private void checkCubeNameV2(String cubeName) {
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cubeInstance = cubeServiceV2.getCubeManager().getCube(cubeName);
+
+ if (cubeInstance == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ }
+
+ public void setCubeService(CubeServiceV2 cubeService) {
+ this.cubeServiceV2 = cubeService;
+ }
+
+ public void setJobService(JobService jobService) {
+ this.jobService = jobService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeDescControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeDescControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeDescControllerV2.java
new file mode 100644
index 0000000..0984c11
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/CubeDescControllerV2.java
@@ -0,0 +1,141 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.apache.kylin.cube.CubeInstance;
+import org.apache.kylin.cube.model.CubeDesc;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.exception.BadRequestException;
+import org.apache.kylin.rest.msg.Message;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.CubeServiceV2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import static org.apache.kylin.cube.model.CubeDesc.STATUS_DRAFT;
+
+/**
+ * @author xduo
+ *
+ */
+@Controller
+@RequestMapping(value = "/cube_desc")
+public class CubeDescControllerV2 extends BasicController {
+
+ @Autowired
+ @Qualifier("cubeMgmtServiceV2")
+ private CubeServiceV2 cubeServiceV2;
+
+ /**
+ * Get detail information of the "Cube ID"
+ *
+ * @param cubeName
+ * Cube Name
+ * @return
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getCubeV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ CubeInstance cubeInstance = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cubeInstance == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+ CubeDesc cSchema = cubeInstance.getDescriptor();
+ if (cSchema != null) {
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, new CubeDesc[] { cSchema }, "");
+ } else {
+ throw new BadRequestException(String.format(msg.getCUBE_DESC_NOT_FOUND(), cubeName));
+ }
+ }
+
+ /**
+ * Get detail information of the "Cube ID"
+ * return CubeDesc instead of CubeDesc[]
+ *
+ * @param cubeName
+ * Cube Name
+ * @return
+ * @throws IOException
+ */
+
+ @RequestMapping(value = "/{cubeName}/desc", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getDescV2(@RequestHeader("Accept-Language") String lang, @PathVariable String cubeName) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ HashMap<String, CubeDesc> data = new HashMap<String, CubeDesc>();
+
+ CubeInstance cubeInstance = cubeServiceV2.getCubeManager().getCube(cubeName);
+ if (cubeInstance == null) {
+ throw new BadRequestException(String.format(msg.getCUBE_NOT_FOUND(), cubeName));
+ }
+
+ CubeDesc desc = cubeInstance.getDescriptor();
+ if (desc == null)
+ throw new BadRequestException(String.format(msg.getCUBE_DESC_NOT_FOUND(), cubeName));
+
+ if (desc.getStatus() == null) {
+ data.put("cube", desc);
+
+ String draftName = cubeName + "_draft";
+ CubeInstance draftCubeInstance = cubeServiceV2.getCubeManager().getCube(draftName);
+ if (draftCubeInstance != null) {
+ CubeDesc draftCubeDesc = draftCubeInstance.getDescriptor();
+ if (draftCubeDesc != null && draftCubeDesc.getStatus() != null && draftCubeDesc.getStatus().equals(STATUS_DRAFT)) {
+ data.put("draft", draftCubeDesc);
+ }
+ }
+ } else if (desc.getStatus().equals(STATUS_DRAFT)) {
+ data.put("draft", desc);
+
+ String parentName = cubeName.substring(0, cubeName.lastIndexOf("_draft"));
+ CubeInstance parentCubeInstance = cubeServiceV2.getCubeManager().getCube(parentName);
+ if (parentCubeInstance != null) {
+ CubeDesc parentDesc = parentCubeInstance.getDescriptor();
+ if (parentDesc != null && parentDesc.getStatus() == null) {
+ data.put("cube", parentDesc);
+ }
+ }
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+ }
+
+ public void setCubeService(CubeServiceV2 cubeService) {
+ this.cubeServiceV2 = cubeService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/DiagnosisControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/DiagnosisControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/DiagnosisControllerV2.java
new file mode 100644
index 0000000..290e130
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/DiagnosisControllerV2.java
@@ -0,0 +1,121 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.kylin.metadata.badquery.BadQueryEntry;
+import org.apache.kylin.metadata.badquery.BadQueryHistory;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.DiagnosisService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.google.common.collect.Lists;
+
+@Controller
+@RequestMapping(value = "/diag")
+public class DiagnosisControllerV2 extends BasicController {
+
+ private static final Logger logger = LoggerFactory.getLogger(DiagnosisControllerV2.class);
+
+ @Autowired
+ @Qualifier("diagnosisService")
+ private DiagnosisService dgService;
+
+ /**
+ * Get bad query history
+ */
+
+ @RequestMapping(value = "/{project}/sql", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getBadQuerySqlV2(@RequestHeader("Accept-Language") String lang, @PathVariable String project, @RequestParam(value = "pageOffset", required = false, defaultValue = "0") Integer pageOffset, @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ HashMap<String, Object> data = new HashMap<String, Object>();
+ List<BadQueryEntry> badEntry = Lists.newArrayList();
+ BadQueryHistory badQueryHistory = dgService.getProjectBadQueryHistory(project);
+ badEntry.addAll(badQueryHistory.getEntries());
+
+ int offset = pageOffset * pageSize;
+ int limit = pageSize;
+
+ if (badEntry.size() <= offset) {
+ offset = badEntry.size();
+ limit = 0;
+ }
+
+ if ((badEntry.size() - offset) < limit) {
+ limit = badEntry.size() - offset;
+ }
+
+ data.put("badQueries", badEntry.subList(offset, offset + limit));
+ data.put("size", badEntry.size());
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+ }
+
+ /**
+ * Get diagnosis information for project
+ */
+
+ @RequestMapping(value = "/project/{project}/download", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void dumpProjectDiagnosisInfoV2(@RequestHeader("Accept-Language") String lang, @PathVariable String project, final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ String filePath;
+ filePath = dgService.dumpProjectDiagnosisInfo(project);
+
+ setDownloadResponse(filePath, response);
+ }
+
+ /**
+ * Get diagnosis information for job
+ */
+
+ @RequestMapping(value = "/job/{jobId}/download", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void dumpJobDiagnosisInfoV2(@RequestHeader("Accept-Language") String lang, @PathVariable String jobId, final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ String filePath;
+ filePath = dgService.dumpJobDiagnosisInfo(jobId);
+
+ setDownloadResponse(filePath, response);
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/EncodingControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/EncodingControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/EncodingControllerV2.java
new file mode 100644
index 0000000..edb58b4
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/EncodingControllerV2.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.controller2;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.kylin.metadata.datatype.DataType;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.Message;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.EncodingService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+@Controller
+@RequestMapping(value = "/encodings")
+public class EncodingControllerV2 extends BasicController {
+
+ private static final Logger logger = LoggerFactory.getLogger(EncodingControllerV2.class);
+
+ @Autowired
+ @Qualifier("encodingService")
+ private EncodingService encodingService;
+
+ /**
+ * Get valid encodings for the datatype, if no datatype parameter, return all encodings.
+ *
+ * @return suggestion map
+ */
+
+ @RequestMapping(value = "valid_encodings", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getValidEncodingsV2(@RequestHeader("Accept-Language") String lang) {
+ MsgPicker.setMsg(lang);
+ Message msg = MsgPicker.getMsg();
+
+ Set<String> allDatatypes = Sets.newHashSet();
+ allDatatypes.addAll(DataType.DATETIME_FAMILY);
+ allDatatypes.addAll(DataType.INTEGER_FAMILY);
+ allDatatypes.addAll(DataType.NUMBER_FAMILY);
+ allDatatypes.addAll(DataType.STRING_FAMILY);
+
+ Map<String, List<String>> datatypeValidEncodings = Maps.newHashMap();
+ for (String dataTypeStr : allDatatypes) {
+ datatypeValidEncodings.put(dataTypeStr, encodingService.getValidEncodings(DataType.getType(dataTypeStr)));
+ }
+
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, datatypeValidEncodings, "");
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/ExternalFilterControllerV2.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/controller2/ExternalFilterControllerV2.java b/server-base/src/main/java/org/apache/kylin/rest/controller2/ExternalFilterControllerV2.java
new file mode 100644
index 0000000..4e82b41
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/controller2/ExternalFilterControllerV2.java
@@ -0,0 +1,101 @@
+/*
+ * 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.kylin.rest.controller2;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.metadata.model.ExternalFilterDesc;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.ExternalFilterRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.ExtFilterService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.google.common.collect.Lists;
+
+/**
+ * @author jiazhong
+ */
+@Controller
+@RequestMapping(value = "/extFilter")
+public class ExternalFilterControllerV2 extends BasicController {
+ private static final Logger logger = LoggerFactory.getLogger(ExternalFilterControllerV2.class);
+
+ @Autowired
+ @Qualifier("extFilterService")
+ private ExtFilterService extFilterService;
+
+ @RequestMapping(value = "/saveExtFilter", method = { RequestMethod.POST }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void saveExternalFilterV2(@RequestHeader("Accept-Language") String lang, @RequestBody ExternalFilterRequest request) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ String filterProject = request.getProject();
+ ExternalFilterDesc desc = JsonUtil.readValue(request.getExtFilter(), ExternalFilterDesc.class);
+ desc.setUuid(UUID.randomUUID().toString());
+ extFilterService.saveExternalFilter(desc);
+ extFilterService.syncExtFilterToProject(new String[] { desc.getName() }, filterProject);
+ }
+
+ @RequestMapping(value = "/updateExtFilter", method = { RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void updateExternalFilterV2(@RequestHeader("Accept-Language") String lang, @RequestBody ExternalFilterRequest request) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ ExternalFilterDesc desc = JsonUtil.readValue(request.getExtFilter(), ExternalFilterDesc.class);
+ extFilterService.updateExternalFilter(desc);
+ extFilterService.syncExtFilterToProject(new String[] { desc.getName() }, request.getProject());
+ }
+
+ @RequestMapping(value = "/{filter}/{project}", method = { RequestMethod.DELETE }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public void removeFilterV2(@RequestHeader("Accept-Language") String lang, @PathVariable String filter, @PathVariable String project) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ extFilterService.removeExtFilterFromProject(filter, project);
+ extFilterService.removeExternalFilter(filter);
+ }
+
+ @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+ @ResponseBody
+ public EnvelopeResponse getExternalFiltersV2(@RequestHeader("Accept-Language") String lang, @RequestParam(value = "project", required = true) String project) throws IOException {
+ MsgPicker.setMsg(lang);
+
+ List<ExternalFilterDesc> filterDescs = Lists.newArrayList();
+ filterDescs.addAll(extFilterService.getProjectManager().listExternalFilterDescs(project).values());
+ return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, filterDescs, "");
+ }
+
+}