You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by ma...@apache.org on 2015/05/15 07:21:49 UTC

[20/52] [abbrv] incubator-kylin git commit: add model service&controller backend

add model service&controller backend


Project: http://git-wip-us.apache.org/repos/asf/incubator-kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kylin/commit/286e5203
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kylin/tree/286e5203
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kylin/diff/286e5203

Branch: refs/heads/0.8.0
Commit: 286e52036ff0aec8fa2118561eac7a21eac755b0
Parents: be5b810
Author: jiazhong <ji...@ebay.com>
Authored: Thu Mar 12 17:49:27 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:35:49 2015 +0800

----------------------------------------------------------------------
 .../apache/kylin/metadata/MetadataManager.java  |  11 +-
 .../kylin/rest/controller/CubeController.java   |  69 +--------
 .../kylin/rest/controller/ModelController.java  | 149 +++++++++++++++----
 .../rest/controller/ModelDescController.java    |  61 ++++++++
 .../apache/kylin/rest/request/CubeRequest.java  |  29 +---
 .../apache/kylin/rest/request/ModelRequest.java | 109 ++++++++++++++
 .../apache/kylin/rest/service/ModelService.java | 118 +++++++++++++++
 .../rest/controller/CubeControllerTest.java     |   7 -
 8 files changed, 420 insertions(+), 133 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java b/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
index b5a3e96..9d489e2 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
@@ -22,11 +22,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -286,6 +282,11 @@ public class MetadataManager {
         return dataModelDescMap.get(name);
     }
 
+    public List<DataModelDesc> getModels() {
+        return new ArrayList<DataModelDesc>(dataModelDescMap.values());
+    }
+
+
     private void reloadAllDataModel() throws IOException {
         ResourceStore store = getStore();
         logger.debug("Reloading DataModel from folder " + store.getReadableResourcePath(ResourceStore.DATA_MODEL_DESC_RESOURCE_ROOT));

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java b/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
index 231c834..d4cef18 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/CubeController.java
@@ -122,7 +122,6 @@ public class CubeController extends BasicController {
      * @param cubeName
      * @param notifyList
      * @throws IOException
-     * @throws CubeIntegrityException
      */
     @RequestMapping(value = "/{cubeName}/notify_list", method = {RequestMethod.PUT})
     @ResponseBody
@@ -283,7 +282,7 @@ public class CubeController extends BasicController {
     }
 
     /**
-     * Get available table list of the input database
+     *save cubeDesc
      *
      * @return Table metadata array
      * @throws IOException
@@ -292,26 +291,6 @@ public class CubeController extends BasicController {
     @ResponseBody
     @Metered(name = "saveCube")
     public CubeRequest saveCubeDesc(@RequestBody CubeRequest cubeRequest) {
-        //Update Model 
-        MetadataManager metaManager = MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
-        DataModelDesc modelDesc = deserializeDataModelDesc(cubeRequest);
-        if (modelDesc == null || StringUtils.isEmpty(modelDesc.getName())) {
-            return cubeRequest;
-        }
-
-        try {
-            DataModelDesc existingModel = metaManager.getDataModelDesc(modelDesc.getName());
-            if (existingModel == null) {
-                metaManager.createDataModelDesc(modelDesc);
-            } else {
-                modelDesc.setLastModified(existingModel.getLastModified());
-                metaManager.updateDataModelDesc(modelDesc);
-            }
-        } catch (IOException e) {
-            // TODO Auto-generated catch block
-            logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
-            throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
-        }
 
         CubeDesc desc = deserializeCubeDesc(cubeRequest);
         if (desc == null) {
@@ -339,7 +318,7 @@ public class CubeController extends BasicController {
     }
 
     /**
-     * Get available table list of the input database
+     * update CubDesc
      *
      * @return Table metadata array
      * @throws JsonProcessingException
@@ -350,30 +329,6 @@ public class CubeController extends BasicController {
     @Metered(name = "updateCube")
     public CubeRequest updateCubeDesc(@RequestBody CubeRequest cubeRequest) throws JsonProcessingException {
 
-        //Update Model 
-        MetadataManager metaManager = MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
-        DataModelDesc modelDesc = deserializeDataModelDesc(cubeRequest);
-        if (modelDesc == null) {
-            return cubeRequest;
-        }
-        try {
-
-            DataModelDesc existingModel = metaManager.getDataModelDesc(modelDesc.getName());
-            if (existingModel == null) {
-                metaManager.createDataModelDesc(modelDesc);
-            } else {
-
-                //ignore overwriting conflict checking before splict MODEL & CUBE
-                modelDesc.setLastModified(existingModel.getLastModified());
-                metaManager.updateDataModelDesc(modelDesc);
-            }
-
-        } catch (IOException e) {
-            // TODO Auto-generated catch block
-            logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
-            throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
-        }
-
         //update cube
         CubeDesc desc = deserializeCubeDesc(cubeRequest);
 
@@ -413,7 +368,7 @@ public class CubeController extends BasicController {
     }
 
     /**
-     * Get available table list of the input database
+     *get Hbase Info
      *
      * @return true
      * @throws IOException
@@ -474,23 +429,7 @@ public class CubeController extends BasicController {
         return desc;
     }
 
-    private DataModelDesc deserializeDataModelDesc(CubeRequest cubeRequest) {
-        DataModelDesc desc = null;
-        try {
-            logger.debug("Saving MODEL " + cubeRequest.getModelDescData());
-            desc = JsonUtil.readValue(cubeRequest.getModelDescData(), DataModelDesc.class);
-        } catch (JsonParseException e) {
-            logger.error("The data model definition is not valid.", e);
-            updateRequest(cubeRequest, false, e.getMessage());
-        } catch (JsonMappingException e) {
-            logger.error("The data model definition is not valid.", e);
-            updateRequest(cubeRequest, false, e.getMessage());
-        } catch (IOException e) {
-            logger.error("Failed to deal with the request.", e);
-            throw new InternalErrorException("Failed to deal with the request:" + e.getMessage(), e);
-        }
-        return desc;
-    }
+
 
     /**
      * @return

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java b/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
index 2499f59..97a5d32 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/ModelController.java
@@ -18,50 +18,143 @@
 
 package org.apache.kylin.rest.controller;
 
-import java.io.IOException;
-
-import org.apache.kylin.rest.service.CubeService;
+import com.codahale.metrics.annotation.Metered;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.metadata.model.DataModelDesc;
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.rest.exception.BadRequestException;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.apache.kylin.rest.request.ModelRequest;
+import org.apache.kylin.rest.service.ModelService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 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.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.*;
 
-import org.apache.kylin.common.KylinConfig;
-import org.apache.kylin.metadata.MetadataManager;
-import org.apache.kylin.metadata.model.DataModelDesc;
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
 
 /**
+ * ModelController is defined as Restful API entrance for UI.
+ *
  * @author jiazhong
- * 
  */
 @Controller
-@RequestMapping(value = "/model")
-public class ModelController {
+@RequestMapping(value = "/models")
+public class ModelController extends BasicController {
+    private static final Logger logger = LoggerFactory.getLogger(ModelController.class);
 
     @Autowired
-    private CubeService cubeService;
+    private ModelService modelService;
+
+    @RequestMapping(value = "", method = {RequestMethod.GET})
+    @ResponseBody
+    @Metered(name = "listModels")
+    public List<DataModelDesc> getModels(@RequestParam(value = "modelName", required = false) String modelName, @RequestParam(value = "projectName", required = false) String projectName, @RequestParam("limit") Integer limit, @RequestParam("offset") Integer offset) {
+        return modelService.getModels(modelName, projectName, (null == limit) ? 20 : limit, offset);
+    }
+
+    @RequestMapping(value = "/{modelName}", method = {RequestMethod.DELETE})
+    @ResponseBody
+    @Metered(name = "deleteModel")
+    public void deleteModel(@PathVariable String modelName) {
+
+    }
 
     /**
-     * Get detail information of the "Cube ID"
-     * 
-     * @param cubeDescName
-     *            Cube ID
-     * @return
-     * @throws IOException
+     *
+     * create model
+     * @throws java.io.IOException
      */
-    @RequestMapping(value = "/{model_name}", method = { RequestMethod.GET })
+    @RequestMapping(value = "", method = {RequestMethod.POST})
     @ResponseBody
-    public DataModelDesc getModel(@PathVariable String model_name) {
-        MetadataManager metaManager= MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
-        DataModelDesc modeDesc = metaManager.getDataModelDesc(model_name);
-        return modeDesc;
-            
+    @Metered(name = "saveModel")
+    public ModelRequest saveModelDesc(@RequestBody ModelRequest modelRequest) {
+        //Update Model
+        DataModelDesc modelDesc = deserializeDataModelDesc(modelRequest);
+        if (modelDesc == null || StringUtils.isEmpty(modelDesc.getName())) {
+            return modelRequest;
+        }
+        if (StringUtils.isEmpty(modelDesc.getName())) {
+            logger.info("Model name should not be empty.");
+            throw new BadRequestException("Model name should not be empty.");
+        }
+
+        try {
+            modelDesc.setUuid(UUID.randomUUID().toString());
+            String projectName = (null == modelRequest.getProject()) ? ProjectInstance.DEFAULT_PROJECT_NAME : modelRequest.getProject();
+
+            modelService.createModelDesc(projectName, modelDesc);
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
+            throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
+        }
+
+        modelRequest.setUuid(modelDesc.getUuid());
+        modelRequest.setSuccessful(true);
+        return modelRequest;
+    }
+
+    @RequestMapping(value = "", method = {RequestMethod.PUT})
+    @ResponseBody
+    @Metered(name = "updateModel")
+    public ModelRequest updateModelDesc(@RequestBody ModelRequest modelRequest) throws JsonProcessingException {
+
+        //Update Model
+        DataModelDesc modelDesc = deserializeDataModelDesc(modelRequest);
+        if (modelDesc == null) {
+            return modelRequest;
+        }
+
+        try {
+            modelService.updateModelAndDesc(modelDesc,modelRequest.getProject());
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
+            throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
+        }
+
+        String descData = JsonUtil.writeValueAsIndentString(modelDesc);
+        modelRequest.setModelDescData(descData);
+
+        return modelRequest;
     }
 
-    public void setCubeService(CubeService cubeService) {
-        this.cubeService = cubeService;
+
+
+    private DataModelDesc deserializeDataModelDesc(ModelRequest modelRequest) {
+        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);
+            updateRequest(modelRequest, false, e.getMessage());
+        } catch (JsonMappingException e) {
+            logger.error("The data model definition is not valid.", e);
+            updateRequest(modelRequest, false, e.getMessage());
+        } catch (IOException e) {
+            logger.error("Failed to deal with the request.", e);
+            throw new InternalErrorException("Failed to deal with the request:" + e.getMessage(), e);
+        }
+        return desc;
     }
 
+    private void updateRequest(ModelRequest request, boolean success, String message) {
+        request.setModelDescData("");
+        request.setSuccessful(success);
+        request.setMessage(message);
+    }
+    public void setModelService(ModelService modelService) {
+        this.modelService = modelService;
+    }
+
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java b/server/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
new file mode 100644
index 0000000..fda7927
--- /dev/null
+++ b/server/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
@@ -0,0 +1,61 @@
+/*
+ * 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.controller;
+
+import java.io.IOException;
+
+import org.apache.kylin.rest.service.CubeService;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.metadata.MetadataManager;
+import org.apache.kylin.metadata.model.DataModelDesc;
+
+/**
+ * @author jiazhong
+ * 
+ */
+@Controller
+@RequestMapping(value = "/model")
+public class ModelDescController extends BasicController{
+
+
+    /**
+     * Get detail information of the "Model ID"
+     * 
+     * @param modelDescName
+     *            Model ID
+     * @return
+     * @throws IOException
+     */
+    @RequestMapping(value = "/{model_name}", method = { RequestMethod.GET })
+    @ResponseBody
+    public DataModelDesc getModel(@PathVariable String model_name) {
+        MetadataManager metaManager= MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
+        DataModelDesc modeDesc = metaManager.getDataModelDesc(model_name);
+        return modeDesc;
+            
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/request/CubeRequest.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/request/CubeRequest.java b/server/src/main/java/org/apache/kylin/rest/request/CubeRequest.java
index ab6f8f4..6c4eecb 100644
--- a/server/src/main/java/org/apache/kylin/rest/request/CubeRequest.java
+++ b/server/src/main/java/org/apache/kylin/rest/request/CubeRequest.java
@@ -23,10 +23,8 @@ public class CubeRequest {
     private String uuid;
     private String cubeName;
     private String cubeDescData;
-    private String modelDescData;
     private boolean successful;
     private String message;
-    private String cubeDescName;
     private String project;
 
     public String getUuid() {
@@ -38,21 +36,6 @@ public class CubeRequest {
     }
 
     /**
-     * @return the cubeDescName
-     */
-    public String getCubeDescName() {
-        return cubeDescName;
-    }
-
-    /**
-     * @param cubeDescName
-     *            the cubeDescName to set
-     */
-    public void setCubeDescName(String cubeDescName) {
-        this.cubeDescName = cubeDescName;
-    }
-
-    /**
      * @return the message
      */
     public String getMessage() {
@@ -85,10 +68,9 @@ public class CubeRequest {
     public CubeRequest() {
     }
 
-    public CubeRequest(long id, String cubeName, String cubeDescData,String modelDescData) {
+    public CubeRequest( String cubeName, String cubeDescData) {
         this.cubeName = cubeName;
         this.cubeDescData = cubeDescData;
-        this.modelDescData = modelDescData;
     }
 
     public String getCubeDescData() {
@@ -98,16 +80,7 @@ public class CubeRequest {
     public void setCubeDescData(String cubeDescData) {
         this.cubeDescData = cubeDescData;
     }
-    
-    
-    
-    public String getModelDescData() {
-        return modelDescData;
-    }
 
-    public void setModelDescData(String modelDescData) {
-        this.modelDescData = modelDescData;
-    }
 
     /**
      * @return the cubeDescName

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/request/ModelRequest.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/request/ModelRequest.java b/server/src/main/java/org/apache/kylin/rest/request/ModelRequest.java
new file mode 100644
index 0000000..15b62cf
--- /dev/null
+++ b/server/src/main/java/org/apache/kylin/rest/request/ModelRequest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.request;
+
+public class ModelRequest {
+
+    private String uuid;
+    private String modelName;
+    private String modelDescData;
+    private boolean successful;
+    private String message;
+    private String project;
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    /**
+     * @return the message
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * @param message
+     *            the message to set
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    /**
+     * @return the status
+     */
+    public boolean getSuccessful() {
+        return successful;
+    }
+
+    /**
+     * @param status
+     *            the status to set
+     */
+    public void setSuccessful(boolean status) {
+        this.successful = status;
+    }
+
+    public ModelRequest() {
+    }
+
+    public ModelRequest(String modelName, String modelDescData) {
+        this.modelName = modelName;
+        this.modelDescData = modelDescData;
+    }
+
+    
+    
+    public String getModelDescData() {
+        return modelDescData;
+    }
+
+    public void setModelDescData(String modelDescData) {
+        this.modelDescData = modelDescData;
+    }
+
+    /**
+     * @return the modelName
+     */
+    public String getModelName() {
+        return modelName;
+    }
+
+    /**
+     * @param modelName
+     *            the cubeName to set
+     */
+    public void setModelName(String modelName) {
+        this.modelName = modelName;
+    }
+
+    public String getProject() {
+        return project;
+    }
+
+    public void setProject(String project) {
+        this.project = project;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
new file mode 100644
index 0000000..ddf2594
--- /dev/null
+++ b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
@@ -0,0 +1,118 @@
+/*
+ * 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.service;
+
+
+import org.apache.kylin.job.exception.JobException;
+import org.apache.kylin.metadata.model.DataModelDesc;
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PostFilter;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author jiazhong
+ */
+@Component("modelMgmtService")
+public class ModelService extends BasicService {
+
+    private static final Logger logger = LoggerFactory.getLogger(ModelService.class);
+
+    @Autowired
+    private AccessService accessService;
+
+    @PostFilter(Constant.ACCESS_POST_FILTER_READ)
+    public List<DataModelDesc> listAllModels(final String modelName, final String projectName) {
+        List<DataModelDesc> models = null;
+        ProjectInstance project = (null != projectName) ? getProjectManager().getProject(projectName) : null;
+
+        if (null == project) {
+            models = getMetadataManager().getModels();
+        } else {
+            //TO-DO
+//            models = listAllModels(projectName);
+        }
+
+        List<DataModelDesc> filterModels = new ArrayList();
+        for (DataModelDesc modelDesc : models) {
+            boolean isModelMatch = (null == modelName) || modelDesc.getName().toLowerCase().contains(modelName.toLowerCase());
+
+            if (isModelMatch) {
+                filterModels.add(modelDesc);
+            }
+        }
+
+        return filterModels;
+    }
+
+    public List<DataModelDesc> getModels(final String modelName, final String projectName, final Integer limit, final Integer offset) {
+        int climit = (null == limit) ? 30 : limit;
+        int coffset = (null == offset) ? 0 : offset;
+
+        List<DataModelDesc> modelDescs;
+        modelDescs = listAllModels(modelName, projectName);
+
+        if (modelDescs.size() <= coffset) {
+            return Collections.emptyList();
+        }
+
+        if ((modelDescs.size() - coffset) < climit) {
+            return modelDescs.subList(coffset, modelDescs.size());
+        }
+
+        return modelDescs.subList(coffset, coffset + climit);
+    }
+
+
+    public DataModelDesc createModelDesc(String projectName, DataModelDesc desc) throws IOException {
+        if (getMetadataManager().getDataModelDesc(desc.getName()) != null) {
+            throw new InternalErrorException("The model named " + desc.getName() + " already exists");
+        }
+        DataModelDesc createdDesc = null;
+        createdDesc = getMetadataManager().createDataModelDesc(desc);
+//        ProjectInstance project = getProjectManager().getProject(projectName);
+//        accessService.inherit(createdDesc, project);
+        return createdDesc;
+    }
+
+
+    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#model, 'ADMINISTRATION') or hasPermission(#model, 'MANAGEMENT')")
+    public DataModelDesc updateModelAndDesc(DataModelDesc desc, String newProjectName) throws IOException {
+        DataModelDesc existingModel = getMetadataManager().getDataModelDesc(desc.getName());
+        if (existingModel == null) {
+            getMetadataManager().createDataModelDesc(desc);
+        } else {
+            getMetadataManager().updateDataModelDesc(desc);
+        }
+        return desc;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/286e5203/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java
----------------------------------------------------------------------
diff --git a/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java b/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java
index 336eae5..52c2d77 100644
--- a/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java
+++ b/server/src/test/java/org/apache/kylin/rest/controller/CubeControllerTest.java
@@ -43,7 +43,6 @@ public class CubeControllerTest extends ServiceTestBase {
 
     private CubeController cubeController;
     private CubeDescController cubeDescController;
-    private ModelController modelController;
 
     @Autowired
     CubeService cubeService;
@@ -60,8 +59,6 @@ public class CubeControllerTest extends ServiceTestBase {
         cubeDescController = new CubeDescController();
         cubeDescController.setCubeService(cubeService);
 
-        modelController = new ModelController();
-        modelController.setCubeService(cubeService);
     }
 
     @Test
@@ -104,13 +101,9 @@ public class CubeControllerTest extends ServiceTestBase {
 
         CubeRequest cubeRequest = new CubeRequest();
         cubeRequest.setCubeDescData(cubeDescWriter.toString());
-        cubeRequest.setModelDescData(modelDescWriter.toString());
         cubeRequest = cubeController.saveCubeDesc(cubeRequest);
 
 
-        DataModelDesc model = modelController.getModel(newModelName);
-        Assert.assertNotNull(model);
-
         List<String> notifyList = Lists.newArrayList();
         notifyList.add("john@example.com");
         cubeController.updateNotifyList(newCubeName, notifyList);