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

Reply via email to