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, ""); + } + +}