http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/HybridControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/HybridControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/HybridControllerV2.java
new file mode 100644
index 0000000..ddf745a
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/HybridControllerV2.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.HybridRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.HybridService;
+import org.apache.kylin.storage.hybrid.HybridInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+
+@Controller
+@RequestMapping(value = "/hybrids")
+public class HybridControllerV2 extends BasicController {
+
+    @Autowired
+    private HybridService hybridService;
+
+    @RequestMapping(value = "", method = RequestMethod.POST, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse createV2(@RequestHeader("Accept-Language") String 
lang, @RequestBody HybridRequest request) {
+        MsgPicker.setMsg(lang);
+
+        checkRequiredArg("hybrid", request.getHybrid());
+        checkRequiredArg("project", request.getProject());
+        checkRequiredArg("model", request.getModel());
+        checkRequiredArg("cubes", request.getCubes());
+        HybridInstance instance = 
hybridService.createHybridCube(request.getHybrid(), request.getProject(), 
request.getModel(), request.getCubes());
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, instance, "");
+    }
+
+    @RequestMapping(value = "", method = RequestMethod.PUT, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse updateV2(@RequestHeader("Accept-Language") String 
lang, @RequestBody HybridRequest request) {
+        MsgPicker.setMsg(lang);
+
+        checkRequiredArg("hybrid", request.getHybrid());
+        checkRequiredArg("project", request.getProject());
+        checkRequiredArg("model", request.getModel());
+        checkRequiredArg("cubes", request.getCubes());
+        HybridInstance instance = 
hybridService.updateHybridCube(request.getHybrid(), request.getProject(), 
request.getModel(), request.getCubes());
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, instance, "");
+    }
+
+    @RequestMapping(value = "", method = RequestMethod.DELETE, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void deleteV2(@RequestHeader("Accept-Language") String lang, 
@RequestBody HybridRequest request) {
+        MsgPicker.setMsg(lang);
+
+        checkRequiredArg("hybrid", request.getHybrid());
+        checkRequiredArg("project", request.getProject());
+        checkRequiredArg("model", request.getModel());
+        hybridService.deleteHybridCube(request.getHybrid(), 
request.getProject(), request.getModel());
+    }
+
+    @RequestMapping(value = "", method = RequestMethod.GET, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse listV2(@RequestHeader("Accept-Language") String 
lang, @RequestParam(required = false) String project, @RequestParam(required = 
false) String model) {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
hybridService.listHybrids(project, model), "");
+    }
+
+    @RequestMapping(value = "{hybrid}", method = RequestMethod.GET, produces = 
{ "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String hybrid) {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
hybridService.getHybridInstance(hybrid), "");
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/JobControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/JobControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/JobControllerV2.java
new file mode 100644
index 0000000..4c25071
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/JobControllerV2.java
@@ -0,0 +1,222 @@
+/*
+ * 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.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.kylin.job.JobInstance;
+import org.apache.kylin.job.constant.JobStatusEnum;
+import org.apache.kylin.job.constant.JobTimeFilterEnum;
+import org.apache.kylin.job.exception.JobException;
+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.JobService;
+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;
+
+@Controller
+@RequestMapping(value = "jobs")
+public class JobControllerV2 extends BasicController {
+    private static final Logger logger = 
LoggerFactory.getLogger(JobControllerV2.class);
+
+    @Autowired
+    @Qualifier("jobService")
+    private JobService jobService;
+
+    /**
+     * get all cube jobs
+     * 
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse listV2(@RequestHeader("Accept-Language") String 
lang, @RequestParam(value = "status", required = false) Integer[] status, 
@RequestParam(value = "timeFilter", required = true) Integer timeFilter, 
@RequestParam(value = "cubeName", required = false) String cubeName, 
@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<JobStatusEnum> statusList = new ArrayList<JobStatusEnum>();
+
+        if (null != status) {
+            for (int sta : status) {
+                statusList.add(JobStatusEnum.getByCode(sta));
+            }
+        }
+
+        List<JobInstance> jobInstanceList = jobService.searchJobs(cubeName, 
projectName, statusList, JobTimeFilterEnum.getByCode(timeFilter));
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        if (jobInstanceList.size() <= offset) {
+            offset = jobInstanceList.size();
+            limit = 0;
+        }
+
+        if ((jobInstanceList.size() - offset) < limit) {
+            limit = jobInstanceList.size() - offset;
+        }
+
+        data.put("jobs", jobInstanceList.subList(offset, offset + limit));
+        data.put("size", jobInstanceList.size());
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    /**
+     * Get a cube job
+     * 
+     * @return
+     * @throws JobException 
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String jobId) {
+        MsgPicker.setMsg(lang);
+
+        JobInstance jobInstance = jobService.getJobInstance(jobId);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, jobInstance, 
"");
+    }
+
+    /**
+     * Get a job step output
+     * 
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/steps/{stepId}/output", method = { 
RequestMethod.GET }, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getStepOutputV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String jobId, @PathVariable String stepId) {
+        MsgPicker.setMsg(lang);
+
+        Map<String, String> result = new HashMap<String, String>();
+        result.put("jobId", jobId);
+        result.put("stepId", String.valueOf(stepId));
+        result.put("cmd_output", 
jobService.getExecutableManager().getOutput(stepId).getVerboseMsg());
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, result, "");
+    }
+
+    /**
+     * Resume a cube job
+     * 
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/resume", method = { RequestMethod.PUT }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse resumeV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String jobId) {
+        MsgPicker.setMsg(lang);
+
+        final JobInstance jobInstance = jobService.getJobInstance(jobId);
+        jobService.resumeJob(jobInstance);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
jobService.getJobInstance(jobId), "");
+    }
+
+    /**
+     * Cancel/discard a job
+     * 
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/cancel", method = { RequestMethod.PUT }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse cancelV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String jobId) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        final JobInstance jobInstance = jobService.getJobInstance(jobId);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
jobService.cancelJob(jobInstance), "");
+    }
+
+    /**
+     * Pause a job
+     *
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/pause", method = { RequestMethod.PUT }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse pauseV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String jobId) {
+        MsgPicker.setMsg(lang);
+
+        final JobInstance jobInstance = jobService.getJobInstance(jobId);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
jobService.pauseJob(jobInstance), "");
+    }
+
+    /**
+     * Rollback a job to the given step
+     *
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/steps/{stepId}/rollback", method = { 
RequestMethod.PUT }, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse rollbackV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String jobId, @PathVariable String stepId) {
+        MsgPicker.setMsg(lang);
+
+        final JobInstance jobInstance = jobService.getJobInstance(jobId);
+        jobService.rollbackJob(jobInstance, stepId);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
jobService.getJobInstance(jobId), "");
+    }
+
+    /**
+     * Drop a cube job
+     *
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{jobId}/drop", method = { RequestMethod.DELETE 
}, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse dropJobV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String jobId) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        JobInstance jobInstance = jobService.getJobInstance(jobId);
+        jobService.dropJob(jobInstance);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, jobInstance, 
"");
+    }
+
+    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/ModelControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelControllerV2.java
new file mode 100644
index 0000000..7dc2be7
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelControllerV2.java
@@ -0,0 +1,284 @@
+/*
+ * 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 com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.cube.CubeInstance;
+import org.apache.kylin.metadata.MetadataManager;
+import org.apache.kylin.metadata.model.DataModelDesc;
+import org.apache.kylin.metadata.model.TblColRef;
+import org.apache.kylin.metadata.project.ProjectInstance;
+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.ModelRequest;
+import org.apache.kylin.rest.response.DataModelDescResponse;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.GeneralResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.ModelServiceV2;
+import org.apache.kylin.rest.service.ProjectServiceV2;
+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 java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ModelController is defined as Restful API entrance for UI.
+ *
+ * @author jiazhong
+ */
+@Controller
+@RequestMapping(value = "/models")
+public class ModelControllerV2 extends BasicController {
+    private static final Logger logger = 
LoggerFactory.getLogger(ModelControllerV2.class);
+
+    public static final char[] VALID_MODELNAME = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
+
+    @Autowired
+    @Qualifier("modelMgmtServiceV2")
+    private ModelServiceV2 modelServiceV2;
+
+    @Autowired
+    @Qualifier("projectServiceV2")
+    private ProjectServiceV2 projectServiceV2;
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getModelsPaging(@RequestHeader("Accept-Language") 
String lang, @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) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        HashMap<String, Object> data = new HashMap<String, Object>();
+        List<DataModelDesc> models = modelServiceV2.listAllModels(modelName, 
projectName);
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        if (models.size() <= offset) {
+            offset = models.size();
+            limit = 0;
+        }
+
+        if ((models.size() - offset) < limit) {
+            limit = models.size() - offset;
+        }
+
+        List<DataModelDescResponse> dataModelDescResponses = new 
ArrayList<DataModelDescResponse>();
+        for (DataModelDesc model : modelServiceV2.getModels(modelName, 
projectName, limit, offset)) {
+            DataModelDescResponse dataModelDescResponse = new 
DataModelDescResponse(model);
+
+            if (projectName != null)
+                dataModelDescResponse.setProject(projectName);
+            else
+                
dataModelDescResponse.setProject(projectServiceV2.getProjectOfModel(model.getName()));
+
+            dataModelDescResponses.add(dataModelDescResponse);
+        }
+        data.put("models", dataModelDescResponses);
+        data.put("size", models.size());
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
updateModelDescV2(@RequestHeader("Accept-Language") String lang, @RequestBody 
ModelRequest modelRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        //Update Model
+        DataModelDesc modelDesc = deserializeDataModelDescV2(modelRequest);
+        modelServiceV2.validateModelDesc(modelDesc);
+
+        boolean createNew = modelServiceV2.unifyModelDesc(modelDesc, false);
+
+        String projectName = (null == modelRequest.getProject()) ? 
ProjectInstance.DEFAULT_PROJECT_NAME : modelRequest.getProject();
+
+        modelDesc = modelServiceV2.updateModelToResourceStore(modelDesc, 
projectName, createNew, false);
+
+        String descData = JsonUtil.writeValueAsIndentString(modelDesc);
+        GeneralResponse data = new GeneralResponse();
+        data.setProperty("uuid", modelDesc.getUuid());
+        data.setProperty("modelDescData", descData);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    @RequestMapping(value = "/draft", method = { RequestMethod.PUT }, produces 
= { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
updateModelDescDraftV2(@RequestHeader("Accept-Language") String lang, 
@RequestBody ModelRequest modelRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        DataModelDesc modelDesc = deserializeDataModelDescV2(modelRequest);
+        modelServiceV2.validateModelDesc(modelDesc);
+
+        boolean createNew = modelServiceV2.unifyModelDesc(modelDesc, true);
+
+        String projectName = (null == modelRequest.getProject()) ? 
ProjectInstance.DEFAULT_PROJECT_NAME : modelRequest.getProject();
+
+        modelDesc = modelServiceV2.updateModelToResourceStore(modelDesc, 
projectName, createNew, true);
+
+        String descData = JsonUtil.writeValueAsIndentString(modelDesc);
+        GeneralResponse data = new GeneralResponse();
+        data.setProperty("uuid", modelDesc.getUuid());
+        data.setProperty("modelDescData", descData);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    @RequestMapping(value = "/{modelName}", method = { RequestMethod.DELETE }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void deleteModelV2(@RequestHeader("Accept-Language") String lang, 
@PathVariable String modelName) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        DataModelDesc desc = 
modelServiceV2.getMetadataManager().getDataModelDesc(modelName);
+        if (null == desc) {
+            throw new 
BadRequestException(String.format(msg.getMODEL_NOT_FOUND(), modelName));
+        }
+        modelServiceV2.dropModel(desc);
+    }
+
+    @RequestMapping(value = "/{modelName}/clone", method = { RequestMethod.PUT 
}, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse cloneModelV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String modelName, @RequestBody ModelRequest 
modelRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        String project = modelRequest.getProject();
+        MetadataManager metaManager = 
MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
+        DataModelDesc modelDesc = metaManager.getDataModelDesc(modelName);
+        String newModelName = modelRequest.getModelName();
+
+        if (StringUtils.isEmpty(project)) {
+            logger.info("Project name should not be empty.");
+            throw new BadRequestException(msg.getEMPTY_PROJECT_NAME());
+        }
+
+        if (modelDesc == null || StringUtils.isEmpty(modelName)) {
+            throw new BadRequestException(msg.getEMPTY_MODEL_NAME());
+        }
+
+        if (StringUtils.isEmpty(newModelName)) {
+            logger.info("New model name is empty.");
+            throw new BadRequestException(msg.getEMPTY_NEW_MODEL_NAME());
+        }
+        if (!StringUtils.containsOnly(newModelName, VALID_MODELNAME)) {
+            logger.info("Invalid Model name {}, only letters, numbers and 
underline supported.", newModelName);
+            throw new 
BadRequestException(String.format(msg.getINVALID_MODEL_NAME(), newModelName));
+        }
+
+        DataModelDesc newModelDesc = DataModelDesc.getCopyOf(modelDesc);
+        newModelDesc.setName(newModelName);
+
+        newModelDesc = modelServiceV2.createModelDesc(project, newModelDesc);
+
+        //reload avoid shallow
+        
metaManager.reloadDataModelDescAt(DataModelDesc.concatResourcePath(newModelName));
+
+        String descData = JsonUtil.writeValueAsIndentString(newModelDesc);
+        GeneralResponse data = new GeneralResponse();
+        data.setProperty("uuid", newModelDesc.getUuid());
+        data.setProperty("modelDescData", descData);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    private DataModelDesc deserializeDataModelDescV2(ModelRequest 
modelRequest) throws IOException {
+        Message msg = MsgPicker.getMsg();
+
+        DataModelDesc desc = null;
+        try {
+            logger.debug("Saving MODEL " + modelRequest.getModelDescData());
+            desc = JsonUtil.readValue(modelRequest.getModelDescData(), 
DataModelDesc.class);
+        } catch (JsonParseException e) {
+            logger.error("The data model definition is not valid.", e);
+            throw new BadRequestException(msg.getINVALID_MODEL_DEFINITION());
+        } catch (JsonMappingException e) {
+            logger.error("The data model definition is not valid.", e);
+            throw new BadRequestException(msg.getINVALID_MODEL_DEFINITION());
+        }
+        return desc;
+    }
+
+    @RequestMapping(value = "/checkNameAvailability/{modelName}", method = 
RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
checkNameAvailabilityV2(@RequestHeader("Accept-Language") String lang, 
@PathVariable String modelName) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        boolean ret = modelServiceV2.checkNameAvailability(modelName);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, ret, "");
+    }
+
+    @RequestMapping(value = "/{modelName}/usedCols", method = 
RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getUsedColsV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String modelName) {
+        MsgPicker.setMsg(lang);
+
+        Map<String, Set<String>> data = new HashMap<>();
+
+        for (Map.Entry<TblColRef, Set<CubeInstance>> entry : 
modelServiceV2.getUsedDimCols(modelName).entrySet()) {
+            populateUsedColResponse(entry.getKey(), entry.getValue(), data);
+        }
+
+        for (Map.Entry<TblColRef, Set<CubeInstance>> entry : 
modelServiceV2.getUsedNonDimCols(modelName).entrySet()) {
+            populateUsedColResponse(entry.getKey(), entry.getValue(), data);
+        }
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    private void populateUsedColResponse(TblColRef tblColRef, 
Set<CubeInstance> cubeInstances, Map<String, Set<String>> ret) {
+        String columnIdentity = tblColRef.getIdentity();
+        if (!ret.containsKey(columnIdentity)) {
+            ret.put(columnIdentity, Sets.<String> newHashSet());
+        }
+
+        for (CubeInstance cubeInstance : cubeInstances) {
+            ret.get(columnIdentity).add(cubeInstance.getCanonicalName());
+        }
+    }
+
+    public void setModelService(ModelServiceV2 modelService) {
+        this.modelServiceV2 = modelService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelDescControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelDescControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelDescControllerV2.java
new file mode 100644
index 0000000..14c9a88
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ModelDescControllerV2.java
@@ -0,0 +1,107 @@
+/*
+ * 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 static org.apache.kylin.metadata.model.DataModelDesc.STATUS_DRAFT;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.metadata.MetadataManager;
+import org.apache.kylin.metadata.model.DataModelDesc;
+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.DataModelDescResponse;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.ProjectServiceV2;
+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;
+
+/**
+ * @author jiazhong
+ * 
+ */
+@Controller
+@RequestMapping(value = "/model")
+public class ModelDescControllerV2 extends BasicController {
+
+    @Autowired
+    @Qualifier("projectServiceV2")
+    private ProjectServiceV2 projectServiceV2;
+
+    /**
+     * Get detail information of the "Model ID"
+     * 
+     * @param modelName
+     *            Model ID
+     * @return
+     * @throws IOException
+     */
+    @RequestMapping(value = "/{modelName}", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getModelV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String modelName) {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        HashMap<String, DataModelDescResponse> data = new HashMap<String, 
DataModelDescResponse>();
+
+        MetadataManager metaManager = 
MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
+        DataModelDesc modelDesc = metaManager.getDataModelDesc(modelName);
+        if (modelDesc == null)
+            throw new 
BadRequestException(String.format(msg.getMODEL_NOT_FOUND(), modelName));
+
+        DataModelDescResponse dataModelDescResponse = new 
DataModelDescResponse(modelDesc);
+        
dataModelDescResponse.setProject(projectServiceV2.getProjectOfModel(modelName));
+
+        if (modelDesc.getStatus() == null) {
+            data.put("model", dataModelDescResponse);
+
+            String draftName = modelName + "_draft";
+            DataModelDesc draftDesc = metaManager.getDataModelDesc(draftName);
+            if (draftDesc != null && draftDesc.getStatus() != null && 
draftDesc.getStatus().equals(STATUS_DRAFT)) {
+                DataModelDescResponse draftModelDescResponse = new 
DataModelDescResponse(draftDesc);
+                
draftModelDescResponse.setProject(projectServiceV2.getProjectOfModel(draftName));
+                data.put("draft", draftModelDescResponse);
+            }
+        } else if (modelDesc.getStatus().equals(STATUS_DRAFT)) {
+            data.put("draft", dataModelDescResponse);
+
+            String parentName = modelName.substring(0, 
modelName.lastIndexOf("_draft"));
+            DataModelDesc parentDesc = 
metaManager.getDataModelDesc(parentName);
+            if (parentDesc != null && parentDesc.getStatus() == null) {
+                DataModelDescResponse parentModelDescResponse = new 
DataModelDescResponse(parentDesc);
+                
parentModelDescResponse.setProject(projectServiceV2.getProjectOfModel(parentName));
+                data.put("model", parentModelDescResponse);
+            }
+        }
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/ProjectControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/ProjectControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ProjectControllerV2.java
new file mode 100644
index 0000000..3ab0d66
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/ProjectControllerV2.java
@@ -0,0 +1,269 @@
+/*
+ * 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.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.persistence.AclEntity;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.cube.CubeInstance;
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.rest.constant.Constant;
+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.ProjectRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.AccessService;
+import org.apache.kylin.rest.service.CubeServiceV2;
+import org.apache.kylin.rest.service.ProjectServiceV2;
+import org.apache.kylin.rest.util.AclUtil;
+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.acls.domain.GrantedAuthoritySid;
+import org.springframework.security.acls.domain.PrincipalSid;
+import org.springframework.security.acls.model.AccessControlEntry;
+import org.springframework.security.acls.model.Acl;
+import org.springframework.security.core.userdetails.UserDetails;
+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;
+
+/**
+ * @author xduo
+ */
+@Controller
+@RequestMapping(value = "/projects")
+public class ProjectControllerV2 extends BasicController {
+    private static final Logger logger = 
LoggerFactory.getLogger(ProjectControllerV2.class);
+
+    private static final char[] VALID_PROJECTNAME = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
+
+    @Autowired
+    @Qualifier("projectServiceV2")
+    private ProjectServiceV2 projectServiceV2;
+
+    @Autowired
+    @Qualifier("accessService")
+    private AccessService accessService;
+
+    @Autowired
+    private AclUtil aclUtil;
+
+    @Autowired
+    @Qualifier("cubeMgmtServiceV2")
+    private CubeServiceV2 cubeServiceV2;
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getProjectsV2(@RequestHeader("Accept-Language") 
String lang, @RequestParam(value = "pageOffset", required = false, defaultValue 
= "0") Integer pageOffset, @RequestParam(value = "pageSize", required = false, 
defaultValue = "10") Integer pageSize) {
+        MsgPicker.setMsg(lang);
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
projectServiceV2.listProjects(limit, offset), "");
+    }
+
+    @RequestMapping(value = "/readable", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
getReadableProjectsV2(@RequestHeader("Accept-Language") String lang, 
@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<ProjectInstance> readableProjects = new 
ArrayList<ProjectInstance>();
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        //list all projects first
+        List<ProjectInstance> projectInstances = 
projectServiceV2.getProjectManager().listAllProjects();
+
+        if (projectInstances.size() <= offset) {
+            offset = projectInstances.size();
+            limit = 0;
+        }
+
+        if ((projectInstances.size() - offset) < limit) {
+            limit = projectInstances.size() - offset;
+        }
+
+        //get user infomation
+        UserDetails userDetails = aclUtil.getCurrentUser();
+        String userName = userDetails.getUsername();
+
+        //check if ROLE_ADMIN return all,also get user role list
+        List<String> userAuthority = aclUtil.getAuthorityList();
+        for (String auth : userAuthority) {
+            if (auth.equals(Constant.ROLE_ADMIN)) {
+                data.put("readableProjects", projectInstances.subList(offset, 
offset + limit));
+                data.put("size", projectInstances.size());
+                return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, 
"");
+            }
+        }
+
+        for (ProjectInstance projectInstance : projectInstances) {
+            if (projectInstance == null) {
+                continue;
+            }
+
+            boolean hasProjectPermission = false;
+            AclEntity ae = accessService.getAclEntity("ProjectInstance", 
projectInstance.getId());
+            Acl projectAcl = accessService.getAcl(ae);
+            //project no Acl info will be skipped
+            if (projectAcl != null) {
+
+                //project owner has permission
+                if (((PrincipalSid) 
projectAcl.getOwner()).getPrincipal().equals(userName)) {
+                    readableProjects.add(projectInstance);
+                    continue;
+                }
+
+                //check project permission and role
+                for (AccessControlEntry ace : projectAcl.getEntries()) {
+                    if (ace.getSid() instanceof PrincipalSid && 
((PrincipalSid) ace.getSid()).getPrincipal().equals(userName)) {
+                        hasProjectPermission = true;
+                        readableProjects.add(projectInstance);
+                        break;
+
+                    } else if (ace.getSid() instanceof GrantedAuthoritySid) {
+                        String projectAuthority = ((GrantedAuthoritySid) 
ace.getSid()).getGrantedAuthority();
+                        if (userAuthority.contains(projectAuthority)) {
+                            hasProjectPermission = true;
+                            readableProjects.add(projectInstance);
+                            break;
+                        }
+
+                    }
+
+                }
+            }
+
+            if (!hasProjectPermission) {
+                List<CubeInstance> cubeInstances = 
cubeServiceV2.listAllCubes(projectInstance.getName());
+
+                for (CubeInstance cubeInstance : cubeInstances) {
+                    if (cubeInstance == null) {
+                        continue;
+                    }
+
+                    if (aclUtil.isHasCubePermission(cubeInstance)) {
+                        hasProjectPermission = true;
+                        break;
+                    }
+                }
+                if (hasProjectPermission) {
+                    readableProjects.add(projectInstance);
+                }
+            }
+
+        }
+
+        if (readableProjects.size() <= offset) {
+            offset = readableProjects.size();
+            limit = 0;
+        }
+
+        if ((readableProjects.size() - offset) < limit) {
+            limit = readableProjects.size() - offset;
+        }
+        data.put("readableProjects", readableProjects.subList(offset, offset + 
limit));
+        data.put("size", readableProjects.size());
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse saveProjectV2(@RequestHeader("Accept-Language") 
String lang, @RequestBody ProjectRequest projectRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        ProjectInstance projectDesc = deserializeProjectDescV2(projectRequest);
+
+        if (StringUtils.isEmpty(projectDesc.getName())) {
+            throw new BadRequestException(msg.getEMPTY_PROJECT_NAME());
+        }
+
+        if (!StringUtils.containsOnly(projectDesc.getName(), 
VALID_PROJECTNAME)) {
+            logger.info("Invalid Project name {}, only letters, numbers and 
underline supported.", projectDesc.getName());
+            throw new 
BadRequestException(String.format(msg.getINVALID_PROJECT_NAME(), 
projectDesc.getName()));
+        }
+
+        ProjectInstance createdProj = null;
+        createdProj = projectServiceV2.createProject(projectDesc);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, createdProj, 
"");
+    }
+
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse updateProjectV2(@RequestHeader("Accept-Language") 
String lang, @RequestBody ProjectRequest projectRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        String formerProjectName = projectRequest.getFormerProjectName();
+        if (StringUtils.isEmpty(formerProjectName)) {
+            throw new BadRequestException(msg.getEMPTY_PROJECT_NAME());
+        }
+
+        ProjectInstance projectDesc = deserializeProjectDescV2(projectRequest);
+
+        ProjectInstance updatedProj = null;
+
+        ProjectInstance currentProject = 
projectServiceV2.getProjectManager().getProject(formerProjectName);
+        if (currentProject == null) {
+            throw new 
BadRequestException(String.format(msg.getPROJECT_NOT_FOUND(), 
formerProjectName));
+        }
+
+        updatedProj = projectServiceV2.updateProject(projectDesc, 
currentProject);
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, updatedProj, 
"");
+    }
+
+    private ProjectInstance deserializeProjectDescV2(ProjectRequest 
projectRequest) throws IOException {
+        ProjectInstance projectDesc = null;
+        logger.debug("Saving project " + projectRequest.getProjectDescData());
+        projectDesc = JsonUtil.readValue(projectRequest.getProjectDescData(), 
ProjectInstance.class);
+        return projectDesc;
+    }
+
+    @RequestMapping(value = "/{projectName}", method = { RequestMethod.DELETE 
}, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void deleteProjectV2(@RequestHeader("Accept-Language") String lang, 
@PathVariable String projectName) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        ProjectInstance project = 
projectServiceV2.getProjectManager().getProject(projectName);
+        projectServiceV2.deleteProject(projectName, project);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java
new file mode 100644
index 0000000..a279619
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/QueryControllerV2.java
@@ -0,0 +1,186 @@
+/*
+ * 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.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.apache.kylin.rest.model.Query;
+import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.MetaRequest;
+import org.apache.kylin.rest.request.PrepareSqlRequest;
+import org.apache.kylin.rest.request.SQLRequest;
+import org.apache.kylin.rest.request.SaveSqlRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.apache.kylin.rest.service.QueryServiceV2;
+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 org.supercsv.io.CsvListWriter;
+import org.supercsv.io.ICsvListWriter;
+import org.supercsv.prefs.CsvPreference;
+
+/**
+ * Handle query requests.
+ * 
+ * @author xduo
+ */
+@Controller
+public class QueryControllerV2 extends BasicController {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(QueryControllerV2.class);
+
+    @Autowired
+    @Qualifier("queryServiceV2")
+    private QueryServiceV2 queryServiceV2;
+
+    @RequestMapping(value = "/query", method = RequestMethod.POST, produces = 
{ "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse queryV2(@RequestHeader("Accept-Language") String 
lang, @RequestBody SQLRequest sqlRequest) {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
queryServiceV2.doQueryWithCache(sqlRequest), "");
+    }
+
+    // TODO should be just "prepare" a statement, get back expected 
ResultSetMetaData
+
+    @RequestMapping(value = "/query/prestate", method = RequestMethod.POST, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse prepareQueryV2(@RequestHeader("Accept-Language") 
String lang, @RequestBody PrepareSqlRequest sqlRequest) {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
queryServiceV2.doQueryWithCache(sqlRequest), "");
+    }
+
+    @RequestMapping(value = "/saved_queries", method = RequestMethod.POST, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void saveQueryV2(@RequestHeader("Accept-Language") String lang, 
@RequestBody SaveSqlRequest sqlRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        String creator = 
SecurityContextHolder.getContext().getAuthentication().getName();
+        Query newQuery = new Query(sqlRequest.getName(), 
sqlRequest.getProject(), sqlRequest.getSql(), sqlRequest.getDescription());
+
+        queryServiceV2.saveQuery(creator, newQuery);
+    }
+
+    @RequestMapping(value = "/saved_queries/{id}", method = 
RequestMethod.DELETE, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void removeQueryV2(@RequestHeader("Accept-Language") String lang, 
@PathVariable String id) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        String creator = 
SecurityContextHolder.getContext().getAuthentication().getName();
+        queryServiceV2.removeQuery(creator, id);
+    }
+
+    @RequestMapping(value = "/saved_queries/{project}", method = 
RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getQueriesV2(@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>();
+        String creator = 
SecurityContextHolder.getContext().getAuthentication().getName();
+        List<Query> queries = new ArrayList<Query>();
+        for (Query query : queryServiceV2.getQueries(creator)) {
+            if (query.getProject().equals(project))
+                queries.add(query);
+        }
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        if (queries.size() <= offset) {
+            offset = queries.size();
+            limit = 0;
+        }
+
+        if ((queries.size() - offset) < limit) {
+            limit = queries.size() - offset;
+        }
+
+        data.put("queries", queries.subList(offset, offset + limit));
+        data.put("size", queries.size());
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+    }
+
+    @RequestMapping(value = "/query/format/{format}", method = 
RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void downloadQueryResultV2(@RequestHeader("Accept-Language") String 
lang, @PathVariable String format, SQLRequest sqlRequest, HttpServletResponse 
response) {
+        MsgPicker.setMsg(lang);
+
+        SQLResponse result = queryServiceV2.doQueryWithCache(sqlRequest);
+        response.setContentType("text/" + format + ";charset=utf-8");
+        response.setHeader("Content-Disposition", "attachment; 
filename=\"result." + format + "\"");
+        ICsvListWriter csvWriter = null;
+
+        try {
+            csvWriter = new CsvListWriter(response.getWriter(), 
CsvPreference.STANDARD_PREFERENCE);
+
+            List<String> headerList = new ArrayList<String>();
+
+            for (SelectedColumnMeta column : result.getColumnMetas()) {
+                headerList.add(column.getName());
+            }
+
+            String[] headers = new String[headerList.size()];
+            csvWriter.writeHeader(headerList.toArray(headers));
+
+            for (List<String> row : result.getResults()) {
+                csvWriter.write(row);
+            }
+        } catch (IOException e) {
+            throw new InternalErrorException(e);
+        } finally {
+            IOUtils.closeQuietly(csvWriter);
+        }
+    }
+
+    @RequestMapping(value = "/tables_and_columns", method = RequestMethod.GET, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getMetadataV2(@RequestHeader("Accept-Language") 
String lang, MetaRequest metaRequest) throws SQLException, IOException {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
queryServiceV2.getMetadataV2(metaRequest.getProject()), "");
+    }
+
+    public void setQueryService(QueryServiceV2 queryService) {
+        this.queryServiceV2 = queryService;
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/StreamingControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/StreamingControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/StreamingControllerV2.java
new file mode 100644
index 0000000..b810d0a
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/StreamingControllerV2.java
@@ -0,0 +1,288 @@
+/*
+ * 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.UUID;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.util.HadoopUtil;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.metadata.model.TableDesc;
+import org.apache.kylin.metadata.streaming.StreamingConfig;
+import org.apache.kylin.rest.controller.BasicController;
+import org.apache.kylin.rest.exception.BadRequestException;
+import org.apache.kylin.rest.exception.ForbiddenException;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.apache.kylin.rest.msg.Message;
+import org.apache.kylin.rest.msg.MsgPicker;
+import org.apache.kylin.rest.request.StreamingRequest;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.KafkaConfigService;
+import org.apache.kylin.rest.service.StreamingService;
+import org.apache.kylin.rest.service.TableServiceV2;
+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;
+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.databind.JsonMappingException;
+
+/**
+ * StreamingController is defined as Restful API entrance for UI.
+ *
+ * @author jiazhong
+ */
+@Controller
+@RequestMapping(value = "/streaming")
+public class StreamingControllerV2 extends BasicController {
+    private static final Logger logger = 
LoggerFactory.getLogger(StreamingControllerV2.class);
+
+    @Autowired
+    @Qualifier("streamingMgmtService")
+    private StreamingService streamingService;
+
+    @Autowired
+    @Qualifier("kafkaMgmtService")
+    private KafkaConfigService kafkaConfigService;
+
+    @Autowired
+    @Qualifier("tableServiceV2")
+    private TableServiceV2 tableServiceV2;
+
+    @RequestMapping(value = "/getConfig", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getStreamingsV2(@RequestHeader("Accept-Language") 
String lang, @RequestParam(value = "table", required = false) String table, 
@RequestParam(value = "pageOffset", required = false, defaultValue = "0") 
Integer pageOffset, @RequestParam(value = "pageSize", required = false, 
defaultValue = "10") Integer pageSize) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
streamingService.getStreamingConfigs(table, limit, offset), "");
+    }
+
+    @RequestMapping(value = "/getKfkConfig", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
getKafkaConfigsV2(@RequestHeader("Accept-Language") String lang, 
@RequestParam(value = "kafkaConfigName", required = false) String 
kafkaConfigName, @RequestParam(value = "pageOffset", required = false, 
defaultValue = "0") Integer pageOffset, @RequestParam(value = "pageSize", 
required = false, defaultValue = "10") Integer pageSize) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        int offset = pageOffset * pageSize;
+        int limit = pageSize;
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
kafkaConfigService.getKafkaConfigs(kafkaConfigName, limit, offset), "");
+    }
+
+    /**
+     *
+     * create Streaming Schema
+     * @throws java.io.IOException
+     */
+
+    @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void saveStreamingConfigV2(@RequestHeader("Accept-Language") String 
lang, @RequestBody StreamingRequest streamingRequest) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        String project = streamingRequest.getProject();
+        TableDesc tableDesc = deserializeTableDescV2(streamingRequest);
+        if (null == tableDesc) {
+            throw new 
BadRequestException(msg.getINVALID_TABLE_DESC_DEFINITION());
+        }
+
+        StreamingConfig streamingConfig = 
deserializeSchemalDescV2(streamingRequest);
+        KafkaConfig kafkaConfig = 
deserializeKafkaSchemalDescV2(streamingRequest);
+
+        boolean saveStreamingSuccess = false, saveKafkaSuccess = false;
+
+        try {
+            tableServiceV2.addStreamingTable(tableDesc, project);
+        } catch (IOException e) {
+            throw new 
InternalErrorException(msg.getADD_STREAMING_TABLE_FAIL());
+        }
+
+        streamingConfig.setName(tableDesc.getIdentity());
+        kafkaConfig.setName(tableDesc.getIdentity());
+        try {
+            if (StringUtils.isEmpty(streamingConfig.getName())) {
+                logger.info("StreamingConfig should not be empty.");
+                throw new 
BadRequestException(msg.getEMPTY_STREAMING_CONFIG_NAME());
+            }
+            try {
+                streamingConfig.setUuid(UUID.randomUUID().toString());
+                streamingService.createStreamingConfig(streamingConfig);
+                saveStreamingSuccess = true;
+            } catch (IOException e) {
+                logger.error("Failed to save StreamingConfig:" + 
e.getLocalizedMessage(), e);
+                throw new 
InternalErrorException(msg.getSAVE_STREAMING_CONFIG_FAIL());
+            }
+            try {
+                kafkaConfig.setUuid(UUID.randomUUID().toString());
+                kafkaConfigService.createKafkaConfig(kafkaConfig);
+                saveKafkaSuccess = true;
+            } catch (IOException e) {
+                try {
+                    streamingService.dropStreamingConfig(streamingConfig);
+                } catch (IOException e1) {
+                    throw new 
InternalErrorException(msg.getCREATE_KAFKA_CONFIG_FAIL());
+                }
+                logger.error("Failed to save KafkaConfig:" + 
e.getLocalizedMessage(), e);
+                throw new 
InternalErrorException(msg.getSAVE_KAFKA_CONFIG_FAIL());
+            }
+        } finally {
+            if (saveKafkaSuccess == false || saveStreamingSuccess == false) {
+
+                if (saveStreamingSuccess == true) {
+                    StreamingConfig sConfig = 
streamingService.getStreamingManager().getStreamingConfig(streamingConfig.getName());
+                    try {
+                        streamingService.dropStreamingConfig(sConfig);
+                    } catch (IOException e) {
+                        throw new 
InternalErrorException(msg.getROLLBACK_STREAMING_CONFIG_FAIL());
+                    }
+                }
+                if (saveKafkaSuccess == true) {
+                    try {
+                        KafkaConfig kConfig = 
kafkaConfigService.getKafkaConfig(kafkaConfig.getName());
+                        kafkaConfigService.dropKafkaConfig(kConfig);
+                    } catch (IOException e) {
+                        throw new 
InternalErrorException(msg.getROLLBACK_KAFKA_CONFIG_FAIL());
+                    }
+                }
+            }
+
+        }
+    }
+
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void updateStreamingConfigV2(@RequestHeader("Accept-Language") 
String lang, @RequestBody StreamingRequest streamingRequest) throws IOException 
{
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        StreamingConfig streamingConfig = 
deserializeSchemalDescV2(streamingRequest);
+        KafkaConfig kafkaConfig = 
deserializeKafkaSchemalDescV2(streamingRequest);
+
+        if (streamingConfig == null) {
+            throw new 
BadRequestException(msg.getINVALID_STREAMING_CONFIG_DEFINITION());
+        }
+        try {
+            streamingService.updateStreamingConfig(streamingConfig);
+        } catch (AccessDeniedException accessDeniedException) {
+            throw new 
ForbiddenException(msg.getUPDATE_STREAMING_CONFIG_NO_RIGHT());
+        }
+
+        try {
+            kafkaConfigService.updateKafkaConfig(kafkaConfig);
+        } catch (AccessDeniedException accessDeniedException) {
+            throw new 
ForbiddenException(msg.getUPDATE_KAFKA_CONFIG_NO_RIGHT());
+        }
+    }
+
+    @RequestMapping(value = "/{configName}", method = { RequestMethod.DELETE 
}, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void deleteConfigV2(@RequestHeader("Accept-Language") String lang, 
@PathVariable String configName) throws IOException {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        StreamingConfig config = 
streamingService.getStreamingManager().getStreamingConfig(configName);
+        KafkaConfig kafkaConfig = 
kafkaConfigService.getKafkaConfig(configName);
+        if (null == config) {
+            throw new 
BadRequestException(String.format(msg.getSTREAMING_CONFIG_NOT_FOUND(), 
configName));
+        }
+        streamingService.dropStreamingConfig(config);
+        kafkaConfigService.dropKafkaConfig(kafkaConfig);
+    }
+
+    private TableDesc deserializeTableDescV2(StreamingRequest 
streamingRequest) throws IOException {
+        Message msg = MsgPicker.getMsg();
+
+        TableDesc desc = null;
+        try {
+            logger.debug("Saving TableDesc " + 
streamingRequest.getTableData());
+            desc = JsonUtil.readValue(streamingRequest.getTableData(), 
TableDesc.class);
+        } catch (JsonParseException e) {
+            logger.error("The TableDesc definition is invalid.", e);
+            throw new 
BadRequestException(msg.getINVALID_TABLE_DESC_DEFINITION());
+        } catch (JsonMappingException e) {
+            logger.error("The data TableDesc definition is invalid.", e);
+            throw new 
BadRequestException(msg.getINVALID_TABLE_DESC_DEFINITION());
+        }
+
+        if (null != desc) {
+            String[] dbTable = HadoopUtil.parseHiveTableName(desc.getName());
+            desc.setName(dbTable[1]);
+            desc.setDatabase(dbTable[0]);
+            desc.getIdentity();
+        }
+        return desc;
+    }
+
+    private StreamingConfig deserializeSchemalDescV2(StreamingRequest 
streamingRequest) throws IOException {
+        Message msg = MsgPicker.getMsg();
+
+        StreamingConfig desc = null;
+        try {
+            logger.debug("Saving StreamingConfig " + 
streamingRequest.getStreamingConfig());
+            desc = JsonUtil.readValue(streamingRequest.getStreamingConfig(), 
StreamingConfig.class);
+        } catch (JsonParseException e) {
+            logger.error("The StreamingConfig definition is invalid.", e);
+            throw new 
BadRequestException(msg.getINVALID_STREAMING_CONFIG_DEFINITION());
+        } catch (JsonMappingException e) {
+            logger.error("The data StreamingConfig definition is invalid.", e);
+            throw new 
BadRequestException(msg.getINVALID_STREAMING_CONFIG_DEFINITION());
+        }
+        return desc;
+    }
+
+    private KafkaConfig deserializeKafkaSchemalDescV2(StreamingRequest 
streamingRequest) throws IOException {
+        Message msg = MsgPicker.getMsg();
+
+        KafkaConfig desc = null;
+        try {
+            logger.debug("Saving KafkaConfig " + 
streamingRequest.getKafkaConfig());
+            desc = JsonUtil.readValue(streamingRequest.getKafkaConfig(), 
KafkaConfig.class);
+        } catch (JsonParseException e) {
+            logger.error("The KafkaConfig definition is invalid.", e);
+            throw new 
BadRequestException(msg.getINVALID_KAFKA_CONFIG_DEFINITION());
+        } catch (JsonMappingException e) {
+            logger.error("The data KafkaConfig definition is invalid.", e);
+            updateRequest(streamingRequest, false, e.getMessage());
+            throw new 
BadRequestException(msg.getINVALID_KAFKA_CONFIG_DEFINITION());
+        }
+        return desc;
+    }
+
+    private void updateRequest(StreamingRequest request, boolean success, 
String message) {
+        request.setSuccessful(success);
+        request.setMessage(message);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/TableControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/TableControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/TableControllerV2.java
new file mode 100644
index 0000000..4a4bf74
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/TableControllerV2.java
@@ -0,0 +1,159 @@
+/*
+ * 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 org.apache.kylin.metadata.model.TableDesc;
+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.HiveTableRequestV2;
+import org.apache.kylin.rest.response.EnvelopeResponse;
+import org.apache.kylin.rest.response.ResponseCode;
+import org.apache.kylin.rest.service.TableServiceV2;
+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 java.io.IOException;
+
+/**
+ * @author xduo
+ */
+@Controller
+@RequestMapping(value = "/tables")
+public class TableControllerV2 extends BasicController {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(TableControllerV2.class);
+
+    @Autowired
+    @Qualifier("tableServiceV2")
+    private TableServiceV2 tableServiceV2;
+
+    /**
+     * Get available table list of the project
+     *
+     * @return Table metadata array
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getTableDescV2(@RequestHeader("Accept-Language") 
String lang, @RequestParam(value = "ext", required = false) boolean withExt, 
@RequestParam(value = "project", required = true) String project) throws 
IOException {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
tableServiceV2.getTableDescByProject(project, withExt), "");
+    }
+
+    /**
+     * Get available table list of the input database
+     *
+     * @return Table metadata array
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/{tableName:.+}", method = { RequestMethod.GET }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getTableDescV2(@RequestHeader("Accept-Language") 
String lang, @PathVariable String tableName) {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        TableDesc table = tableServiceV2.getTableDescByName(tableName, false);
+        if (table == null)
+            throw new 
BadRequestException(String.format(msg.getHIVE_TABLE_NOT_FOUND(), tableName));
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, table, "");
+    }
+
+    @RequestMapping(value = "/load", method = { RequestMethod.POST }, produces 
= { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse loadHiveTablesV2(@RequestHeader("Accept-Language") 
String lang, @RequestBody HiveTableRequestV2 requestV2) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
tableServiceV2.loadHiveTables(requestV2.getTables(), requestV2.getProject(), 
requestV2.isNeedProfile()), "");
+    }
+
+    @RequestMapping(value = "/load", method = { RequestMethod.DELETE }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
unLoadHiveTablesV2(@RequestHeader("Accept-Language") String lang, @RequestBody 
HiveTableRequestV2 requestV2) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
tableServiceV2.unloadHiveTables(requestV2.getTables(), requestV2.getProject()), 
"");
+    }
+
+    /**
+     * Regenerate table cardinality
+     *
+     * @return Table metadata array
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/cardinality", method = { RequestMethod.POST }, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public void generateCardinalityV2(@RequestHeader("Accept-Language") String 
lang, @RequestBody HiveTableRequestV2 requestV2) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        String submitter = 
SecurityContextHolder.getContext().getAuthentication().getName();
+        String[] tables = requestV2.getTables();
+
+        for (String table : tables) {
+            tableServiceV2.calculateCardinality(table.toUpperCase(), 
submitter);
+        }
+    }
+
+    /**
+     * Show all databases in Hive
+     *
+     * @return Hive databases list
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/hive", method = { RequestMethod.GET }, produces 
= { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    private EnvelopeResponse 
showHiveDatabasesV2(@RequestHeader("Accept-Language") String lang) throws 
Exception {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
tableServiceV2.getHiveDbNames(), "");
+    }
+
+    /**
+     * Show all tables in a Hive database
+     *
+     * @return Hive table list
+     * @throws IOException
+     */
+
+    @RequestMapping(value = "/hive/{database}", method = { RequestMethod.GET 
}, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    private EnvelopeResponse 
showHiveTablesV2(@RequestHeader("Accept-Language") String lang, @PathVariable 
String database) throws Exception {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
tableServiceV2.getHiveTableNames(database), "");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller2/UserControllerV2.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller2/UserControllerV2.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/UserControllerV2.java
new file mode 100644
index 0000000..437caa1
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller2/UserControllerV2.java
@@ -0,0 +1,103 @@
+/*
+ * 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.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.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;
+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;
+
+/**
+ * Handle user authentication request to protected kylin rest resources by
+ * spring security.
+ * 
+ * @author xduo
+ * 
+ */
+@Controller
+@RequestMapping(value = "/user")
+public class UserControllerV2 extends BasicController {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(UserControllerV2.class);
+
+    @Autowired
+    @Qualifier("userService")
+    UserService userService;
+
+    @RequestMapping(value = "/authentication", method = RequestMethod.POST, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse authenticateV2(@RequestHeader("Accept-Language") 
String lang) {
+        return authenticatedUserV2(lang);
+    }
+
+    @RequestMapping(value = "/authentication", method = RequestMethod.GET, 
produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse 
authenticatedUserV2(@RequestHeader("Accept-Language") String lang) {
+        MsgPicker.setMsg(lang);
+        Message msg = MsgPicker.getMsg();
+
+        Authentication authentication = 
SecurityContextHolder.getContext().getAuthentication();
+        UserDetails data = null;
+
+        if (authentication == null) {
+            logger.debug("authentication is null.");
+            throw new BadRequestException(msg.getAUTH_INFO_NOT_FOUND());
+        }
+
+        if (authentication.getPrincipal() instanceof UserDetails) {
+            logger.debug("authentication.getPrincipal() is " + 
authentication.getPrincipal());
+            data = (UserDetails) authentication.getPrincipal();
+            return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+        }
+
+        if (authentication.getDetails() instanceof UserDetails) {
+            logger.debug("authentication.getDetails() is " + 
authentication.getDetails());
+            data = (UserDetails) authentication.getDetails();
+            return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, data, "");
+        }
+
+        throw new BadRequestException(msg.getAUTH_INFO_NOT_FOUND());
+    }
+
+    @RequestMapping(value = "/authentication/authorities", method = 
RequestMethod.GET, produces = { "application/vnd.apache.kylin-v2+json" })
+    @ResponseBody
+    public EnvelopeResponse getAuthoritiesV2(@RequestHeader("Accept-Language") 
String lang) throws IOException {
+        MsgPicker.setMsg(lang);
+
+        return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
userService.listUserAuthorities(), "");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/exception/BadRequestException.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/exception/BadRequestException.java
 
b/server-base/src/main/java/org/apache/kylin/rest/exception/BadRequestException.java
index af1995b..53d619a 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/exception/BadRequestException.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/exception/BadRequestException.java
@@ -51,6 +51,7 @@ public class BadRequestException extends RuntimeException {
         this.code = code;
     }
 
+
     public String getCode() {
         return code;
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMeta.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMeta.java 
b/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMeta.java
index 15afb2e..ed52ae6 100644
--- a/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMeta.java
+++ b/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMeta.java
@@ -24,29 +24,29 @@ import java.io.Serializable;
  */
 public class ColumnMeta implements Serializable {
     private static final long serialVersionUID = 1L;
-    private String TABLE_CAT;
-    private String TABLE_SCHEM;
-    private String TABLE_NAME;
-    private String COLUMN_NAME;
-    private int DATA_TYPE;
-    private String TYPE_NAME;
-    private int COLUMN_SIZE;
-    private int BUFFER_LENGTH;
-    private int DECIMAL_DIGITS;
-    private int NUM_PREC_RADIX;
-    private int NULLABLE;
-    private String REMARKS;
-    private String COLUMN_DEF;
-    private int SQL_DATA_TYPE;
-    private int SQL_DATETIME_SUB;
-    private int CHAR_OCTET_LENGTH;
-    private int ORDINAL_POSITION;
-    private String IS_NULLABLE;
-    private String SCOPE_CATLOG;
-    private String SCOPE_SCHEMA;
-    private String SCOPE_TABLE;
-    private short SOURCE_DATA_TYPE;
-    private String IS_AUTOINCREMENT;
+    protected String TABLE_CAT;
+    protected String TABLE_SCHEM;
+    protected String TABLE_NAME;
+    protected String COLUMN_NAME;
+    protected int DATA_TYPE;
+    protected String TYPE_NAME;
+    protected int COLUMN_SIZE;
+    protected int BUFFER_LENGTH;
+    protected int DECIMAL_DIGITS;
+    protected int NUM_PREC_RADIX;
+    protected int NULLABLE;
+    protected String REMARKS;
+    protected String COLUMN_DEF;
+    protected int SQL_DATA_TYPE;
+    protected int SQL_DATETIME_SUB;
+    protected int CHAR_OCTET_LENGTH;
+    protected int ORDINAL_POSITION;
+    protected String IS_NULLABLE;
+    protected String SCOPE_CATLOG;
+    protected String SCOPE_SCHEMA;
+    protected String SCOPE_TABLE;
+    protected short SOURCE_DATA_TYPE;
+    protected String IS_AUTOINCREMENT;
 
     public ColumnMeta() {
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMetaWithType.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMetaWithType.java 
b/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMetaWithType.java
new file mode 100644
index 0000000..4d3abb8
--- /dev/null
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/model/ColumnMetaWithType.java
@@ -0,0 +1,70 @@
+/*
+ * 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.model;
+
+import java.io.Serializable;
+import java.util.HashSet;
+
+/**
+ * Created by luwei on 17-4-26.
+ */
+public class ColumnMetaWithType extends ColumnMeta {
+    public static enum columnTypeEnum implements Serializable {
+
+        DIMENSION, MEASURE, PK, FK
+
+    }
+
+    private HashSet<columnTypeEnum> TYPE;
+
+    public ColumnMetaWithType(String tABLE_CAT, String tABLE_SCHEM, String 
tABLE_NAME, String cOLUMN_NAME, int dATA_TYPE, String tYPE_NAME, int 
cOLUMN_SIZE, int bUFFER_LENGTH, int dECIMAL_DIGITS, int nUM_PREC_RADIX, int 
nULLABLE, String rEMARKS, String cOLUMN_DEF, int sQL_DATA_TYPE, int 
sQL_DATETIME_SUB, int cHAR_OCTET_LENGTH, int oRDINAL_POSITION, String 
iS_NULLABLE, String sCOPE_CATLOG, String sCOPE_SCHEMA, String sCOPE_TABLE, 
short sOURCE_DATA_TYPE, String iS_AUTOINCREMENT) {
+        TABLE_CAT = tABLE_CAT;
+        TABLE_SCHEM = tABLE_SCHEM;
+        TABLE_NAME = tABLE_NAME;
+        COLUMN_NAME = cOLUMN_NAME;
+        DATA_TYPE = dATA_TYPE;
+        TYPE_NAME = tYPE_NAME;
+        COLUMN_SIZE = cOLUMN_SIZE;
+        BUFFER_LENGTH = bUFFER_LENGTH;
+        DECIMAL_DIGITS = dECIMAL_DIGITS;
+        NUM_PREC_RADIX = nUM_PREC_RADIX;
+        NULLABLE = nULLABLE;
+        REMARKS = rEMARKS;
+        COLUMN_DEF = cOLUMN_DEF;
+        SQL_DATA_TYPE = sQL_DATA_TYPE;
+        SQL_DATETIME_SUB = sQL_DATETIME_SUB;
+        CHAR_OCTET_LENGTH = cHAR_OCTET_LENGTH;
+        ORDINAL_POSITION = oRDINAL_POSITION;
+        IS_NULLABLE = iS_NULLABLE;
+        SCOPE_CATLOG = sCOPE_CATLOG;
+        SCOPE_SCHEMA = sCOPE_SCHEMA;
+        SCOPE_TABLE = sCOPE_TABLE;
+        SOURCE_DATA_TYPE = sOURCE_DATA_TYPE;
+        IS_AUTOINCREMENT = iS_AUTOINCREMENT;
+        TYPE = new HashSet<columnTypeEnum>();
+    }
+
+    public HashSet<columnTypeEnum> getTYPE() {
+        return TYPE;
+    }
+
+    public void setTYPE(HashSet<columnTypeEnum> TYPE) {
+        this.TYPE = TYPE;
+    }
+}

Reply via email to