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:22:08 UTC

[39/52] [abbrv] incubator-kylin git commit: compatible with old meta data

compatible with old meta data


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

Branch: refs/heads/0.8.0
Commit: 0aca96b1682efa2b2af5deb800681ebfe5f35e8a
Parents: aebd109
Author: jiazhong <ji...@ebay.com>
Authored: Fri Apr 3 14:11:44 2015 +0800
Committer: honma <ho...@ebay.com>
Committed: Fri May 15 11:38:00 2015 +0800

----------------------------------------------------------------------
 .../org/apache/kylin/cube/CubeInstance.java     |   7 +-
 .../apache/kylin/invertedindex/IIInstance.java  |   9 +-
 .../apache/kylin/metadata/MetadataManager.java  |  26 ++-
 .../kylin/metadata/model/DataModelDesc.java     |  36 ++++
 .../kylin/metadata/project/ProjectManager.java  |  11 +-
 .../metadata/realization/IRealization.java      |   3 +
 .../kylin/rest/controller/ModelController.java  |   8 +-
 .../apache/kylin/rest/service/ModelService.java |  13 +-
 .../kylin/storage/hybrid/HybridInstance.java    |  13 +-
 webapp/app/js/controllers/modelEdit.js          |   9 +-
 webapp/app/js/controllers/modelSchema.js        |   5 +-
 webapp/app/js/model/metaModel.js                | 191 ++++++++++---------
 webapp/app/js/services/message.js               |   2 +-
 webapp/app/less/component.less                  |   4 +
 .../modelDesigner/conditions_settings.html      |   5 +-
 .../app/partials/modelDesigner/model_info.html  |  15 ++
 webapp/app/partials/models/model_schema.html    |   4 +-
 webapp/app/partials/models/models_tree.html     |   1 +
 .../app/partials/tables/source_table_tree.html  |   1 +
 webapp/bower.json                               |   4 +-
 20 files changed, 233 insertions(+), 134 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/cube/src/main/java/org/apache/kylin/cube/CubeInstance.java
----------------------------------------------------------------------
diff --git a/cube/src/main/java/org/apache/kylin/cube/CubeInstance.java b/cube/src/main/java/org/apache/kylin/cube/CubeInstance.java
index e63f836..c397f98 100644
--- a/cube/src/main/java/org/apache/kylin/cube/CubeInstance.java
+++ b/cube/src/main/java/org/apache/kylin/cube/CubeInstance.java
@@ -25,10 +25,7 @@ import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.persistence.ResourceStore;
 import org.apache.kylin.common.persistence.RootPersistentEntity;
 import org.apache.kylin.cube.model.CubeDesc;
-import org.apache.kylin.metadata.model.LookupDesc;
-import org.apache.kylin.metadata.model.MeasureDesc;
-import org.apache.kylin.metadata.model.SegmentStatusEnum;
-import org.apache.kylin.metadata.model.TblColRef;
+import org.apache.kylin.metadata.model.*;
 import org.apache.kylin.metadata.realization.IRealization;
 import org.apache.kylin.metadata.realization.RealizationStatusEnum;
 import org.apache.kylin.metadata.realization.RealizationType;
@@ -120,6 +117,8 @@ public class CubeInstance extends RootPersistentEntity implements IRealization {
         return CubeDescManager.getInstance(config).getCubeDesc(descName);
     }
 
+    public DataModelDesc getDataModelDesc(){return this.getDescriptor().getModel();}
+
     public boolean isReady() {
         return getStatus() == RealizationStatusEnum.READY;
     }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/invertedindex/src/main/java/org/apache/kylin/invertedindex/IIInstance.java
----------------------------------------------------------------------
diff --git a/invertedindex/src/main/java/org/apache/kylin/invertedindex/IIInstance.java b/invertedindex/src/main/java/org/apache/kylin/invertedindex/IIInstance.java
index 1d300a8..cdb3fa7 100644
--- a/invertedindex/src/main/java/org/apache/kylin/invertedindex/IIInstance.java
+++ b/invertedindex/src/main/java/org/apache/kylin/invertedindex/IIInstance.java
@@ -28,10 +28,7 @@ import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.persistence.ResourceStore;
 import org.apache.kylin.common.persistence.RootPersistentEntity;
 import org.apache.kylin.invertedindex.model.IIDesc;
-import org.apache.kylin.metadata.model.LookupDesc;
-import org.apache.kylin.metadata.model.MeasureDesc;
-import org.apache.kylin.metadata.model.SegmentStatusEnum;
-import org.apache.kylin.metadata.model.TblColRef;
+import org.apache.kylin.metadata.model.*;
 import org.apache.kylin.metadata.realization.IRealization;
 import org.apache.kylin.metadata.realization.RealizationStatusEnum;
 import org.apache.kylin.metadata.realization.RealizationType;
@@ -113,6 +110,10 @@ public class IIInstance extends RootPersistentEntity implements IRealization {
         return IIDescManager.getInstance(config).getIIDesc(descName);
     }
 
+    public DataModelDesc getDataModelDesc(){
+        return this.getDescriptor().getModel();
+    }
+
     public boolean isReady() {
         return getStatus() == RealizationStatusEnum.READY;
     }

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/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 86d33f7..ae64f4c 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
@@ -29,6 +29,10 @@ import java.util.concurrent.ConcurrentHashMap;
 import org.apache.kylin.metadata.model.TableDesc;
 import org.apache.kylin.metadata.project.ProjectInstance;
 import org.apache.kylin.metadata.project.ProjectManager;
+import org.apache.kylin.metadata.project.RealizationEntry;
+import org.apache.kylin.metadata.realization.IRealization;
+import org.apache.kylin.metadata.realization.RealizationRegistry;
+import org.apache.kylin.metadata.realization.RealizationType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -287,9 +291,11 @@ public class MetadataManager {
         return new ArrayList<DataModelDesc>(dataModelDescMap.values());
     }
 
-    public List<DataModelDesc> getModels(String projectName){
+    public List<DataModelDesc> getModels(String projectName) throws IOException{
         ProjectInstance projectInstance =  ProjectManager.getInstance(config).getProject(projectName);
         HashSet<DataModelDesc> ret = new HashSet<>();
+
+
         if (projectInstance != null&&projectInstance.getModels()!=null) {
             for (String modelName : projectInstance.getModels()) {
                 DataModelDesc model = getDataModelDesc(modelName);
@@ -301,6 +307,22 @@ public class MetadataManager {
             }
         }
 
+        //TODO, list model from realization,compatible with old meta data,will remove
+        RealizationRegistry registry = RealizationRegistry.getInstance(config);
+        for (RealizationEntry realization : projectInstance.getRealizationEntries()) {
+            IRealization rel = registry.getRealization(realization.getType(), realization.getRealization());
+            if (rel != null) {
+                DataModelDesc modelDesc = rel.getDataModelDesc();
+                if(!ret.contains(modelDesc)){
+                    ProjectManager.getInstance(config).updateModelToProject(modelDesc.getName(),projectName);
+                    ret.add(modelDesc);
+                }
+            } else {
+                logger.warn("Realization '" + realization + "' defined under project '" + projectInstance + "' is not found");
+            }
+        }
+
+
         return new ArrayList<>(ret);
     }
 
@@ -344,7 +366,7 @@ public class MetadataManager {
         String name = desc.getName();
         if (dataModelDescMap.containsKey(name))
             throw new IllegalArgumentException("DataModelDesc '" + name + "' already exists");
-        ProjectManager.getInstance(config).updateModelToProject(name,projectName,owner);
+        ProjectManager.getInstance(config).updateModelToProject(name,projectName);
         return saveDataModelDesc(desc);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java b/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
index 7e888c2..88c3521 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
@@ -41,6 +41,9 @@ public class DataModelDesc extends RootPersistentEntity {
     @JsonProperty("name")
     private String name;
 
+    @JsonProperty("description")
+    private String description;
+
     @JsonProperty("fact_table")
     private String factTable;
 
@@ -76,6 +79,14 @@ public class DataModelDesc extends RootPersistentEntity {
         this.name = name;
     }
 
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
     public Collection<String> getAllTables() {
         HashSet<String> ret = Sets.newHashSet();
         ret.add(factTable);
@@ -247,6 +258,31 @@ public class DataModelDesc extends RootPersistentEntity {
     public List<String> getError() {
         return this.errors;
     }
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        DataModelDesc modelDesc = (DataModelDesc) o;
+
+        if (!name.equals(modelDesc.name))
+            return false;
+        if (!getFactTable().equals(modelDesc.getFactTable()))
+            return false;
+
+        return true;
+    }
+
+
+    @Override
+    public int hashCode() {
+        int result = 0;
+        result = 31 * result + name.hashCode();
+        result = 31 * result + getFactTable().hashCode();
+        return result;
+    }
 
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java b/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
index fb2d298..9538398 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
@@ -224,10 +224,9 @@ public class ProjectManager {
         return this.getProject(projectName).containsModel(modelName);
     }
 
-    public ProjectInstance updateModelToProject(String modelName, String newProjectName, String owner) throws IOException {
+    public ProjectInstance updateModelToProject(String modelName, String newProjectName) throws IOException {
         removeModelFromProjects(modelName);
-
-        return addModelToProject(modelName, newProjectName, owner);
+        return addModelToProject(modelName, newProjectName);
     }
 
     public void removeModelFromProjects(String modelName) throws IOException {
@@ -238,11 +237,11 @@ public class ProjectManager {
         }
     }
 
-    private ProjectInstance addModelToProject(String modelName, String project, String user) throws IOException {
+    private ProjectInstance addModelToProject(String modelName, String project) throws IOException {
         String newProjectName = ProjectInstance.getNormalizedProjectName(project);
         ProjectInstance newProject = getProject(newProjectName);
         if (newProject == null) {
-            newProject = this.createProject(newProjectName, user, "This is a project automatically added when adding model " + modelName);
+            throw new IllegalArgumentException("Project "+newProjectName+" does not exist.");
         }
         newProject.addModel(modelName);
         saveResource(newProject);
@@ -259,7 +258,7 @@ public class ProjectManager {
         String newProjectName = norm(project);
         ProjectInstance newProject = getProject(newProjectName);
         if (newProject == null) {
-            newProject = this.createProject(newProjectName, user, "This is a project automatically added when adding realization " + realizationName + "(" + type + ")");
+            throw new IllegalArgumentException("Project "+newProjectName+" does not exist.");
         }
         newProject.addRealizationEntry(type, realizationName);
         saveResource(newProject);

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/metadata/src/main/java/org/apache/kylin/metadata/realization/IRealization.java
----------------------------------------------------------------------
diff --git a/metadata/src/main/java/org/apache/kylin/metadata/realization/IRealization.java b/metadata/src/main/java/org/apache/kylin/metadata/realization/IRealization.java
index fbc26d0..251e794 100644
--- a/metadata/src/main/java/org/apache/kylin/metadata/realization/IRealization.java
+++ b/metadata/src/main/java/org/apache/kylin/metadata/realization/IRealization.java
@@ -18,6 +18,7 @@
 
 package org.apache.kylin.metadata.realization;
 
+import org.apache.kylin.metadata.model.DataModelDesc;
 import org.apache.kylin.metadata.model.MeasureDesc;
 import org.apache.kylin.metadata.model.TblColRef;
 
@@ -47,6 +48,8 @@ public interface IRealization {
      */
     public RealizationType getType();
 
+    public DataModelDesc getDataModelDesc();
+
     public String getFactTable();
 
     public List<TblColRef> getAllColumns();

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/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 9b50af6..3e17be1 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
@@ -59,7 +59,13 @@ public class ModelController extends BasicController {
     @ResponseBody
     @Metered(name = "listModels")
     public List<DataModelDesc> getModels(@RequestParam(value = "modelName", required = false) String modelName, @RequestParam(value = "projectName", required = false) String projectName, @RequestParam(value="limit",required=false) Integer limit, @RequestParam(value="offset",required=false) Integer offset) {
-        return modelService.getModels(modelName, projectName, limit, offset);
+        try{
+            return modelService.getModels(modelName, projectName, limit, offset);
+        }
+        catch (IOException e){
+            logger.error("Failed to deal with the request:" + e.getLocalizedMessage(), e);
+            throw new InternalErrorException("Failed to deal with the request: " + e.getLocalizedMessage());
+        }
     }
 
     @RequestMapping(value = "/{modelName}", method = {RequestMethod.DELETE})

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/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
index 490de31..d210077 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/ModelService.java
@@ -49,7 +49,7 @@ public class ModelService extends BasicService {
     private AccessService accessService;
 
     @PostFilter(Constant.ACCESS_POST_FILTER_READ)
-    public List<DataModelDesc> listAllModels(final String modelName, final String projectName) {
+    public List<DataModelDesc> listAllModels(final String modelName, final String projectName) throws IOException{
         List<DataModelDesc> models = null;
         ProjectInstance project = (null != projectName) ? getProjectManager().getProject(projectName) : null;
 
@@ -72,7 +72,7 @@ public class ModelService extends BasicService {
         return filterModels;
     }
 
-    public List<DataModelDesc> getModels(final String modelName, final String projectName, final Integer limit, final Integer offset) {
+    public List<DataModelDesc> getModels(final String modelName, final String projectName, final Integer limit, final Integer offset) throws IOException{
 
         List<DataModelDesc> modelDescs;
         modelDescs = listAllModels(modelName, projectName);
@@ -110,13 +110,8 @@ public class ModelService extends BasicService {
 
     @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#desc, 'ADMINISTRATION') or hasPermission(#desc, 'MANAGEMENT')")
     public DataModelDesc updateModelAndDesc(DataModelDesc desc, String newProjectName) throws IOException {
-        DataModelDesc existingModel = getMetadataManager().getDataModelDesc(desc.getName());
-        if (existingModel == null) {
-            String owner = SecurityContextHolder.getContext().getAuthentication().getName();
-            getMetadataManager().createDataModelDesc(desc,newProjectName,owner);
-        } else {
-            getMetadataManager().updateDataModelDesc(desc);
-        }
+
+        getMetadataManager().updateDataModelDesc(desc);
         return desc;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/storage/src/main/java/org/apache/kylin/storage/hybrid/HybridInstance.java
----------------------------------------------------------------------
diff --git a/storage/src/main/java/org/apache/kylin/storage/hybrid/HybridInstance.java b/storage/src/main/java/org/apache/kylin/storage/hybrid/HybridInstance.java
index beb86c5..1694719 100644
--- a/storage/src/main/java/org/apache/kylin/storage/hybrid/HybridInstance.java
+++ b/storage/src/main/java/org/apache/kylin/storage/hybrid/HybridInstance.java
@@ -7,6 +7,7 @@ import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.persistence.RootPersistentEntity;
 import org.apache.kylin.cube.CubeInstance;
 import org.apache.kylin.invertedindex.IIInstance;
+import org.apache.kylin.metadata.model.DataModelDesc;
 import org.apache.kylin.metadata.model.MeasureDesc;
 import org.apache.kylin.metadata.model.TblColRef;
 import org.apache.kylin.metadata.project.RealizationEntry;
@@ -159,7 +160,17 @@ public class HybridInstance extends RootPersistentEntity implements IRealization
         return Math.max(getHistoryRealizationInstance().getDateRangeEnd(), getRealTimeRealizationInstance().getDateRangeEnd()) +1;
     }
 
-    @Override
+    
+
+    public DataModelDesc getDataModelDesc(){
+        if (getHistoryRealizationInstance() instanceof CubeInstance) {
+            return ((CubeInstance) historyRealizationInstance).getDescriptor().getModel();
+        }
+
+        return ((IIInstance) historyRealizationInstance).getDescriptor().getModel();
+    }
+
+   @Override
     public String getModelName() {
         if (getHistoryRealizationInstance() instanceof CubeInstance) {
             return ((CubeInstance) historyRealizationInstance).getDescriptor().getModelName();

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/js/controllers/modelEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelEdit.js b/webapp/app/js/controllers/modelEdit.js
index 810242e..5ca95b1 100644
--- a/webapp/app/js/controllers/modelEdit.js
+++ b/webapp/app/js/controllers/modelEdit.js
@@ -117,6 +117,9 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
             }
 
         }
+        if($scope.model.partition_desc.partition_date_column==null){
+            $scope.model.partition_desc.partition_date_start=null;
+        }
         $scope.state.project = $scope.model.project;
         var _model = angular.copy($scope.model);
         delete _model.project;
@@ -159,7 +162,7 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
                             $scope.state.modelSchema = request.modelSchema;
                             MessageService.sendMsg($scope.modelResultTmpl({'text':'Updated the model successfully.',type:'success'}), 'success', {}, true, 'top_center');
                         } else {
-                            $scope.saveModelRollBack();
+                               $scope.saveModelRollBack();
                                 var message =request.message;
                                 var msg = !!(message) ? message : 'Failed to take action.';
                                 MessageService.sendMsg($scope.modelResultTmpl({'text':msg,'schema':$scope.state.modelSchema}), 'error', {}, true, 'top_center');
@@ -172,6 +175,7 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
                         if(e.data&& e.data.exception){
                             var message =e.data.exception;
                             var msg = !!(message) ? message : 'Failed to take action.';
+                            $log.log($scope.modelResultTmpl({'text':msg,'schema':$scope.state.modelSchema}));
                             MessageService.sendMsg($scope.modelResultTmpl({'text':msg,'schema':$scope.state.modelSchema}), 'error', {}, true, 'top_center');
                         } else {
                             MessageService.sendMsg($scope.modelResultTmpl({'text':'Failed to take action.','schema':$scope.state.modelSchema}), 'error', {}, true, 'top_center');
@@ -217,6 +221,9 @@ KylinApp.controller('ModelEditCtrl', function ($scope, $q, $routeParams, $locati
 
 //    reverse the date
     $scope.saveModelRollBack = function (){
+        if($scope.model.partition_desc.partition_date_start==0){
+            $scope.model.partition_desc.partition_date_start = null;
+        }
         if($scope.model&&($scope.model.partition_desc.partition_date_start||$scope.model.partition_desc.partition_date_start==0))
         {
             $scope.model.partition_desc.partition_date_start+=new Date().getTimezoneOffset()*60000;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index 409582a..81df1df 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -171,7 +171,7 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
             errorInfo+="\n"+item;
         });
         if(errors.length){
-            SweetAlert.swal('', errorInfo, 'warning');
+            SweetAlert.swal('Oops...', errorInfo, 'warning');
             return false;
         }else{
             return true;
@@ -206,9 +206,6 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
         if($scope.model.partition_desc.partition_date_column!=null&& $scope.model.partition_desc.partition_date_start==null){
             errors.push("Please indicate start date when partition date column selected.");
         }
-        if($scope.model.partition_desc.partition_date_column==null&& $scope.model.partition_desc.partition_date_start!=null){
-            errors.push("Please select your partitoin date column.");
-        }
         var errorInfo = "";
         angular.forEach(errors,function(item){
             errorInfo+="\n"+item;

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/js/model/metaModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/metaModel.js b/webapp/app/js/model/metaModel.js
index 5366809..3c70822 100644
--- a/webapp/app/js/model/metaModel.js
+++ b/webapp/app/js/model/metaModel.js
@@ -1,94 +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.
-*/
-
-/**
- *MetaModel will manage model info of cube
- */
-KylinApp.service('MetaModel',function(){
-
-    //data model when edit model
-    this.model={
-        name: null,
-        fact_table: null,
-        lookups: [],
-        filter_condition:null,
-        capacity:null,
-        dimensions:[],
-        metrics:[],
-        "partition_desc" : {
-            "partition_date_column" : null,
-            "partition_date_start" : null,
-            "partition_type" : 'APPEND'
-        },
-        last_modified:0
-    };
-
-
-    this.setMetaModel =function(model){
-        var _model = {};
-        _model.name = model.name;
-        _model.fact_table = model.fact_table;
-        _model.lookups =model.lookups;
-        _model.filter_condition = model.filter_condition;
-        _model.capacity = model.capacity;
-        _model.dimensions = model.dimensions;
-        _model.metrics = model.metrics;
-        _model.partition_desc = model.partition_desc;
-        _model.last_modified = model.last_modified;
-        this.model = _model;
-    };
-
-    this.initModel = function(){
-        this.model = this.createNew();
-    }
-
-    this.getMetaModel = function(){
-        return this.model;
-    };
-
-    this.setFactTable = function(fact_table) {
-        this.model.fact_table =fact_table;
-    };
-
-
-    this.converDateToGMT = function(){
-        if(this.model.partition_desc&&this.model.partition_desc.partition_date_start){
-            this.model.partition_desc.partition_date_start+=new Date().getTimezoneOffset()*60000;
-        }
-    };
-    //
-    this.createNew = function () {
-        var metaModel = {
-            name: '',
-            fact_table: '',
-            lookups: [],
-            filter_condition:'',
-            capacity:'MEDIUM',
-            dimensions:[],
-            metrics:[],
-            "partition_desc" : {
-                "partition_date_column" : null,
-                "partition_date_start" : null,
-                "partition_type" : 'APPEND'
-            },
-            last_modified:0
-        };
-
-        return metaModel;
-    }
-})
\ No newline at end of file
+/*
+ * 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.
+*/
+
+/**
+ *MetaModel will manage model info of cube
+ */
+KylinApp.service('MetaModel',function(){
+
+    //data model when edit model
+    this.model={
+        name: null,
+        description:null,
+        fact_table: null,
+        lookups: [],
+        filter_condition:null,
+        capacity:null,
+        dimensions:[],
+        metrics:[],
+        "partition_desc" : {
+            "partition_date_column" : null,
+            "partition_date_start" : null,
+            "partition_type" : 'APPEND'
+        },
+        last_modified:0
+    };
+
+
+    this.setMetaModel =function(model){
+        var _model = {};
+        _model.name = model.name;
+        _model.description = model.description;
+        _model.fact_table = model.fact_table;
+        _model.lookups =model.lookups;
+        _model.filter_condition = model.filter_condition;
+        _model.capacity = model.capacity;
+        _model.dimensions = model.dimensions;
+        _model.metrics = model.metrics;
+        _model.partition_desc = model.partition_desc;
+        _model.last_modified = model.last_modified;
+        this.model = _model;
+    };
+
+    this.initModel = function(){
+        this.model = this.createNew();
+    }
+
+    this.getMetaModel = function(){
+        return this.model;
+    };
+
+    this.setFactTable = function(fact_table) {
+        this.model.fact_table =fact_table;
+    };
+
+
+    this.converDateToGMT = function(){
+        if(this.model.partition_desc&&this.model.partition_desc.partition_date_start){
+            this.model.partition_desc.partition_date_start+=new Date().getTimezoneOffset()*60000;
+        }
+    };
+    //
+    this.createNew = function () {
+        var metaModel = {
+            name: '',
+            description:'',
+            fact_table: '',
+            lookups: [],
+            filter_condition:'',
+            capacity:'MEDIUM',
+            dimensions:[],
+            metrics:[],
+            "partition_desc" : {
+                "partition_date_column" : null,
+                "partition_date_start" : null,
+                "partition_type" : 'APPEND'
+            },
+            last_modified:0
+        };
+
+        return metaModel;
+    }
+})

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/js/services/message.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/message.js b/webapp/app/js/services/message.js
index a5a6d1c..7c8fabd 100644
--- a/webapp/app/js/services/message.js
+++ b/webapp/app/js/services/message.js
@@ -16,7 +16,7 @@
  * limitations under the License.
 */
 
-KylinApp.service('MessageService', ['config_ui_messenger', function (config_ui_messenger) {
+KylinApp.service('MessageService', ['config_ui_messenger', function (config_ui_messenger,$log) {
 
     this.sendMsg = function (msg, type, actions, sticky, position) {
         var options = {

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/less/component.less
----------------------------------------------------------------------
diff --git a/webapp/app/less/component.less b/webapp/app/less/component.less
index 14a6fe8..ab137d2 100644
--- a/webapp/app/less/component.less
+++ b/webapp/app/less/component.less
@@ -971,4 +971,8 @@ Angular 1.2.0 Animation
 }
 .highlight-bule{
   color:#428bca !important;
+}
+
+.sweet-alert .lead.text-muted{
+  word-break:break-all;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/partials/modelDesigner/conditions_settings.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/conditions_settings.html b/webapp/app/partials/modelDesigner/conditions_settings.html
index 035c777..b104309 100644
--- a/webapp/app/partials/modelDesigner/conditions_settings.html
+++ b/webapp/app/partials/modelDesigner/conditions_settings.html
@@ -40,7 +40,7 @@
         <div class="form-group">
             <div class="row">
                 <label class="control-label col-xs-12 col-sm-3 no-padding-right font-color-default"><b>Partition Date Column</b></label>
-                <div class="col-xs-12 col-sm-6" ng-class="model.partition_desc.partition_date_column==null&& model.partition_desc.partition_date_start!=null?'has-error':''">
+                <div class="col-xs-12 col-sm-6">
 
                     <select style="width: 100%" chosen data-placeholder="e.g. DEFAULT.TEST_KYLIN_FACT.CAL_DT"
                             ng-model="model.partition_desc.partition_date_column"
@@ -49,8 +49,7 @@
                             ng-options="model.fact_table+'.'+columns.name as model.fact_table+'.'+columns.name for columns in getPartitonColumns(model.fact_table)" >
                         <option value="">--Select Partition Column--</option>
                     </select>
-                    <small class="help-block" ng-show="model.partition_desc.partition_date_column==null&& model.partition_desc.partition_date_start!=null">Please select your partitoin date column.</small>
-                    <p class="text-red"  ng-if="state.mode=='edit'">(data format in column should be 'YYYY-MM-DD')</p>
+                    <small class="help-block text-red" ng-show="state.mode=='edit'">(data format in column should be 'YYYY-MM-DD')</small>
 
                     <span ng-if="state.mode=='view'">
                         {{!!(model.partition_desc.partition_date_column)?model.partition_desc.partition_date_column: ''}}</span>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/partials/modelDesigner/model_info.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/model_info.html b/webapp/app/partials/modelDesigner/model_info.html
index 097739c..d300806 100644
--- a/webapp/app/partials/modelDesigner/model_info.html
+++ b/webapp/app/partials/modelDesigner/model_info.html
@@ -43,6 +43,21 @@
                     </div>
                 </div>
             </div>
+
+            <!--Description-->
+            <div class="form-group">
+                <div class="row">
+                    <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default">
+                        <b>Description</b>
+                    </label>
+                    <div class="col-xs-12 col-sm-6">
+                        <textarea ng-if="state.mode=='edit'" class="form-control box-default"
+                                  name="comment" id="comment" ng-model="model.description"></textarea>
+                        <span ng-if="state.mode=='view'">{{model.description}}</span>
+                    </div>
+                </div>
+            </div>
+
         </ng-form>
     </div>
 

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/partials/models/model_schema.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/model_schema.html b/webapp/app/partials/models/model_schema.html
index b2cf20c..b94cecb 100644
--- a/webapp/app/partials/models/model_schema.html
+++ b/webapp/app/partials/models/model_schema.html
@@ -14,7 +14,7 @@
 * 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.
--->A
+-->
 
 <!--hide when view model and no model selected-->
 <div class="box box-primary model-design box-2px" ng-hide="state.mode=='view'&&!model.name">
@@ -55,7 +55,7 @@
                             Next
                             <i class="ace-icon fa fa-arrow-right icon-on-right"></i>
                         </button>
-                        <button class="btn btn-primary" ng-click="saveModel()"
+                        <button class="btn btn-primary"  ng-click="checkForm()?saveModel():''"
                                 ng-if="curStep.title=='Settings' && state.mode=='edit'">
                             Save
                         </button>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/partials/models/models_tree.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/models/models_tree.html b/webapp/app/partials/models/models_tree.html
index 142ef0b..4ed21f6 100644
--- a/webapp/app/partials/models/models_tree.html
+++ b/webapp/app/partials/models/models_tree.html
@@ -41,5 +41,6 @@
                 expand-level      = "2"
                 initial-selection = "">
             </abn-tree>
+        <div no-result ng-if="models_treedata.length==0"></div>
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/app/partials/tables/source_table_tree.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/source_table_tree.html b/webapp/app/partials/tables/source_table_tree.html
index c7229a9..2e5de36 100755
--- a/webapp/app/partials/tables/source_table_tree.html
+++ b/webapp/app/partials/tables/source_table_tree.html
@@ -42,5 +42,6 @@
                 icon-collapse     = "fa fa-database"
                 expand-level      = "3">
         </abn-tree>
+        <div no-result ng-if="tableModel.selectedSrcDb.length == 0"></div>
     </div>
 </div>

http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/0aca96b1/webapp/bower.json
----------------------------------------------------------------------
diff --git a/webapp/bower.json b/webapp/bower.json
index b3f9a8d..0c385a9 100755
--- a/webapp/bower.json
+++ b/webapp/bower.json
@@ -21,7 +21,6 @@
     "nvd3": "1.1.15-beta",
     "angularjs-nvd3-directives": "0.0.5-beta",
     "angular-sweetalert": "~1.0.3",
-    "bootstrap-sweetalert": "~0.4.3",
     "angular-underscore": "~0.5.0",
     "angular-ui-sortable": "0.13.1",
     "underscore": "~1.7.0",
@@ -29,7 +28,8 @@
     "angular-animate": "1.2",
     "angular-cookies": "1.2",
     "angular-bootstrap-nav-tree": "*",
-    "components-font-awesome": "~4.3.0"
+    "components-font-awesome": "~4.3.0",
+    "bootstrap-sweetalert": "~0.4.3"
   },
   "devDependencies": {
     "less.js": "~1.4.0",