You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by sh...@apache.org on 2016/03/23 10:15:14 UTC

[30/50] [abbrv] kylin git commit: KYLIN-1431 load streaming table ui update add cluster info when add table #2

KYLIN-1431 load streaming table ui update add cluster info when add table #2


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

Branch: refs/heads/1.5.x-HBase1.1.3
Commit: 376d695c5893c482eaba6853929b8a34276ba964
Parents: 890577d
Author: Jason <ji...@163.com>
Authored: Thu Mar 10 20:50:25 2016 +0800
Committer: Jason <ji...@163.com>
Committed: Fri Mar 11 10:58:35 2016 +0800

----------------------------------------------------------------------
 .../apache/kylin/metadata/model/TableDesc.java  |   4 +
 .../rest/controller/StreamingController.java    | 105 ++++++++++---
 .../kylin/rest/request/StreamingRequest.java    |   3 +-
 .../kylin/rest/response/TableDescResponse.java  |   1 +
 webapp/app/js/controllers/cubeEdit.js           | 101 ++----------
 webapp/app/js/controllers/modelSchema.js        |   2 +-
 webapp/app/js/controllers/sourceMeta.js         | 154 +++++++++++++++----
 webapp/app/js/controllers/streamingConfig.js    |  31 +++-
 webapp/app/js/model/streamingModel.js           |   3 +-
 webapp/app/js/model/tableModel.js               |   7 +-
 webapp/app/partials/cubeDesigner/info.html      |  10 +-
 .../partials/cubeDesigner/kafkaBasicConfig.html |   4 +-
 .../partials/cubeDesigner/streamingConfig.html  |  69 ++++++---
 .../app/partials/modelDesigner/data_model.html  |   8 +-
 .../app/partials/modelDesigner/model_info.html  |   6 +-
 .../app/partials/tables/loadStreamingTable.html |  19 +--
 webapp/app/partials/tables/table_detail.html    |  12 +-
 17 files changed, 343 insertions(+), 196 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableDesc.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableDesc.java b/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableDesc.java
index d5e4dbb..65d85dd 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableDesc.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableDesc.java
@@ -180,4 +180,8 @@ public class TableDesc extends RootPersistentEntity implements ISourceAware {
     public int getSourceType() {
         return sourceType;
     }
+
+    public void setSourceType(int sourceType) {
+        this.sourceType = sourceType;
+    }
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/server/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/StreamingController.java b/server/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
index ecd7571..932ad51 100644
--- a/server/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
+++ b/server/src/main/java/org/apache/kylin/rest/controller/StreamingController.java
@@ -22,13 +22,17 @@ 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.KylinConfig;
 import org.apache.kylin.common.util.JsonUtil;
 import org.apache.kylin.engine.streaming.StreamingConfig;
+import org.apache.kylin.metadata.MetadataManager;
+import org.apache.kylin.metadata.model.TableDesc;
 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.exception.NotFoundException;
 import org.apache.kylin.rest.request.StreamingRequest;
+import org.apache.kylin.rest.service.CubeService;
 import org.apache.kylin.rest.service.KafkaConfigService;
 import org.apache.kylin.rest.service.StreamingService;
 import org.apache.kylin.source.kafka.config.KafkaConfig;
@@ -40,7 +44,9 @@ import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 /**
@@ -57,6 +63,9 @@ public class StreamingController extends BasicController {
     private StreamingService streamingService;
     @Autowired
     private KafkaConfigService kafkaConfigService;
+    @Autowired
+    private CubeService cubeMgmtService;
+
 
     @RequestMapping(value = "/getConfig", method = { RequestMethod.GET })
     @ResponseBody
@@ -89,36 +98,69 @@ public class StreamingController extends BasicController {
     @RequestMapping(value = "", method = { RequestMethod.POST })
     @ResponseBody
     public StreamingRequest saveStreamingConfig(@RequestBody StreamingRequest streamingRequest) {
-        //Update Model
+
+        String project = streamingRequest.getProject();
+        TableDesc tableDesc = deserializeTableDesc(streamingRequest);
         StreamingConfig streamingConfig = deserializeSchemalDesc(streamingRequest);
         KafkaConfig kafkaConfig = deserializeKafkaSchemalDesc(streamingRequest);
-        if (streamingConfig == null ||kafkaConfig == null) {
-            return streamingRequest;
-        }
-        if (StringUtils.isEmpty(streamingConfig.getName())) {
-            logger.info("StreamingConfig should not be empty.");
-            throw new BadRequestException("StremingConfig name should not be empty.");
-        }
+        boolean  saveStreamingSuccess = false, saveKafkaSuccess = false;
 
         try {
-            streamingConfig.setUuid(UUID.randomUUID().toString());
-            streamingService.createStreamingConfig(streamingConfig);
-
+            tableDesc.setUuid(UUID.randomUUID().toString());
+            MetadataManager metaMgr = MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());
+            metaMgr.saveSourceTable(tableDesc);
+            cubeMgmtService.syncTableToProject(new String[]{tableDesc.getName()}, project);
         } catch (IOException e) {
-            logger.error("Failed to save StreamingConfig:" + e.getLocalizedMessage(), e);
-            throw new InternalErrorException("Failed to save StreamingConfig: " + e.getLocalizedMessage());
+            throw new BadRequestException("Failed to add streaming table.");
         }
+
         try {
-            kafkaConfig.setUuid(UUID.randomUUID().toString());
-            kafkaConfigService.createKafkaConfig(kafkaConfig);
-        }catch (IOException e){
+            if (StringUtils.isEmpty(streamingConfig.getName())) {
+                logger.info("StreamingConfig should not be empty.");
+                throw new BadRequestException("StremingConfig name should not be empty.");
+            }
+            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("Failed to save StreamingConfig: " + e.getLocalizedMessage());
+            }
             try {
-                streamingService.dropStreamingConfig(streamingConfig);
-            } catch (IOException e1) {
-                throw new InternalErrorException("StreamingConfig is created, but failed to create KafkaConfig: " + e.getLocalizedMessage());
+                kafkaConfig.setUuid(UUID.randomUUID().toString());
+                kafkaConfigService.createKafkaConfig(kafkaConfig);
+                saveKafkaSuccess = true;
+            } catch (IOException e) {
+                try {
+                    streamingService.dropStreamingConfig(streamingConfig);
+                } catch (IOException e1) {
+                    throw new InternalErrorException("StreamingConfig is created, but failed to create KafkaConfig: " + e.getLocalizedMessage());
+                }
+                logger.error("Failed to save KafkaConfig:" + e.getLocalizedMessage(), e);
+                throw new InternalErrorException("Failed to save KafkaConfig: " + e.getLocalizedMessage());
             }
-            logger.error("Failed to save KafkaConfig:" + e.getLocalizedMessage(), e);
-            throw new InternalErrorException("Failed to save KafkaConfig: " + e.getLocalizedMessage());
+        }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("Action failed and failed to rollback the created streaming config: " + e.getLocalizedMessage());
+                        }
+                }
+                if(saveKafkaSuccess == true){
+                    try {
+                        KafkaConfig kConfig = kafkaConfigService.getKafkaConfig(kafkaConfig.getName());
+                        kafkaConfigService.dropKafkaConfig(kConfig);
+                    } catch (IOException e) {
+                        throw new InternalErrorException("Action failed and failed to rollback the created kafka config: " + e.getLocalizedMessage());
+                    }
+                }
+            }
+
         }
         streamingRequest.setSuccessful(true);
         return streamingRequest;
@@ -172,6 +214,24 @@ public class StreamingController extends BasicController {
         }
     }
 
+    private TableDesc deserializeTableDesc(StreamingRequest streamingRequest) {
+        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 not valid.", e);
+            updateRequest(streamingRequest, false, e.getMessage());
+        } catch (JsonMappingException e) {
+            logger.error("The data TableDesc definition is not valid.", e);
+            updateRequest(streamingRequest, 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 StreamingConfig deserializeSchemalDesc(StreamingRequest streamingRequest) {
         StreamingConfig desc = null;
         try {
@@ -222,4 +282,7 @@ public class StreamingController extends BasicController {
         this.kafkaConfigService = kafkaConfigService;
     }
 
+    public void setCubeService(CubeService cubeService) {
+        this.cubeMgmtService = cubeService;
+    }
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/server/src/main/java/org/apache/kylin/rest/request/StreamingRequest.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/request/StreamingRequest.java b/server/src/main/java/org/apache/kylin/rest/request/StreamingRequest.java
index 07c30f3..a8a983b 100644
--- a/server/src/main/java/org/apache/kylin/rest/request/StreamingRequest.java
+++ b/server/src/main/java/org/apache/kylin/rest/request/StreamingRequest.java
@@ -19,7 +19,8 @@
 
 package org.apache.kylin.rest.request;
 
-import java.lang.String;public class StreamingRequest {
+import java.lang.String;
+public class StreamingRequest {
 
     private String project;
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/server/src/main/java/org/apache/kylin/rest/response/TableDescResponse.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/response/TableDescResponse.java b/server/src/main/java/org/apache/kylin/rest/response/TableDescResponse.java
index fc663dd..5dede2a 100644
--- a/server/src/main/java/org/apache/kylin/rest/response/TableDescResponse.java
+++ b/server/src/main/java/org/apache/kylin/rest/response/TableDescResponse.java
@@ -74,6 +74,7 @@ public class TableDescResponse extends TableDesc {
         this.setColumns(table.getColumns());
         this.setDatabase(table.getDatabase());
         this.setName(table.getName());
+        this.setSourceType(table.getSourceType());
         this.setUuid(table.getUuid());
     }
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/controllers/cubeEdit.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/cubeEdit.js b/webapp/app/js/controllers/cubeEdit.js
index 24bdf8d..748019f 100755
--- a/webapp/app/js/controllers/cubeEdit.js
+++ b/webapp/app/js/controllers/cubeEdit.js
@@ -380,73 +380,6 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
     });
   };
 
-  //save streaming
-  $scope.postData = {};
-  $scope.saveStreaming = function () {
-    $scope.kafkaMeta.name = $scope.streamingMeta.name;
-
-    $scope.postData.streamingMeta = angular.toJson($scope.streamingMeta, true);
-    $scope.postData.kafkaMeta = angular.toJson($scope.kafkaMeta, true);
-    SweetAlert.swal({
-      title: '',
-      text: 'Are you sure to save Streaming ?',
-      type: '',
-      showCancelButton: true,
-      confirmButtonColor: '#DD6B55',
-      confirmButtonText: "Yes",
-      closeOnConfirm: true
-    }, function (isConfirm) {
-      if (isConfirm) {
-        loadingRequest.show();
-
-        if ($scope.modelMode == "editExistStreaming") {
-          StreamingService.update({}, {
-            project: $scope.projectModel.selectedProject,
-            streamingConfig: $scope.postData.streamingMeta,
-            kafkaConfig: $scope.postData.kafkaMeta
-          }, function (request) {
-            if (request.successful) {
-              SweetAlert.swal('', 'Updated the streaming successfully.', 'success');
-              $location.path("/models");
-            } else {
-              var message = request.message;
-              var msg = !!(message) ? message : 'Failed to take action.';
-              MessageService.sendMsg($scope.streamingResultTmpl({
-                'text': msg,
-                'streamingSchema': $scope.postData.streamingMeta,
-                'kfkSchema': $scope.postData.kafkaMeta
-              }), 'error', {}, true, 'top_center');
-            }
-            loadingRequest.hide();
-          })
-        } else {
-          StreamingService.save({}, {
-            project: $scope.projectModel.selectedProject,
-            streamingConfig: $scope.postData.streamingMeta,
-            kafkaConfig: $scope.postData.kafkaMeta
-          }, function (request) {
-            if (request.successful) {
-              SweetAlert.swal('', 'Created the streaming successfully.', 'success');
-              $location.path("/models");
-            } else {
-              var message = request.message;
-              var msg = !!(message) ? message : 'Failed to take action.';
-              MessageService.sendMsg($scope.streamingResultTmpl({
-                'text': msg,
-                'streamingSchema': $scope.postData.streamingMeta,
-                'kfkSchema': $scope.postData.kafkaMeta
-              }), 'error', {}, true, 'top_center');
-            }
-            loadingRequest.hide();
-          })
-        }
-
-      }
-    });
-
-
-  }
-
 
 //    reverse the date
   $scope.saveCubeRollBack = function () {
@@ -732,31 +665,15 @@ KylinApp.controller('CubeEditCtrl', function ($scope, $q, $routeParams, $locatio
     }
   });
 
-
-  //dimensions options is depend on the model input when add cube
-  //$scope.$watch('cubeMetaFrame.model_name', function (newValue, oldValue) {
-  //  if (!newValue) {
-  //    return;
-  //  }
-  //  $scope.metaModel.model = modelsManager.getModel(newValue);
-  //
-  //  if(!$scope.metaModel.model){
-  //    return;
-  //  }
-  //
-  //  var factTable = $scope.metaModel.model.fact_table;
-  //  var cols = $scope.getColumnsByTable(factTable);
-  //
-  //  for(var i=0;i<cols.length;i++){
-  //    var col = cols[i];
-  //    if(col.datatype === "timestamp"){
-  //      $scope.streamingCfg.columnOptions.push(col.name);
-  //    }
-  //  }
-  //  $scope.kafkaMeta.parserProperties = "tsColName=' ';formatTs=TRUE";
-  //
-  //
-  //});
+  $scope.$watch('cubeMetaFrame.model_name', function (newValue, oldValue) {
+    if (!newValue) {
+      return;
+    }
+    $scope.metaModel.model = modelsManager.getModel(newValue);
+    if(!$scope.metaModel.model){
+      return;
+    }
+  });
 
 
   $scope.$on('DimensionsEdited', function (event) {

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/controllers/modelSchema.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/modelSchema.js b/webapp/app/js/controllers/modelSchema.js
index 3c66609..7885758 100644
--- a/webapp/app/js/controllers/modelSchema.js
+++ b/webapp/app/js/controllers/modelSchema.js
@@ -139,7 +139,7 @@ KylinApp.controller('ModelSchemaCtrl', function ($scope, QueryService, UserServi
     else {
       //form validation
       if ($scope.forms[$scope.curStep.form].$invalid) {
-        $scope.forms[$scope.curStep.form].$sbumitted = true;
+        $scope.forms[$scope.curStep.form].$submitted = true;
         return false;
       } else {
         //business rule check

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/controllers/sourceMeta.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/sourceMeta.js b/webapp/app/js/controllers/sourceMeta.js
index 472b18b..1466a5b 100755
--- a/webapp/app/js/controllers/sourceMeta.js
+++ b/webapp/app/js/controllers/sourceMeta.js
@@ -422,7 +422,7 @@ KylinApp
       });
     };
 
-    var StreamingSourceCtrl = function ($scope, $location, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig,cubeConfig,StreamingModel) {
+    var StreamingSourceCtrl = function ($scope, $location,$interpolate,$templateCache, $modalInstance, tableNames, MessageService, projectName, scope, tableConfig,cubeConfig,StreamingModel,StreamingService) {
 
       $scope.cubeState={
         "isStreaming": false
@@ -449,19 +449,26 @@ KylinApp
       }
 
       $scope.nextStep = function(){
+
+        $scope.checkFailed = false;
+
         //check form
-        $scope.form['setStreamingSchema'].$sbumitted = true;
+        $scope.form['setStreamingSchema'].$submitted = true;
         if(!$scope.streaming.sourceSchema||$scope.streaming.sourceSchema===""){
-          return;
+          $scope.checkFailed = true;
         }
 
         if(!$scope.table.name||$scope.table.name===""){
-          return;
+          $scope.checkFailed = true;
         }
 
         $scope.prepareNextStep();
 
         if(!$scope.rule.timestampColumnExist){
+          $scope.checkFailed = true;
+        }
+
+        if($scope.checkFailed){
           return;
         }
 
@@ -470,6 +477,7 @@ KylinApp
 
       $scope.prepareNextStep = function(){
         $scope.streamingCfg.columnOptions = [];
+        $scope.rule.timestampColumnExist = false;
         angular.forEach($scope.columnList,function(column,$index){
           if (column.checked == "Y" && column.fromSource=="Y" && column.type == "timestamp") {
             $scope.streamingCfg.columnOptions.push(column.name);
@@ -551,9 +559,6 @@ KylinApp
             'fromSource':'Y'
           });
 
-
-
-          //var formatList = [];
           //var
           columnList = _.sortBy(columnList, function (i) { return i.type; });
         }
@@ -587,15 +592,35 @@ KylinApp
           })
         }
         $scope.columnList = columnList;
-
       }
 
+
+      $scope.streamingResultTmpl = function (notification) {
+        // Get the static notification template.
+        var tmpl = notification.type == 'success' ? 'streamingResultSuccess.html' : 'streamingResultError.html';
+        return $interpolate($templateCache.get(tmpl))(notification);
+      };
+
+
       $scope.form={};
       $scope.rule={
         'timestampColumnExist':false
       }
+
+      $scope.modelMode == "addStreaming";
+
       $scope.syncStreamingSchema = function () {
 
+        $scope.form['cube_streaming_form'].$submitted = true;
+
+        if($scope.form['cube_streaming_form'].parserName.$invalid || $scope.form['cube_streaming_form'].parserProperties.$invalid) {
+          $scope.state.isParserHeaderOpen = true;
+        }
+
+        if($scope.form['cube_streaming_form'].$invalid){
+            return;
+        }
+
         var columns = [];
         angular.forEach($scope.columnList,function(column,$index){
           if (column.checked == "Y") {
@@ -616,10 +641,13 @@ KylinApp
           'database':'Default'
         }
 
+
+        $scope.kafkaMeta.name = $scope.table.name
+        $scope.streamingMeta.name = $scope.table.name;
+
         SweetAlert.swal({
-          title: '',
-          text: 'Are you sure to create the streaming table info?',
-          type: '',
+          title:"",
+          text: 'Are you sure to save the streaming table and cluster info ?',
           showCancelButton: true,
           confirmButtonColor: '#DD6B55',
           confirmButtonText: "Yes",
@@ -627,31 +655,93 @@ KylinApp
         }, function (isConfirm) {
           if (isConfirm) {
             loadingRequest.show();
-            TableService.addStreamingSrc({}, {project: $scope.projectName,tableData:angular.toJson($scope.tableData)}, function (request) {
-              if(request.success){
+
+            if ($scope.modelMode == "editExistStreaming") {
+              StreamingService.update({}, {
+                project: $scope.projectName,
+                tableData:angular.toJson($scope.tableData),
+                streamingConfig: angular.toJson($scope.streamingMeta),
+                kafkaConfig: angular.toJson($scope.kafkaMeta)
+              }, function (request) {
+                if (request.successful) {
+                  SweetAlert.swal('', 'Updated the streaming successfully.', 'success');
+                  $location.path("/models");
+                } else {
+                  var message = request.message;
+                  var msg = !!(message) ? message : 'Failed to take action.';
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema': angular.toJson($scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                }
                 loadingRequest.hide();
-                SweetAlert.swal('', 'Create Streaming Table Schema Successfully.', 'success');
-                $scope.cancel();
-                scope.aceSrcTbLoaded(true);
-                return;
-              }else{
-                SweetAlert.swal('Oops...', "Failed to take action.", 'error');
-              }
-              //end loading
-              loadingRequest.hide();
-            }, function (e) {
-              if (e.data && e.data.exception) {
-                var message = e.data.exception;
-                var msg = !!(message) ? message : 'Failed to take action.';
-                SweetAlert.swal('Oops...', msg, 'error');
-              } else {
-                SweetAlert.swal('Oops...', "Failed to take action.", 'error');
-              }
-              loadingRequest.hide();
-            });
+              }, function (e) {
+                if (e.data && e.data.exception) {
+                  var message = e.data.exception;
+                  var msg = !!(message) ? message : 'Failed to take action.';
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema': angular.toJson($scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                } else {
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema': angular.toJson($scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                }
+                //end loading
+                loadingRequest.hide();
+
+              })
+            } else {
+              StreamingService.save({}, {
+                project: $scope.projectName,
+                tableData:angular.toJson($scope.tableData),
+                streamingConfig: angular.toJson($scope.streamingMeta),
+                kafkaConfig: angular.toJson($scope.kafkaMeta)
+              }, function (request) {
+                if (request.successful) {
+                  SweetAlert.swal('', 'Created the streaming successfully.', 'success');
+                  location.reload();
+                } else {
+                  var message = request.message;
+                  var msg = !!(message) ? message : 'Failed to take action.';
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema': angular.toJson($scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                }
+                loadingRequest.hide();
+              }, function (e) {
+                if (e.data && e.data.exception) {
+                  var message = e.data.exception;
+                  var msg = !!(message) ? message : 'Failed to take action.';
+
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema':angular.toJson( $scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                } else {
+                  MessageService.sendMsg($scope.streamingResultTmpl({
+                    'text': msg,
+                    'streamingSchema': angular.toJson($scope.streamingMeta,true),
+                    'kfkSchema': angular.toJson($scope.kafkaMeta,true)
+                  }), 'error', {}, true, 'top_center');
+                }
+                //end loading
+                loadingRequest.hide();
+              })
+            }
+
           }
         });
       }
+
     };
 
   });

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/controllers/streamingConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/streamingConfig.js b/webapp/app/js/controllers/streamingConfig.js
index b0a1ebd..4e916db 100644
--- a/webapp/app/js/controllers/streamingConfig.js
+++ b/webapp/app/js/controllers/streamingConfig.js
@@ -18,7 +18,13 @@
 
 'use strict';
 
-KylinApp.controller('streamingConfigCtrl', function ($scope, $q, $routeParams, $location, $window, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, modelConfig, ProjectModel, ModelService, MetaModel, modelsManager, cubesManager, TableModel, $animate,StreamingService,StreamingModel) {
+KylinApp.controller('streamingConfigCtrl', function ($scope,StreamingService, $q, $routeParams, $location, $window, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, modelConfig, ProjectModel, ModelService, MetaModel, modelsManager, cubesManager, TableModel, $animate,StreamingModel) {
+
+  $scope.tableModel = TableModel;
+  $scope.streamingMeta = StreamingModel.createStreamingConfig();
+  $scope.kafkaMeta = StreamingModel.createKafkaConfig();
+
+
 
   $scope.addCluster = function () {
     $scope.kafkaMeta.clusters.push(StreamingModel.createKafkaCluster());
@@ -80,4 +86,27 @@ KylinApp.controller('streamingConfigCtrl', function ($scope, $q, $routeParams, $
     $scope.kafkaMeta.parserProperties = "tsColName="+$scope.streamingCfg.parseTsColumn;
   }
 
+  $scope.$watch('tableModel.selectedSrcTable', function (newValue, oldValue) {
+    if (!newValue) {
+      return;
+    }
+    //view model
+    if($scope.state.mode == 'view' && $scope.tableModel.selectedSrcTable.source_type==1){
+      var table = $scope.tableModel.selectedSrcTable;
+      StreamingService.getConfig({table:table.name}, function (configs) {
+        if(!!configs[0]&&configs[0].name.toUpperCase() == table.name.toUpperCase()){
+          $scope.streamingMeta = configs[0];
+          StreamingService.getKfkConfig({kafkaConfigName:$scope.streamingMeta.name}, function (streamings) {
+            if(!!streamings[0]&&streamings[0].name.toUpperCase() == table.name.toUpperCase()){
+              $scope.kafkaMeta = streamings[0];
+            }
+          })
+        }
+      })
+    }
+
+
+
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/model/streamingModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/streamingModel.js b/webapp/app/js/model/streamingModel.js
index 61560d7..0321806 100644
--- a/webapp/app/js/model/streamingModel.js
+++ b/webapp/app/js/model/streamingModel.js
@@ -22,8 +22,7 @@ KylinApp.service('StreamingModel', function () {
   this.createStreamingConfig = function () {
     var streamingConfig = {
       "name": "",
-      "iiName": "",
-      "cubeName": ""
+      "type":"kafka"
     };
 
     return streamingConfig;

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/js/model/tableModel.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/tableModel.js b/webapp/app/js/model/tableModel.js
index bb124c9..788fbae 100755
--- a/webapp/app/js/model/tableModel.js
+++ b/webapp/app/js/model/tableModel.js
@@ -106,10 +106,15 @@ KylinApp.service('TableModel', function(ProjectModel,$q,TableService,$log) {
                 var _table_node_list = [];
                 angular.forEach(tables,function(_table){
 
+                        var table_icon="fa fa-table";
+                        if(_table.source_type==1){
+                          table_icon="fa fa-th"
+                        }
+
                         var _table_node = {
                             label:_table.name,
                             data:_table,
-                            icon:"fa fa-table",
+                            icon:table_icon,
                             onSelect:function(branch){
                                 // set selected model
                                 _this.selectedSrcTable = branch.data;

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/cubeDesigner/info.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/info.html b/webapp/app/partials/cubeDesigner/info.html
index c9fee9b..a1d876b 100644
--- a/webapp/app/partials/cubeDesigner/info.html
+++ b/webapp/app/partials/cubeDesigner/info.html
@@ -25,7 +25,7 @@
                   <label class="col-xs-12 col-sm-3 control-label no-padding-right">
                     <b>Model Name</b>
                   </label>
-                  <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':forms.cube_info_form.model_name.$invalid && (forms.cube_info_form.model_name.$dirty||forms.cube_info_form.model_name.$sbumitted)}">
+                  <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':forms.cube_info_form.model_name.$invalid && (forms.cube_info_form.model_name.$dirty||forms.cube_info_form.model_name.$submitted)}">
                     <select chosen ng-model="cubeMetaFrame.model_name" ng-if="cubeMode=='addNewCube'"
                             ng-options="model for model in modelsManager.modelNameList"
                             style="width:100%;"
@@ -39,7 +39,7 @@
 
                     <input ng-model="cubeMetaFrame.model_name" ng-disabled="true" class="form-control" ng-if="cubeMode=='editExistCube'"/>
 
-                    <small class="help-block" ng-show="forms.cube_info_form.model_name.$error.required && (forms.cube_info_form.model_name.$dirty||forms.cube_info_form.$sbumitted)">Model name is required.</small>
+                    <small class="help-block" ng-show="forms.cube_info_form.model_name.$error.required && (forms.cube_info_form.model_name.$dirty||forms.cube_info_form.$submitted)">Model name is required.</small>
                     <span ng-if="state.mode=='view'">{{cubeMetaFrame.model_name}}</span>
                   </div>
 
@@ -54,13 +54,13 @@
                     <label class="col-xs-12 col-sm-3 control-label no-padding-right font-color-default">
                         <b>Cube Name</b>
                     </label>
-                    <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.cube_info_form.cube_name.$invalid && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.cube_name.$sbumitted)}">
+                    <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.cube_info_form.cube_name.$invalid && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.cube_name.$submitted)}">
                         <input ng-if="state.mode=='edit'" ng-disabled="{{isEdit}}"  name="cube_name" type="text" class="form-control"
                                ng-model="cubeMetaFrame.name" required
                                placeholder="You can use letters, numbers, and '_'"
                                ng-maxlength=100 ng-pattern="/^\w+$/" />
-                        <small class="help-block" ng-show="forms.cube_info_form.cube_name.$error.required && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.$sbumitted)">Cube name is required.</small>
-                        <small class="help-block" ng-show="!forms.cube_info_form.cube_name.$error.required&&forms.cube_info_form.cube_name.$invalid && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.$sbumitted)">Cube name is invalid.</small>
+                        <small class="help-block" ng-show="forms.cube_info_form.cube_name.$error.required && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.$submitted)">Cube name is required.</small>
+                        <small class="help-block" ng-show="!forms.cube_info_form.cube_name.$error.required&&forms.cube_info_form.cube_name.$invalid && (forms.cube_info_form.cube_name.$dirty||forms.cube_info_form.$submitted)">Cube name is invalid.</small>
 
                         <span ng-if="state.mode=='view'">{{cubeMetaFrame.name}}</span>
                     </div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/cubeDesigner/kafkaBasicConfig.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/kafkaBasicConfig.html b/webapp/app/partials/cubeDesigner/kafkaBasicConfig.html
index d9ca5b1..67c0427 100644
--- a/webapp/app/partials/cubeDesigner/kafkaBasicConfig.html
+++ b/webapp/app/partials/cubeDesigner/kafkaBasicConfig.html
@@ -23,11 +23,11 @@
         <label class="col-xs-12 col-sm-3 control-label no-padding-right">
           <b>Topic</b>
         </label>
-        <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':forms.kafka_config_form.topic.$invalid && (forms.kafka_config_form.topic.$dirty||forms.kafka_config_form.topic.$sbumitted)}">
+        <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':forms.kafka_config_form.topic.$invalid && (forms.kafka_config_form.topic.$dirty||forms.kafka_config_form.topic.$submitted)}">
           <input  ng-if="state.mode=='edit'"  name="name" required ng-model="kafkaMeta.topic" type="text"
                   placeholder="Input kafkaConfig topic"
                   class="form-control"/>
-          <small class="help-block" ng-show="forms.kafka_config_form.topic.$error.required && (forms.kafka_config_form.topic.$dirty||forms.kafka_config_form.$sbumitted)">Kafka topic is required.</small>
+          <small class="help-block" ng-show="forms.kafka_config_form.topic.$error.required && (forms.kafka_config_form.topic.$dirty||forms.kafka_config_form.$submitted)">Kafka topic is required.</small>
           <span ng-if="state.mode=='view'">{{kafkaMeta.topic}}</span>
         </div>
       </div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/cubeDesigner/streamingConfig.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/cubeDesigner/streamingConfig.html b/webapp/app/partials/cubeDesigner/streamingConfig.html
index c3afd26..38cb2cd 100644
--- a/webapp/app/partials/cubeDesigner/streamingConfig.html
+++ b/webapp/app/partials/cubeDesigner/streamingConfig.html
@@ -17,7 +17,7 @@
 -->
 
 <div ng-controller="streamingConfigCtrl">
-  <ng-form name="forms.cube_streaming_form" novalidate>
+  <form name="form.cube_streaming_form" novalidate>
 
     <div>
       <accordion>
@@ -33,11 +33,15 @@
           <label class="col-xs-12 col-sm-3 control-label no-padding-right">
             <b>Topic</b>
           </label>
-          <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':forms.cube_streaming_form.topic.$invalid && (forms.cube_streaming_form.topic.$dirty||forms.cube_streaming_form.topic.$sbumitted)}">
+          <div class="col-xs-12 col-sm-6"   ng-class="{'has-error':form.cube_streaming_form.topic.$invalid && (form.cube_streaming_form.topic.$dirty||form.cube_streaming_form.$submitted)}">
             <input  ng-if="state.mode=='edit'"  name="topic" required ng-model="kafkaMeta.topic" type="text"
                     placeholder="Input kafkaConfig topic"
                     class="form-control"/>
-            <small class="help-block" ng-show="forms.cube_streaming_form.topic.$error.required && (forms.cube_streaming_form.topic.$dirty||forms.cube_streaming_form.$sbumitted)">Kafka topic is required.</small>
+            <small class="help-block"
+                   ng-show="!form.cube_streaming_form.topic.$error.required && form.cube_streaming_form.topic.$invalid && (form.cube_streaming_form.topic.$dirty||form.cube_streaming_form.$submitted)">
+              Kafka topic is invalid.
+            </small>
+            <small class="help-block" ng-show="form.cube_streaming_form.topic.$error.required && (form.cube_streaming_form.topic.$dirty||form.cube_streaming_form.$submitted)">Kafka topic is required.</small>
             <span ng-if="state.mode=='view'">{{kafkaMeta.topic}}</span>
           </div>
         </div>
@@ -136,12 +140,17 @@
               </label>
 
               <div class="col-xs-12 col-sm-6"
-                   ng-class="{'has-error':forms.cube_streaming_form.timeout.$invalid && (forms.cube_streaming_form.timeout.$dirty||forms.cube_streaming_form.timeout.$sbumitted)}">
-                <input ng-if="state.mode=='edit'" name="name" required ng-model="kafkaMeta.timeout" type="text"
+                   ng-class="{'has-error':form.cube_streaming_form.timeout.$invalid && (form.cube_streaming_form.timeout.$dirty||form.cube_streaming_form.$submitted)}">
+                <input ng-if="state.mode=='edit'" name="timeout" required ng-model="kafkaMeta.timeout" type="text"
                        placeholder="Input kafkaConfig timeout"
+                       ng-maxlength=100 ng-pattern="/^\+?[1-9][0-9]*$/"
                        class="form-control"/>
                 <small class="help-block"
-                       ng-show="forms.cube_streaming_form.timeout.$error.required && (forms.cube_streaming_form.timeout.$dirty||forms.cube_streaming_form.$sbumitted)">
+                       ng-show="!form.cube_streaming_form.timeout.$error.required && form.cube_streaming_form.timeout.$invalid && (form.cube_streaming_form.timeout.$dirty||form.cube_streaming_form.$submitted)">
+                  Kafka timeout is invalid.
+                </small>
+                <small class="help-block"
+                       ng-show="form.cube_streaming_form.timeout.$error.required && (form.cube_streaming_form.timeout.$dirty||form.cube_streaming_form.$submitted)">
                   Kafka timeout is required.
                 </small>
                 <span ng-if="state.mode=='view'">{{kafkaMeta.timeout}}</span>
@@ -156,12 +165,17 @@
               </label>
 
               <div class="col-xs-12 col-sm-6"
-                   ng-class="{'has-error':forms.cube_streaming_form.bufferSize.$invalid && (forms.cube_streaming_form.bufferSize.$dirty||forms.cube_streaming_form.bufferSize.$sbumitted)}">
-                <input ng-if="state.mode=='edit'" name="name" required ng-model="kafkaMeta.bufferSize" type="text"
+                   ng-class="{'has-error':form.cube_streaming_form.bufferSize.$invalid && (form.cube_streaming_form.bufferSize.$dirty||form.cube_streaming_form.$submitted)}">
+                <input ng-if="state.mode=='edit'" name="bufferSize" required ng-model="kafkaMeta.bufferSize" type="text"
                        placeholder="Input kafkaConfig bufferSize"
+                       ng-maxlength=100 ng-pattern="/^\+?[1-9][0-9]*$/"
                        class="form-control"/>
                 <small class="help-block"
-                       ng-show="forms.cube_streaming_form.bufferSize.$error.required && (forms.cube_streaming_form.bufferSize.$dirty||forms.cube_streaming_form.$sbumitted)">
+                       ng-show="!form.cube_streaming_form.bufferSize.$error.required && form.cube_streaming_form.bufferSize.$invalid && (form.cube_streaming_form.bufferSize.$dirty||form.cube_streaming_form.$submitted)">
+                  Kafka bufferSize is invalid.
+                </small>
+                <small class="help-block"
+                       ng-show="form.cube_streaming_form.bufferSize.$error.required && (form.cube_streaming_form.bufferSize.$dirty||form.cube_streaming_form.$submitted)">
                   Kafka bufferSize is required.
                 </small>
                 <span ng-if="state.mode=='view'">{{kafkaMeta.bufferSize}}</span>
@@ -176,12 +190,17 @@
               </label>
 
               <div class="col-xs-12 col-sm-6"
-                   ng-class="{'has-error':forms.cube_streaming_form.margin.$invalid && (forms.cube_streaming_form.margin.$dirty||forms.cube_streaming_form.margin.$sbumitted)}">
-                <input ng-if="state.mode=='edit'" name="name" required ng-model="kafkaMeta.margin" type="text"
+                   ng-class="{'has-error':form.cube_streaming_form.margin.$invalid && (form.cube_streaming_form.margin.$dirty||form.cube_streaming_form.$submitted)}">
+                <input ng-if="state.mode=='edit'" name="margin" required ng-model="kafkaMeta.margin" type="text"
                        placeholder="Input kafkaConfig margin"
+                       ng-maxlength=100 ng-pattern="/^\+?[1-9][0-9]*$/"
                        class="form-control"/>
                 <small class="help-block"
-                       ng-show="forms.cube_streaming_form.margin.$error.required && (forms.cube_streaming_form.margin.$dirty||forms.cube_streaming_form.$sbumitted)">
+                       ng-show="!form.cube_streaming_form.margin.$error.required && form.cube_streaming_form.margin.$invalid && (form.cube_streaming_form.margin.$dirty||form.cube_streaming_form.$submitted)">
+                  Kafka margin is invalid.
+                </small>
+                <small class="help-block"
+                       ng-show="form.cube_streaming_form.margin.$error.required && (form.cube_streaming_form.margin.$dirty||form.cube_streaming_form.$submitted)">
                   Kafka margin is required.
                 </small>
                 <span ng-if="state.mode=='view'">{{kafkaMeta.margin}}</span>
@@ -208,13 +227,17 @@
               </label>
 
               <div class="col-xs-12 col-sm-6"
-                   ng-class="{'has-error':forms.cube_streaming_form.parserName.$invalid && (forms.cube_streaming_form.parserName.$dirty||forms.cube_streaming_form.parserName.$sbumitted)}">
-                <input ng-if="state.mode=='edit'" name="name" required ng-model="kafkaMeta.parserName" type="text"
+                   ng-class="{'has-error':form.cube_streaming_form.parserName.$invalid && (form.cube_streaming_form.parserName.$dirty||form.cube_streaming_form.$submitted)}">
+                <input ng-if="state.mode=='edit'" name="parserName" required ng-model="kafkaMeta.parserName" type="text"
                        placeholder="Input kafkaConfig parserName"
                        class="form-control"/>
                 <small class="help-block"
-                       ng-show="forms.cube_streaming_form.parserName.$error.required && (forms.cube_streaming_form.parserName.$dirty||forms.cube_streaming_form.$sbumitted)">
-                  Kafka parserName is required.
+                       ng-show="!form.cube_streaming_form.parserName.$error.required && form.cube_streaming_form.parserName.$invalid && (form.cube_streaming_form.parserName.$dirty||form.cube_streaming_form.$submitted)">
+                  Kafka parser name is invalid.
+                </small>
+                <small class="help-block"
+                       ng-show="form.cube_streaming_form.parserName.$error.required && (form.cube_streaming_form.parserName.$dirty||form.cube_streaming_form.$submitted)">
+                  Kafka parser name is required.
                 </small>
                 <span ng-if="state.mode=='view'">{{kafkaMeta.parserName}}</span>
               </div>
@@ -244,13 +267,17 @@
               </label>
 
               <div class="col-xs-12 col-sm-6"
-                   ng-class="{'has-error':forms.cube_streaming_form.parserProperties.$invalid && (forms.cube_streaming_form.parserProperties.$dirty||forms.cube_streaming_form.parserProperties.$sbumitted)}">
-                <input ng-if="state.mode=='edit'" name="name" required ng-model="kafkaMeta.parserProperties" type="text"
+                   ng-class="{'has-error':form.cube_streaming_form.parserProperties.$invalid && (form.cube_streaming_form.parserProperties.$dirty||form.cube_streaming_form.$submitted)}">
+                <input ng-if="state.mode=='edit'" name="parserProperties" required ng-model="kafkaMeta.parserProperties" type="text"
                        placeholder="configA=1;configB=2"
                        class="form-control"/>
                 <small class="help-block"
-                       ng-show="forms.cube_streaming_form.parserProperties.$error.required && (forms.cube_streaming_form.parserProperties.$dirty||forms.cube_streaming_form.$sbumitted)">
-                  Parser Properties is required.
+                       ng-show="!form.cube_streaming_form.parserProperties.$error.required && form.cube_streaming_form.parserProperties.$invalid && (form.cube_streaming_form.parserProperties.$dirty||form.cube_streaming_form.$submitted)">
+                  Parser properties is invalid.
+                </small>
+                <small class="help-block"
+                       ng-show="form.cube_streaming_form.parserProperties.$error.required && (form.cube_streaming_form.parserProperties.$dirty||form.cube_streaming_form.$submitted)">
+                  Parser properties is required.
                 </small>
                 <span ng-if="state.mode=='view'">{{kafkaMeta.parserProperties}}</span>
               </div>
@@ -260,5 +287,5 @@
       </accordion>
 
     </div>
-  </ng-form>
+  </form>
 </div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/modelDesigner/data_model.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/modelDesigner/data_model.html b/webapp/app/partials/modelDesigner/data_model.html
index 83ba101..d1a9cdd 100644
--- a/webapp/app/partials/modelDesigner/data_model.html
+++ b/webapp/app/partials/modelDesigner/data_model.html
@@ -25,7 +25,7 @@
             <label class="col-xs-12 col-sm-2 control-label concube.detailtrol-label no-padding-right font-color-default">
                 <b>Fact Table</b>
             </label>
-            <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.data_model_form.table_name.$invalid && (forms.data_model_form.table_name.$dirty||forms.data_model_form.$sbumitted)}">
+            <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.data_model_form.table_name.$invalid && (forms.data_model_form.table_name.$dirty||forms.data_model_form.$submitted)}">
               <select chosen ng-model="modelsManager.selectedModel.fact_table" ng-if="state.mode=='edit'"
                       ng-options="table.name as table.name for table in tableModel.selectProjectTables"
                       style="width:100%;"
@@ -36,7 +36,7 @@
                 <option value=""> -- Select Fact Table -- </option>
               </select>
 
-                <small class="help-block" ng-show="forms.data_model_form.innerform.typeahead.$error.required && (forms.data_model_form.innerform.typeahead.$dirty||forms.data_model_form.$sbumitted)">The fact table is required</small>
+                <small class="help-block" ng-show="forms.data_model_form.innerform.typeahead.$error.required && (forms.data_model_form.innerform.typeahead.$dirty||forms.data_model_form.$submitted)">The fact table is required</small>
                 <span ng-if="state.mode=='view'">{{modelsManager.selectedModel.fact_table}}</span>
             </div>
         </div>
@@ -121,7 +121,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>Lookup Table Name</b></label>
-                            <div ng-class="{'has-error':lookup_form.table_name.$invalid && (lookup_form.table_name.$dirty||forms.model_info_form.$sbumitted)}">
+                            <div ng-class="{'has-error':lookup_form.table_name.$invalid && (lookup_form.table_name.$dirty||forms.model_info_form.$submitted)}">
                                 <div class="col-xs-12 col-sm-6">
                                   <select chosen ng-model="newLookup.table"
                                           ng-options="table.name as table.name for table in tableModel.selectProjectTables"
@@ -133,7 +133,7 @@
                                     <option value=""> -- Select Lookup Table -- </option>
                                   </select>
 
-                                    <small class="help-block" ng-show="lookup_form.table_name.$invalid && (lookup_form.table_name.$dirty||forms.model_info_form.$sbumitted)">Table name required</small>
+                                    <small class="help-block" ng-show="lookup_form.table_name.$invalid && (lookup_form.table_name.$dirty||forms.model_info_form.$submitted)">Table name required</small>
                                 </div>
                             </div>
                         </div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/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 bace322..a6ad300 100644
--- a/webapp/app/partials/modelDesigner/model_info.html
+++ b/webapp/app/partials/modelDesigner/model_info.html
@@ -28,15 +28,15 @@
                         <b>Model Name</b>
                     </label>
 
-                    <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.model_info_form.model_name.$invalid && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$sbumitted)}">
+                    <div class="col-xs-12 col-sm-6" ng-class="{'has-error':forms.model_info_form.model_name.$invalid && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$submitted)}">
 
                         <!-- edit -->
                         <input ng-if="state.mode=='edit'" name="model_name" type="text" class="form-control"  ng-disabled="{{modelMode=='editExistModel'}}"
                                ng-model="modelsManager.selectedModel.name" required
                                placeholder="You can use letters, numbers, and '_'"
                                ng-maxlength=100 ng-pattern="/^\w+$/" />
-                        <small class="help-block" ng-show="forms.model_info_form.model_name.$error.required && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$sbumitted)">Model name is required.</small>
-                        <small class="help-block" ng-show="!forms.model_info_form.model_name.$error.required&&forms.model_info_form.model_name.$invalid && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$sbumitted)">Model name is invalid.</small>
+                        <small class="help-block" ng-show="forms.model_info_form.model_name.$error.required && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$submitted)">Model name is required.</small>
+                        <small class="help-block" ng-show="!forms.model_info_form.model_name.$error.required&&forms.model_info_form.model_name.$invalid && (forms.model_info_form.model_name.$dirty||forms.model_info_form.$submitted)">Model name is invalid.</small>
 
 
                         <span ng-if="state.mode=='view'">{{modelsManager.selectedModel.name}}</span>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/tables/loadStreamingTable.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/loadStreamingTable.html b/webapp/app/partials/tables/loadStreamingTable.html
index 5e6116c..da79369 100644
--- a/webapp/app/partials/tables/loadStreamingTable.html
+++ b/webapp/app/partials/tables/loadStreamingTable.html
@@ -5,19 +5,20 @@
       Need to input streaming source record here, will detect the source schema and create a table schema for
       streaming.
     </p>
-    <div class="has-error" ng-if="!table.sourceValid&&table.schemaChecked">
-      <small class="help-block">
-        Source json invalid.
-      </small>
-    </div>
+
     <div style="padding:15px;" class="has-error">
-      <small class="help-block" ng-show="streaming.sourceSchema==''&&form.setStreamingSchema.$sbumitted">Please
+      <small class="help-block" ng-show="streaming.sourceSchema==''&&form.setStreamingSchema.$submitted">Please
         input Streaming source record to generate schema.
       </small>
+      <small class="help-block" ng-if="!table.sourceValid&&table.schemaChecked">
+        Source json invalid, Please correct your schema and generate again.
+      </small>
     </div>
+
     <div style="margin-bottom: 20px;">
       <span class="label label-info">JSON</span>
     </div>
+
     <div ng-model="streaming.sourceSchema" ui-ace="{
     useWrapMode : true,
     mode:'json',
@@ -40,10 +41,10 @@
         <label class="col-xs-4 control-label" style="text-align: left;">Table Name</label>
 
         <div class="col-xs-8"
-             ng-class="{'has-error':form.setStreamingSchema.streamingObject.$invalid && (form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)}">
+             ng-class="{'has-error':form.setStreamingSchema.streamingObject.$invalid && (form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$submitted)}">
           <input type="text" name="streamingObject" required="" ng-model="table.name" class="form-control"/>
           <small class="help-block"
-                 ng-show="form.setStreamingSchema.streamingObject.$error.required&&(form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$sbumitted)">
+                 ng-show="form.setStreamingSchema.streamingObject.$error.required&&(form.setStreamingSchema.streamingObject.$dirty||form.setStreamingSchema.$submitted)">
             Table name is required.
           </small>
         </div>
@@ -80,7 +81,7 @@
       </tr>
     </table>
 
-    <div class="has-error" ng-if="!rule.timestampColumnExist&&form.setStreamingSchema.$sbumitted">
+    <div class="has-error" ng-if="!rule.timestampColumnExist&&form.setStreamingSchema.$submitted">
       <small class="help-block">
         You should choose at least one 'timestamp' type column generated from source schema.
       </small>

http://git-wip-us.apache.org/repos/asf/kylin/blob/376d695c/webapp/app/partials/tables/table_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/tables/table_detail.html b/webapp/app/partials/tables/table_detail.html
index b232375..a4548a1 100644
--- a/webapp/app/partials/tables/table_detail.html
+++ b/webapp/app/partials/tables/table_detail.html
@@ -28,6 +28,9 @@
         <li>
           <a data-toggle="tab" href="#schema">Extend Information</a>
         </li>
+        <li>
+          <a data-toggle="tab" ng-if="tableModel.selectedSrcTable.source_type==1" href="#streaming">Streaming Cluster</a>
+        </li>
       </ul>
       <div class="tab-content">
         <!--Schema-->
@@ -143,8 +146,15 @@
             </div>
           </div>
         </div>
+
+        <!--streaming-->
+        <div id="streaming" ng-show="tableModel.selectedSrcTable.source_type==1" class="tab-pane">
+          <div  ng-include="'partials/cubeDesigner/streamingConfig.html'" ng-init="state.mode='view'"></div>
+        </div>
+
+      </div>
+
       </div>
-    </div>
   </div>