KYLIN-2632 Refactor REST API for better convention

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

Branch: refs/heads/master
Commit: 73a78dbee84808de42925ca5a0b8e16761840233
Parents: 429dfbd
Author: Luwei-Chen <chenlu...@apache.org>
Authored: Fri May 19 21:49:31 2017 +0800
Committer: liyang-gmt8 <liy...@apache.org>
Committed: Sun May 21 09:18:59 2017 +0800

----------------------------------------------------------------------
 .../org/apache/kylin/cube/CubeDescManager.java  |  91 ++-
 .../org/apache/kylin/cube/model/CubeDesc.java   |  56 +-
 .../validation/rule/DictionaryRuleTest.java     |   8 +-
 .../model/validation/rule/FunctionRuleTest.java |   6 +-
 .../apache/kylin/metadata/MetadataManager.java  |  16 +-
 .../kylin/metadata/model/DataModelDesc.java     |  49 +-
 .../kylin/metadata/model/JoinTableDesc.java     |   6 +-
 .../apache/kylin/metadata/model/JoinsTree.java  |  10 +
 .../kylin/metadata/model/TableExtDesc.java      |  10 +
 .../org/apache/kylin/engine/mr/IMRInput.java    |   3 -
 .../java/org/apache/kylin/engine/mr/MRUtil.java |  14 +-
 .../kylin/rest/controller/AccessController.java |  12 +-
 .../kylin/rest/controller/AdminController.java  |  34 +-
 .../kylin/rest/controller/CacheController.java  |   8 +-
 .../kylin/rest/controller/CubeController.java   |  67 +-
 .../rest/controller/CubeDescController.java     |   6 +-
 .../rest/controller/DiagnosisController.java    |   9 +-
 .../rest/controller/EncodingController.java     |   5 +-
 .../controller/ExternalFilterController.java    |  10 +-
 .../kylin/rest/controller/HybridController.java |  13 +-
 .../kylin/rest/controller/JobController.java    |  21 +-
 .../kylin/rest/controller/ModelController.java  |  17 +-
 .../rest/controller/ModelDescController.java    |   4 +-
 .../rest/controller/ProjectController.java      |  19 +-
 .../kylin/rest/controller/QueryController.java  |  14 +-
 .../rest/controller/StreamingController.java    |  16 +-
 .../kylin/rest/controller/TableController.java  |  16 +-
 .../kylin/rest/controller/UserController.java   |  11 +-
 .../rest/controller2/AccessControllerV2.java    | 135 ++++
 .../rest/controller2/AdminControllerV2.java     | 106 +++
 .../rest/controller2/CacheControllerV2.java     |  91 +++
 .../rest/controller2/CubeControllerV2.java      | 755 +++++++++++++++++++
 .../rest/controller2/CubeDescControllerV2.java  | 141 ++++
 .../rest/controller2/DiagnosisControllerV2.java | 121 +++
 .../rest/controller2/EncodingControllerV2.java  |  80 ++
 .../controller2/ExternalFilterControllerV2.java | 101 +++
 .../rest/controller2/HybridControllerV2.java    |  97 +++
 .../kylin/rest/controller2/JobControllerV2.java | 222 ++++++
 .../rest/controller2/ModelControllerV2.java     | 284 +++++++
 .../rest/controller2/ModelDescControllerV2.java | 107 +++
 .../rest/controller2/ProjectControllerV2.java   | 269 +++++++
 .../rest/controller2/QueryControllerV2.java     | 186 +++++
 .../rest/controller2/StreamingControllerV2.java | 288 +++++++
 .../rest/controller2/TableControllerV2.java     | 159 ++++
 .../rest/controller2/UserControllerV2.java      | 103 +++
 .../rest/exception/BadRequestException.java     |   1 +
 .../org/apache/kylin/rest/model/ColumnMeta.java |  46 +-
 .../kylin/rest/model/ColumnMetaWithType.java    |  70 ++
 .../org/apache/kylin/rest/model/TableMeta.java  |  20 +-
 .../kylin/rest/model/TableMetaWithType.java     |  57 ++
 .../org/apache/kylin/rest/msg/CnMessage.java    |  38 +
 .../java/org/apache/kylin/rest/msg/Message.java | 588 +++++++++++++++
 .../org/apache/kylin/rest/msg/MsgPicker.java    |  42 ++
 .../kylin/rest/request/HiveTableRequestV2.java  |  59 ++
 .../rest/response/CubeInstanceResponse.java     |  72 ++
 .../rest/response/DataModelDescResponse.java    |  62 ++
 .../kylin/rest/response/HBaseResponse.java      |   9 +
 .../kylin/rest/response/ResponseCode.java       |   2 +-
 .../security/KylinAuthenticationProvider.java   |   2 +
 .../kylin/rest/security/LdapProvider.java       |   2 +
 .../kylin/rest/service/AccessService.java       |  59 +-
 .../apache/kylin/rest/service/AclService.java   |  49 +-
 .../apache/kylin/rest/service/AdminService.java |  63 +-
 .../apache/kylin/rest/service/CacheService.java |  10 +-
 .../apache/kylin/rest/service/CubeService.java  |  55 +-
 .../kylin/rest/service/CubeServiceV2.java       | 497 ++++++++++++
 .../kylin/rest/service/DiagnosisService.java    |  18 +-
 .../kylin/rest/service/EncodingService.java     |   7 +-
 .../kylin/rest/service/ExtFilterService.java    |  12 +-
 .../apache/kylin/rest/service/JobService.java   | 122 +--
 .../kylin/rest/service/KafkaConfigService.java  |   8 +-
 .../apache/kylin/rest/service/ModelService.java |  20 +-
 .../kylin/rest/service/ModelServiceV2.java      | 351 +++++++++
 .../kylin/rest/service/ProjectService.java      |   2 +
 .../kylin/rest/service/ProjectServiceV2.java    |  89 +++
 .../apache/kylin/rest/service/QueryService.java |  14 +-
 .../kylin/rest/service/QueryServiceV2.java      | 516 +++++++++++++
 .../kylin/rest/service/StreamingService.java    |   8 +-
 .../apache/kylin/rest/service/TableService.java |   9 +-
 .../kylin/rest/service/TableServiceV2.java      | 229 ++++++
 .../apache/kylin/rest/service/UserService.java  |  31 +-
 .../kylin/rest/util/ControllerSplitter.java     |  81 ++
 .../src/main/resources/applicationContext.xml   |   4 +-
 .../rest/controller/AccessControllerTest.java   |   4 +
 .../rest/controller/AdminControllerTest.java    |   4 +
 .../rest/controller/CacheControllerTest.java    |   2 +
 .../rest/controller/CubeControllerTest.java     |   6 +
 .../rest/controller/JobControllerTest.java      |   3 +
 .../rest/controller/ProjectControllerTest.java  |   2 +
 .../rest/controller/QueryControllerTest.java    |   3 +
 .../kylin/rest/service/AccessServiceTest.java   |   2 +
 .../kylin/rest/service/CubeServiceTest.java     |   3 +
 .../kylin/rest/service/JobServiceTest.java      |   3 +
 .../kylin/rest/service/ModelServiceTest.java    |   2 +
 .../kylin/rest/service/QueryServiceTest.java    |   3 +
 .../kylin/rest/service/ServiceTestBase.java     |   2 +
 .../kylin/rest/service/UserServiceTest.java     |   5 +-
 .../apache/kylin/source/hive/HiveMRInput.java   |  11 +-
 .../cardinality/ColumnCardinalityMapper.java    |   2 +-
 .../cardinality/HiveColumnCardinalityJob.java   |   2 +-
 .../apache/kylin/source/kafka/KafkaMRInput.java |   5 -
 101 files changed, 6748 insertions(+), 436 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java
----------------------------------------------------------------------
diff --git a/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java 
b/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java
index 00fa705..bfe9937 100644
--- a/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java
+++ b/core-cube/src/main/java/org/apache/kylin/cube/CubeDescManager.java
@@ -185,7 +185,11 @@ public class CubeDescManager {
             throw new IllegalArgumentException("No cube desc found at " + 
path);
 
         try {
-            ndesc.init(config);
+            if (ndesc.getStatus() == null) {
+                ndesc.init(config);
+            } else {
+                ndesc.initConfig(config);
+            }
         } catch (Exception e) {
             logger.warn("Broken cube desc " + path, e);
             ndesc.addError(e.getMessage());
@@ -211,25 +215,34 @@ public class CubeDescManager {
         if (cubeDescMap.containsKey(cubeDesc.getName()))
             throw new IllegalArgumentException("CubeDesc '" + 
cubeDesc.getName() + "' already exists");
 
-        try {
-            cubeDesc.init(config);
-        } catch (Exception e) {
-            logger.warn("Broken cube desc " + cubeDesc, e);
-            cubeDesc.addError(e.getMessage());
-        }
-        postProcessCubeDesc(cubeDesc);
-        // Check base validation
-        if (!cubeDesc.getError().isEmpty()) {
-            return cubeDesc;
-        }
-        // Semantic validation
-        CubeMetadataValidator validator = new CubeMetadataValidator();
-        ValidateContext context = validator.validate(cubeDesc);
-        if (!context.ifPass()) {
-            return cubeDesc;
-        }
+        if (cubeDesc.getStatus() == null) {
+            try {
+                cubeDesc.init(config);
+            } catch (Exception e) {
+                logger.warn("Broken cube desc " + cubeDesc, e);
+                cubeDesc.addError(e.getMessage());
+            }
+            postProcessCubeDesc(cubeDesc);
+            // Check base validation
+            if (!cubeDesc.getError().isEmpty()) {
+                return cubeDesc;
+            }
+            // Semantic validation
+            CubeMetadataValidator validator = new CubeMetadataValidator();
+            ValidateContext context = validator.validate(cubeDesc);
+            if (!context.ifPass()) {
+                return cubeDesc;
+            }
 
-        cubeDesc.setSignature(cubeDesc.calculateSignature());
+            cubeDesc.setSignature(cubeDesc.calculateSignature());
+        } else {
+            try {
+                cubeDesc.initConfig(config);
+            } catch (Exception e) {
+                logger.warn("Broken cube desc " + cubeDesc, e);
+                cubeDesc.addError(e.getMessage());
+            }
+        }
 
         String path = cubeDesc.getResourcePath();
         getStore().putResource(path, cubeDesc, CUBE_DESC_SERIALIZER);
@@ -336,23 +349,33 @@ public class CubeDescManager {
             throw new IllegalArgumentException("CubeDesc '" + name + "' does 
not exist.");
         }
 
-        try {
-            desc.init(config);
-        } catch (Exception e) {
-            logger.warn("Broken cube desc " + desc, e);
-            desc.addError(e.getMessage());
-            return desc;
-        }
+        if (desc.getStatus() == null) {
+            try {
+                desc.init(config);
+            } catch (Exception e) {
+                logger.warn("Broken cube desc " + desc, e);
+                desc.addError(e.getMessage());
+                return desc;
+            }
 
-        postProcessCubeDesc(desc);
-        // Semantic validation
-        CubeMetadataValidator validator = new CubeMetadataValidator();
-        ValidateContext context = validator.validate(desc);
-        if (!context.ifPass()) {
-            return desc;
-        }
+            postProcessCubeDesc(desc);
+            // Semantic validation
+            CubeMetadataValidator validator = new CubeMetadataValidator();
+            ValidateContext context = validator.validate(desc);
+            if (!context.ifPass()) {
+                return desc;
+            }
 
-        desc.setSignature(desc.calculateSignature());
+            desc.setSignature(desc.calculateSignature());
+        } else {
+            try {
+                desc.initConfig(config);
+            } catch (Exception e) {
+                logger.warn("Broken cube desc " + desc, e);
+                desc.addError(e.getMessage());
+                return desc;
+            }
+        }
 
         // Save Source
         String path = desc.getResourcePath();

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java
----------------------------------------------------------------------
diff --git a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java 
b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java
index dfbe6e7..817cc60 100644
--- a/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java
+++ b/core-cube/src/main/java/org/apache/kylin/cube/model/CubeDesc.java
@@ -102,6 +102,8 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
         LOOKUP, PK_FK, EXTENDED_COLUMN
     }
 
+    public static final String STATUS_DRAFT = "DRAFT";
+
     public static class DeriveInfo implements java.io.Serializable {
         public DeriveType type;
         public JoinDesc join;
@@ -127,6 +129,8 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
 
     @JsonProperty("name")
     private String name;
+    @JsonProperty("status")
+    private String status;
     @JsonProperty("model_name")
     private String modelName;
     @JsonProperty("description")
@@ -199,18 +203,18 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
      * @return all columns this cube can support, including derived
      */
     public Set<TblColRef> listAllColumns() {
-        return allColumns;
+        return allColumns == null ? null : 
Collections.unmodifiableSet(allColumns);
     }
 
     public Set<ColumnDesc> listAllColumnDescs() {
-        return allColumnDescs;
+        return allColumnDescs == null ? null : 
Collections.unmodifiableSet(allColumnDescs);
     }
 
     /**
      * @return dimension columns including derived, BUT NOT measures
      */
     public Set<TblColRef> listDimensionColumnsIncludingDerived() {
-        return dimensionColumns;
+        return dimensionColumns == null ? null : 
Collections.unmodifiableSet(dimensionColumns);
     }
 
     /**
@@ -322,6 +326,14 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
         this.name = name;
     }
 
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
     public String getModelName() {
         return modelName;
     }
@@ -351,7 +363,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<DimensionDesc> getDimensions() {
-        return dimensions;
+        return dimensions == null ? null : 
Collections.unmodifiableList(dimensions);
     }
 
     public void setDimensions(List<DimensionDesc> dimensions) {
@@ -359,7 +371,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<MeasureDesc> getMeasures() {
-        return measures;
+        return measures == null ? null : 
Collections.unmodifiableList(measures);
     }
 
     public void setMeasures(List<MeasureDesc> measures) {
@@ -367,10 +379,10 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<DictionaryDesc> getDictionaries() {
-        return dictionaries;
+        return dictionaries == null ? null : 
Collections.unmodifiableList(dictionaries);
     }
 
-    void setDictionaries(List<DictionaryDesc> dictionaries) {
+    public void setDictionaries(List<DictionaryDesc> dictionaries) {
         this.dictionaries = dictionaries;
     }
 
@@ -383,7 +395,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<AggregationGroup> getAggregationGroups() {
-        return aggregationGroups;
+        return aggregationGroups == null ? null : 
Collections.unmodifiableList(aggregationGroups);
     }
 
     public void setAggregationGroups(List<AggregationGroup> aggregationGroups) 
{
@@ -399,7 +411,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<String> getNotifyList() {
-        return notifyList;
+        return notifyList == null ? null : 
Collections.unmodifiableList(notifyList);
     }
 
     public void setNotifyList(List<String> notifyList) {
@@ -407,7 +419,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     }
 
     public List<String> getStatusNeedNotify() {
-        return statusNeedNotify;
+        return statusNeedNotify == null ? null : 
Collections.unmodifiableList(statusNeedNotify);
     }
 
     public void setStatusNeedNotify(List<String> statusNeedNotify) {
@@ -596,6 +608,29 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
         amendAllColumns();
     }
 
+    // initialize config only for draft cube desc
+    public void initConfig(KylinConfig config) {
+        this.errors.clear();
+
+        checkArgument(StringUtils.isNotBlank(name), "CubeDesc name is blank");
+        checkArgument(StringUtils.isNotBlank(modelName), "CubeDesc (%s) has 
blank model name", name);
+
+        // note CubeDesc.name == CubeInstance.name
+        List<ProjectInstance> ownerPrj = 
ProjectManager.getInstance(config).findProjects(RealizationType.CUBE, name);
+
+        // cube inherit the project override props
+        if (ownerPrj.size() == 1) {
+            Map<String, String> prjOverrideProps = 
ownerPrj.get(0).getOverrideKylinProps();
+            for (Entry<String, String> entry : prjOverrideProps.entrySet()) {
+                if (!overrideKylinProps.containsKey(entry.getKey())) {
+                    overrideKylinProps.put(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+
+        this.config = KylinConfigExt.createInstance(config, 
overrideKylinProps);
+    }
+
     public void validateAggregationGroups() {
         int index = 0;
 
@@ -1218,6 +1253,7 @@ public class CubeDesc extends RootPersistentEntity 
implements IEngineAware {
     public static CubeDesc getCopyOf(CubeDesc cubeDesc) {
         CubeDesc newCubeDesc = new CubeDesc();
         newCubeDesc.setName(cubeDesc.getName());
+        newCubeDesc.setStatus(cubeDesc.getStatus());
         newCubeDesc.setModelName(cubeDesc.getModelName());
         newCubeDesc.setDescription(cubeDesc.getDescription());
         newCubeDesc.setNullStrings(cubeDesc.getNullStrings());

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/DictionaryRuleTest.java
----------------------------------------------------------------------
diff --git 
a/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/DictionaryRuleTest.java
 
b/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/DictionaryRuleTest.java
index fcb723e..0dd9b76 100644
--- 
a/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/DictionaryRuleTest.java
+++ 
b/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/DictionaryRuleTest.java
@@ -28,7 +28,9 @@ import static org.junit.Assert.assertTrue;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.List;
 
+import com.google.common.collect.Lists;
 import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.util.JsonUtil;
 import org.apache.kylin.common.util.LocalFileMetadataTestCase;
@@ -109,9 +111,11 @@ public class DictionaryRuleTest extends 
LocalFileMetadataTestCase {
         File f = new File(LocalFileMetadataTestCase.LOCALMETA_TEST_DATA + 
"/cube_desc/test_kylin_cube_without_slr_left_join_desc.json");
         CubeDesc desc = JsonUtil.readValue(new FileInputStream(f), 
CubeDesc.class);
 
+        List<DictionaryDesc> newDicts = 
Lists.newArrayList(desc.getDictionaries());
         for (DictionaryDesc dictDesc : descs) {
-            desc.getDictionaries().add(dictDesc);
+            newDicts.add(dictDesc);
         }
+        desc.setDictionaries(newDicts);
 
         desc.init(config);
         ValidateContext vContext = new ValidateContext();
@@ -125,4 +129,4 @@ public class DictionaryRuleTest extends 
LocalFileMetadataTestCase {
             assertTrue(actualMessage.startsWith(expectMessage));
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/FunctionRuleTest.java
----------------------------------------------------------------------
diff --git 
a/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/FunctionRuleTest.java
 
b/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/FunctionRuleTest.java
index 18d84c3..5368e16 100644
--- 
a/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/FunctionRuleTest.java
+++ 
b/core-cube/src/test/java/org/apache/kylin/cube/model/validation/rule/FunctionRuleTest.java
@@ -23,7 +23,9 @@ import static org.junit.Assert.assertTrue;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.List;
 
+import com.google.common.collect.Lists;
 import org.apache.kylin.common.KylinConfig;
 import org.apache.kylin.common.util.JsonUtil;
 import org.apache.kylin.common.util.LocalFileMetadataTestCase;
@@ -67,7 +69,9 @@ public class FunctionRuleTest extends 
LocalFileMetadataTestCase {
         CubeDesc desc = JsonUtil.readValue(new FileInputStream(f), 
CubeDesc.class);
 
         MeasureDesc measureDescDuplicated = desc.getMeasures().get(1);
-        desc.getMeasures().add(measureDescDuplicated);
+        List<MeasureDesc> newMeasures = Lists.newArrayList(desc.getMeasures());
+        newMeasures.add(measureDescDuplicated);
+        desc.setMeasures(newMeasures);
 
         desc.init(config);
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
----------------------------------------------------------------------
diff --git 
a/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java 
b/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
index b3ca14a..00fafaf 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/MetadataManager.java
@@ -23,7 +23,6 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -169,6 +168,10 @@ public class MetadataManager {
         return Collections.unmodifiableMap(srcTableMap.getMap());
     }
 
+    public Map<String, CCInfo> getCcInfoMap() {
+        return ccInfoMap;
+    }
+
     public Map<String, TableExtDesc> listAllTableExdMap() {
         return srcTableExdMap.getMap();
     }
@@ -532,7 +535,7 @@ public class MetadataManager {
 
     public List<DataModelDesc> getModels(String projectName) throws 
IOException {
         ProjectInstance projectInstance = 
ProjectManager.getInstance(config).getProject(projectName);
-        HashSet<DataModelDesc> ret = new HashSet<>();
+        ArrayList<DataModelDesc> ret = new ArrayList<>();
 
         if (projectInstance != null && projectInstance.getModels() != null) {
             for (String modelName : projectInstance.getModels()) {
@@ -545,7 +548,7 @@ public class MetadataManager {
             }
         }
 
-        return new ArrayList<>(ret);
+        return ret;
     }
 
     public boolean isTableInModel(String tableName, String projectName) throws 
IOException {
@@ -600,7 +603,9 @@ public class MetadataManager {
         ResourceStore store = getStore();
         try {
             DataModelDesc dataModelDesc = store.getResource(path, 
DataModelDesc.class, MODELDESC_SERIALIZER);
-            dataModelDesc.init(config, this.getAllTablesMap(), this.ccInfoMap);
+            if (dataModelDesc.getStatus() == null)
+                dataModelDesc.init(config, this.getAllTablesMap(), 
this.ccInfoMap);
+
             dataModelDescMap.putLocal(dataModelDesc.getName(), dataModelDesc);
             return dataModelDesc;
         } catch (Exception e) {
@@ -648,7 +653,8 @@ public class MetadataManager {
     }
 
     private DataModelDesc saveDataModelDesc(DataModelDesc dataModelDesc) 
throws IOException {
-        dataModelDesc.init(config, this.getAllTablesMap(), this.ccInfoMap);
+        if (dataModelDesc.getStatus() == null)
+            dataModelDesc.init(config, this.getAllTablesMap(), this.ccInfoMap);
 
         String path = dataModelDesc.getResourcePath();
         getStore().putResource(path, dataModelDesc, MODELDESC_SERIALIZER);

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
----------------------------------------------------------------------
diff --git 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
index 2174b7a..c3554f2 100644
--- 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
+++ 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/DataModelDesc.java
@@ -67,6 +67,8 @@ public class DataModelDesc extends RootPersistentEntity {
         SMALL, MEDIUM, LARGE
     }
 
+    public static final String STATUS_DRAFT = "DRAFT";
+
     private KylinConfig config;
 
     @JsonProperty("name")
@@ -75,6 +77,9 @@ public class DataModelDesc extends RootPersistentEntity {
     @JsonProperty("owner")
     private String owner;
 
+    @JsonProperty("status")
+    private String status;
+
     @JsonProperty("description")
     private String description;
 
@@ -130,8 +135,7 @@ public class DataModelDesc extends RootPersistentEntity {
         return name;
     }
 
-    // for test mainly
-    @Deprecated
+    // for updating name from draft to ready
     public void setName(String name) {
         this.name = name;
     }
@@ -144,14 +148,34 @@ public class DataModelDesc extends RootPersistentEntity {
         this.owner = owner;
     }
 
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
     public String getDescription() {
         return description;
     }
 
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
     public TableRef getRootFactTable() {
         return rootFactTableRef;
     }
 
+    public String getRootFactTableName() {
+        return rootFactTable;
+    }
+
+    public void setRootFactTableName(String rootFactTable) {
+        this.rootFactTable = rootFactTable;
+    }
+
     public Set<TableRef> getAllTables() {
         return allTableRefs;
     }
@@ -168,6 +192,10 @@ public class DataModelDesc extends RootPersistentEntity {
         return joinTables;
     }
 
+    public void setJoinTables(JoinTableDesc[] joinTables) {
+        this.joinTables = joinTables;
+    }
+
     public JoinDesc getJoinByPKSide(TableRef table) {
         return joinsTree.getJoinByPKSide(table);
     }
@@ -227,7 +255,6 @@ public class DataModelDesc extends RootPersistentEntity {
         return filterCondition;
     }
 
-    // for internal only
     public void setFilterCondition(String filterCondition) {
         this.filterCondition = filterCondition;
     }
@@ -236,7 +263,6 @@ public class DataModelDesc extends RootPersistentEntity {
         return partitionDesc;
     }
 
-    // for test only
     public void setPartitionDesc(PartitionDesc partitionDesc) {
         this.partitionDesc = partitionDesc;
     }
@@ -245,6 +271,10 @@ public class DataModelDesc extends RootPersistentEntity {
         return capacity;
     }
 
+    public void setCapacity(RealizationCapacity capacity) {
+        this.capacity = capacity;
+    }
+
     public TblColRef findColumn(String table, String column) throws 
IllegalArgumentException {
         TableRef tableRef = findTable(table);
         TblColRef result = tableRef.getColumn(column.toUpperCase());
@@ -385,9 +415,10 @@ public class DataModelDesc extends RootPersistentEntity {
 
             TableDesc tableDesc = tables.get(join.getTable());
             String alias = join.getAlias();
-            if (alias == null)
+            if (alias == null) {
                 alias = tableDesc.getName();
-
+                join.setAlias(alias);
+            }
             TableRef ref = new TableRef(this, alias, tableDesc);
 
             join.setTableRef(ref);
@@ -696,6 +727,10 @@ public class DataModelDesc extends RootPersistentEntity {
         return computedColumnDescs;
     }
 
+    public void setComputedColumnDescs(List<ComputedColumnDesc> 
computedColumnDescs) {
+        this.computedColumnDescs = computedColumnDescs;
+    }
+
     public String[] getMetrics() {
         return metrics;
     }
@@ -713,6 +748,7 @@ public class DataModelDesc extends RootPersistentEntity {
     public static DataModelDesc getCopyOf(DataModelDesc orig) {
         DataModelDesc copy = new DataModelDesc();
         copy.name = orig.name;
+        copy.status = orig.status;
         copy.owner = orig.owner;
         copy.description = orig.description;
         copy.rootFactTable = orig.rootFactTable;
@@ -725,5 +761,4 @@ public class DataModelDesc extends RootPersistentEntity {
         copy.updateRandomUuid();
         return copy;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinTableDesc.java
----------------------------------------------------------------------
diff --git 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinTableDesc.java
 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinTableDesc.java
index 9ca806e..56c90bd 100644
--- 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinTableDesc.java
+++ 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinTableDesc.java
@@ -59,6 +59,10 @@ public class JoinTableDesc implements Serializable {
         return kind;
     }
     
+    void setAlias(String alias) {
+        this.alias = alias;
+    }
+    
     public String getAlias() {
         return alias;
     }
@@ -74,7 +78,5 @@ public class JoinTableDesc implements Serializable {
     void setTableRef(TableRef ref) {
         this.tableRef = ref;
     }
-    
-    
 
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinsTree.java
----------------------------------------------------------------------
diff --git 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinsTree.java 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinsTree.java
index 7db730e..4e7e8b8 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinsTree.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/model/JoinsTree.java
@@ -63,6 +63,16 @@ public class JoinsTree implements Serializable {
         return matchUp;
     }
 
+    public int matchNum(JoinsTree another) {
+        Map<String, String> matchUp = new HashMap<>();
+
+        for (Chain chain : tableChains.values()) {
+            matchInTree(chain, another, Collections.<String, String> 
emptyMap(), matchUp);
+        }
+
+        return matchUp.size();
+    }
+
     private boolean matchInTree(Chain chain, JoinsTree another, Map<String, 
String> constraints, Map<String, String> matchUp) {
         String thisAlias = chain.table.getAlias();
         if (matchUp.containsKey(thisAlias))

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableExtDesc.java
----------------------------------------------------------------------
diff --git 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableExtDesc.java 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableExtDesc.java
index 9692f5a..a0f67f0 100644
--- 
a/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableExtDesc.java
+++ 
b/core-metadata/src/main/java/org/apache/kylin/metadata/model/TableExtDesc.java
@@ -42,6 +42,8 @@ public class TableExtDesc extends RootPersistentEntity {
     @JsonProperty("last_build_job_id")
     private String jodID;
 
+    @JsonProperty("frequency")
+    private int frequency;
     @JsonProperty("columns_stats")
     private List<ColumnStats> columnStats = new ArrayList<>();
 
@@ -68,6 +70,14 @@ public class TableExtDesc extends RootPersistentEntity {
         return ResourceStore.TABLE_EXD_RESOURCE_ROOT + "/" + tableIdentity + 
".json";
     }
 
+    public int getFrequency() {
+        return this.frequency;
+    }
+
+    public void setFrequency(int frequency) {
+        this.frequency = frequency;
+    }
+
     public String getName() {
         return this.tableName;
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/engine-mr/src/main/java/org/apache/kylin/engine/mr/IMRInput.java
----------------------------------------------------------------------
diff --git a/engine-mr/src/main/java/org/apache/kylin/engine/mr/IMRInput.java 
b/engine-mr/src/main/java/org/apache/kylin/engine/mr/IMRInput.java
index 6b0e557..8e77513 100644
--- a/engine-mr/src/main/java/org/apache/kylin/engine/mr/IMRInput.java
+++ b/engine-mr/src/main/java/org/apache/kylin/engine/mr/IMRInput.java
@@ -37,9 +37,6 @@ public interface IMRInput {
     /** Return an InputFormat that reads from specified table. */
     public IMRTableInputFormat getTableInputFormat(TableDesc table);
 
-    /** Return an InputFormat that reads from specified table; "isFullTable" 
indicates whether it is a full table read or not. */
-    public IMRTableInputFormat getTableInputFormat(TableDesc table, boolean 
isFullTable);
-
     /** Return a helper to participate in batch cubing merge job flow. */
     public IMRBatchMergeInputSide getBatchMergeInputSide(ISegment seg);
 

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/engine-mr/src/main/java/org/apache/kylin/engine/mr/MRUtil.java
----------------------------------------------------------------------
diff --git a/engine-mr/src/main/java/org/apache/kylin/engine/mr/MRUtil.java 
b/engine-mr/src/main/java/org/apache/kylin/engine/mr/MRUtil.java
index 5ba9424..cbb68d2 100644
--- a/engine-mr/src/main/java/org/apache/kylin/engine/mr/MRUtil.java
+++ b/engine-mr/src/main/java/org/apache/kylin/engine/mr/MRUtil.java
@@ -43,22 +43,12 @@ public class MRUtil {
         return SourceFactory.createEngineAdapter(seg, 
IMRInput.class).getBatchCubingInputSide(flatDesc);
     }
 
-    @Deprecated
     public static IMRTableInputFormat getTableInputFormat(String tableName) {
-        return getTableInputFormat(tableName, true);
+        return SourceFactory.createEngineAdapter(getTableDesc(tableName), 
IMRInput.class).getTableInputFormat(getTableDesc(tableName));
     }
 
-    public static IMRTableInputFormat getTableInputFormat(String tableName, 
boolean isFullTable) {
-        return getTableInputFormat(getTableDesc(tableName), isFullTable);
-    }
-
-    @Deprecated
     public static IMRTableInputFormat getTableInputFormat(TableDesc tableDesc) 
{
-        return getTableInputFormat(tableDesc, true);
-    }
-
-    public static IMRTableInputFormat getTableInputFormat(TableDesc tableDesc, 
boolean isFullTable) {
-        return SourceFactory.createEngineAdapter(tableDesc, 
IMRInput.class).getTableInputFormat(tableDesc, isFullTable);
+        return SourceFactory.createEngineAdapter(tableDesc, 
IMRInput.class).getTableInputFormat(tableDesc);
     }
 
     private static TableDesc getTableDesc(String tableName) {

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java
index 461aa3f..a88c342 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/AccessController.java
@@ -27,6 +27,7 @@ import org.apache.kylin.rest.response.AccessEntryResponse;
 import org.apache.kylin.rest.security.AclPermissionFactory;
 import org.apache.kylin.rest.service.AccessService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.acls.model.Acl;
 import org.springframework.security.acls.model.Permission;
 import org.springframework.security.acls.model.Sid;
@@ -46,6 +47,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 public class AccessController extends BasicController {
 
     @Autowired
+    @Qualifier("accessService")
     private AccessService accessService;
 
     /**
@@ -55,7 +57,7 @@ public class AccessController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public List<AccessEntryResponse> getAccessEntities(@PathVariable String 
type, @PathVariable String uuid) {
         AclEntity ae = accessService.getAclEntity(type, uuid);
@@ -69,7 +71,7 @@ public class AccessController extends BasicController {
      * 
      * @param accessRequest
      */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.POST })
+    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.POST }, 
produces = { "application/json" })
     @ResponseBody
     public List<AccessEntryResponse> grant(@PathVariable String type, 
@PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
         AclEntity ae = accessService.getAclEntity(type, uuid);
@@ -85,7 +87,7 @@ public class AccessController extends BasicController {
      * 
      * @param accessRequest
      */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.PUT }, 
produces = { "application/json" })
     @ResponseBody
     public List<AccessEntryResponse> update(@PathVariable String type, 
@PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
         AclEntity ae = accessService.getAclEntity(type, uuid);
@@ -98,9 +100,9 @@ public class AccessController extends BasicController {
     /**
      * Revoke access on a domain object from a user/role
      * 
-     * @param AccessRequest
+     * @param accessRequest
      */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.DELETE 
})
+    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.DELETE 
}, produces = { "application/json" })
     public List<AccessEntryResponse> revoke(@PathVariable String type, 
@PathVariable String uuid, AccessRequest accessRequest) {
         AclEntity ae = accessService.getAclEntity(type, uuid);
         Acl acl = accessService.revoke(ae, accessRequest.getAccessEntryId());

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/AdminController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/AdminController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/AdminController.java
index de3c4b4..1252775 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/AdminController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/AdminController.java
@@ -18,7 +18,12 @@
 
 package org.apache.kylin.rest.controller;
 
+import java.io.IOException;
+
+import org.apache.commons.configuration.ConfigurationException;
 import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.rest.msg.Message;
+import org.apache.kylin.rest.msg.MsgPicker;
 import org.apache.kylin.rest.request.MetricsRequest;
 import org.apache.kylin.rest.request.UpdateConfigRequest;
 import org.apache.kylin.rest.response.GeneralResponse;
@@ -26,6 +31,7 @@ import org.apache.kylin.rest.response.MetricsResponse;
 import org.apache.kylin.rest.service.AdminService;
 import org.apache.kylin.rest.service.CubeService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -43,24 +49,32 @@ import org.springframework.web.bind.annotation.ResponseBody;
 public class AdminController extends BasicController {
 
     @Autowired
+    @Qualifier("adminService")
     private AdminService adminService;
+
     @Autowired
+    @Qualifier("cubeMgmtService")
     private CubeService cubeMgmtService;
 
-    @RequestMapping(value = "/env", method = { RequestMethod.GET })
+    @RequestMapping(value = "/env", method = { RequestMethod.GET }, produces = 
{ "application/json" })
     @ResponseBody
     public GeneralResponse getEnv() {
-        String env = adminService.getEnv();
+        Message msg = MsgPicker.getMsg();
+        try {
+            String env = adminService.getEnv();
 
-        GeneralResponse envRes = new GeneralResponse();
-        envRes.put("env", env);
+            GeneralResponse envRes = new GeneralResponse();
+            envRes.put("env", env);
 
-        return envRes;
+            return envRes;
+        } catch (ConfigurationException e) {
+            throw new RuntimeException(msg.getGET_ENV_CONFIG_FAIL(), e);
+        }
     }
 
-    @RequestMapping(value = "/config", method = { RequestMethod.GET })
+    @RequestMapping(value = "/config", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
-    public GeneralResponse getConfig() {
+    public GeneralResponse getConfig() throws IOException {
         String config = adminService.getConfigAsString();
 
         GeneralResponse configRes = new GeneralResponse();
@@ -69,19 +83,19 @@ public class AdminController extends BasicController {
         return configRes;
     }
 
-    @RequestMapping(value = "/metrics/cubes", method = { RequestMethod.GET })
+    @RequestMapping(value = "/metrics/cubes", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public MetricsResponse cubeMetrics(MetricsRequest request) {
         return cubeMgmtService.calculateMetrics(request);
     }
 
-    @RequestMapping(value = "/storage", method = { RequestMethod.DELETE })
+    @RequestMapping(value = "/storage", method = { RequestMethod.DELETE }, 
produces = { "application/json" })
     @ResponseBody
     public void cleanupStorage() {
         adminService.cleanupStorage();
     }
 
-    @RequestMapping(value = "/config", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/config", method = { RequestMethod.PUT }, 
produces = { "application/json" })
     public void updateKylinConfig(@RequestBody UpdateConfigRequest 
updateConfigRequest) {
         
KylinConfig.getInstanceFromEnv().setProperty(updateConfigRequest.getKey(), 
updateConfigRequest.getValue());
     }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/CacheController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CacheController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CacheController.java
index 8d5f00e..092220c 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CacheController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CacheController.java
@@ -26,6 +26,7 @@ import org.apache.kylin.rest.service.CacheService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -45,12 +46,13 @@ public class CacheController extends BasicController {
     private static final Logger logger = 
LoggerFactory.getLogger(CacheController.class);
 
     @Autowired
+    @Qualifier("cacheService")
     private CacheService cacheService;
 
     /**
      * Announce wipe cache to all cluster nodes
      */
-    @RequestMapping(value = "/announce/{entity}/{cacheKey}/{event}", method = 
{ RequestMethod.PUT })
+    @RequestMapping(value = "/announce/{entity}/{cacheKey}/{event}", method = 
{ RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public void announceWipeCache(@PathVariable String entity, @PathVariable 
String event, @PathVariable String cacheKey) throws IOException {
         cacheService.annouceWipeCache(entity, event, cacheKey);
@@ -59,13 +61,13 @@ public class CacheController extends BasicController {
     /**
      * Wipe cache on this node
      */
-    @RequestMapping(value = "/{entity}/{cacheKey}/{event}", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{entity}/{cacheKey}/{event}", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public void wipeCache(@PathVariable String entity, @PathVariable String 
event, @PathVariable String cacheKey) throws IOException {
         cacheService.notifyMetadataChange(entity, 
Broadcaster.Event.getEvent(event), cacheKey);
     }
 
-    @RequestMapping(value = "/announce/config", method = { RequestMethod.POST 
})
+    @RequestMapping(value = "/announce/config", method = { RequestMethod.POST 
}, produces = { "application/json" })
     public void hotLoadKylinConfig() throws IOException {
         KylinConfig.getInstanceFromEnv().hotLoadKylinProperties();
         cacheService.notifyMetadataChange(Broadcaster.SYNC_ALL, 
Broadcaster.Event.UPDATE, Broadcaster.SYNC_ALL);

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java
index 8cdfcfb..7d4cbe6 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeController.java
@@ -53,10 +53,12 @@ import org.apache.kylin.rest.response.GeneralResponse;
 import org.apache.kylin.rest.response.HBaseResponse;
 import org.apache.kylin.rest.service.CubeService;
 import org.apache.kylin.rest.service.JobService;
+import org.apache.kylin.rest.service.ProjectService;
 import org.apache.kylin.source.kafka.util.KafkaClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.stereotype.Controller;
@@ -85,12 +87,18 @@ public class CubeController extends BasicController {
     private static final char[] VALID_CUBENAME = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
 
     @Autowired
+    @Qualifier("cubeMgmtService")
     private CubeService cubeService;
 
     @Autowired
+    @Qualifier("jobService")
     private JobService jobService;
 
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @Autowired
+    @Qualifier("projectService")
+    private ProjectService projectService;
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/json" })
     @ResponseBody
     public List<CubeInstance> getCubes(@RequestParam(value = "cubeName", 
required = false) String cubeName, @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) {
         List<CubeInstance> cubes;
@@ -110,7 +118,7 @@ public class CubeController extends BasicController {
         return cubes.subList(coffset, coffset + climit);
     }
 
-    @RequestMapping(value = "validEncodings", method = { RequestMethod.GET })
+    @RequestMapping(value = "validEncodings", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public Map<String, Integer> getValidEncodings() {
         Map<String, Integer> encodings;
@@ -123,7 +131,7 @@ public class CubeController extends BasicController {
         return encodings;
     }
 
-    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public CubeInstance getCube(@PathVariable String cubeName) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
@@ -141,17 +149,17 @@ public class CubeController extends BasicController {
      * @throws UnknownHostException
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/segs/{segmentName}/sql", method = { 
RequestMethod.GET })
+    @RequestMapping(value = "/{cubeName}/segs/{segmentName}/sql", method = { 
RequestMethod.GET }, produces = { "application/json" })
     @ResponseBody
     public GeneralResponse getSql(@PathVariable String cubeName, @PathVariable 
String segmentName) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
         IJoinedFlatTableDesc flatTableDesc = 
EngineFactory.getJoinedFlatTableDesc(cube.getDescriptor());
         String sql = 
JoinedFlatTable.generateSelectDataStatement(flatTableDesc);
 
-        GeneralResponse repsonse = new GeneralResponse();
-        repsonse.setProperty("sql", sql);
+        GeneralResponse response = new GeneralResponse();
+        response.setProperty("sql", sql);
 
-        return repsonse;
+        return response;
     }
 
     /**
@@ -161,7 +169,7 @@ public class CubeController extends BasicController {
      * @param notifyList
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/notify_list", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/notify_list", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public void updateNotifyList(@PathVariable String cubeName, @RequestBody 
List<String> notifyList) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
@@ -179,7 +187,7 @@ public class CubeController extends BasicController {
 
     }
 
-    @RequestMapping(value = "/{cubeName}/cost", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/cost", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public CubeInstance updateCubeCost(@PathVariable String cubeName, 
@RequestParam(value = "cost") int cost) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
@@ -201,7 +209,7 @@ public class CubeController extends BasicController {
      *
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/segs/{segmentName}/refresh_lookup", 
method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/segs/{segmentName}/refresh_lookup", 
method = { RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public CubeInstance rebuildLookupSnapshot(@PathVariable String cubeName, 
@PathVariable String segmentName, @RequestParam(value = "lookupTable") String 
lookupTable) {
         try {
@@ -219,7 +227,7 @@ public class CubeController extends BasicController {
      *
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/segs/{segmentName}", method = { 
RequestMethod.DELETE })
+    @RequestMapping(value = "/{cubeName}/segs/{segmentName}", method = { 
RequestMethod.DELETE }, produces = { "application/json" })
     @ResponseBody
     public CubeInstance deleteSegment(@PathVariable String cubeName, 
@PathVariable String segmentName) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
@@ -242,21 +250,23 @@ public class CubeController extends BasicController {
     }
 
     /** Build/Rebuild a cube segment */
-    @RequestMapping(value = "/{cubeName}/build", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/build", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public JobInstance build(@PathVariable String cubeName, @RequestBody 
JobBuildRequest req) {
         return rebuild(cubeName, req);
     }
 
     /** Build/Rebuild a cube segment */
-    @RequestMapping(value = "/{cubeName}/rebuild", method = { 
RequestMethod.PUT })
+
+    /** Build/Rebuild a cube segment */
+    @RequestMapping(value = "/{cubeName}/rebuild", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public JobInstance rebuild(@PathVariable String cubeName, @RequestBody 
JobBuildRequest req) {
         return buildInternal(cubeName, req.getStartTime(), req.getEndTime(), 
0, 0, null, null, req.getBuildType(), req.isForce() || 
req.isForceMergeEmptySegment());
     }
 
     /** Build/Rebuild a cube segment by source offset */
-    @RequestMapping(value = "/{cubeName}/build2", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/build2", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public JobInstance build2(@PathVariable String cubeName, @RequestBody 
JobBuildRequest2 req) {
         boolean existKafkaClient = false;
@@ -275,7 +285,7 @@ public class CubeController extends BasicController {
     }
 
     /** Build/Rebuild a cube segment by source offset */
-    @RequestMapping(value = "/{cubeName}/rebuild2", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/rebuild2", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public JobInstance rebuild2(@PathVariable String cubeName, @RequestBody 
JobBuildRequest2 req) {
         return buildInternal(cubeName, 0, 0, req.getSourceOffsetStart(), 
req.getSourceOffsetEnd(), req.getSourcePartitionOffsetStart(), 
req.getSourcePartitionOffsetEnd(), req.getBuildType(), req.isForce());
@@ -290,6 +300,9 @@ public class CubeController extends BasicController {
             if (cube == null) {
                 throw new InternalErrorException("Cannot find cube " + 
cubeName);
             }
+            if (cube.getStatus() != null && cube.getStatus().equals("DRAFT")) {
+                throw new BadRequestException("Cannot build draft cube");
+            }
             return jobService.submitJob(cube, startTime, endTime, startOffset, 
endOffset, //
                     sourcePartitionOffsetStart, sourcePartitionOffsetEnd, 
CubeBuildTypeEnum.valueOf(buildType), force, submitter);
         } catch (Throwable e) {
@@ -298,7 +311,7 @@ public class CubeController extends BasicController {
         }
     }
 
-    @RequestMapping(value = "/{cubeName}/disable", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/disable", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public CubeInstance disableCube(@PathVariable String cubeName) {
         try {
@@ -316,7 +329,7 @@ public class CubeController extends BasicController {
         }
     }
 
-    @RequestMapping(value = "/{cubeName}/purge", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/purge", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public CubeInstance purgeCube(@PathVariable String cubeName) {
         try {
@@ -339,7 +352,7 @@ public class CubeController extends BasicController {
         }
     }
 
-    @RequestMapping(value = "/{cubeName}/clone", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/clone", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public CubeInstance cloneCube(@PathVariable String cubeName, @RequestBody 
CubeRequest cubeRequest) {
         String newCubeName = cubeRequest.getCubeName();
@@ -376,7 +389,7 @@ public class CubeController extends BasicController {
 
     }
 
-    @RequestMapping(value = "/{cubeName}/enable", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/enable", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public CubeInstance enableCube(@PathVariable String cubeName) {
         try {
@@ -393,7 +406,7 @@ public class CubeController extends BasicController {
         }
     }
 
-    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.DELETE })
+    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.DELETE }, 
produces = { "application/json" })
     @ResponseBody
     public void deleteCube(@PathVariable String cubeName) {
         CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
@@ -417,7 +430,7 @@ public class CubeController extends BasicController {
      * @return Table metadata array
      * @throws IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.POST })
+    @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { 
"application/json" })
     @ResponseBody
     public CubeRequest saveCubeDesc(@RequestBody CubeRequest cubeRequest) {
 
@@ -458,7 +471,7 @@ public class CubeController extends BasicController {
      * @throws JsonProcessingException
      * @throws IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.PUT })
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/json" })
     @ResponseBody
     public CubeRequest updateCubeDesc(@RequestBody CubeRequest cubeRequest) 
throws JsonProcessingException {
 
@@ -516,7 +529,7 @@ public class CubeController extends BasicController {
      * @return true
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/hbase", method = { RequestMethod.GET 
})
+    @RequestMapping(value = "/{cubeName}/hbase", method = { RequestMethod.GET 
}, produces = { "application/json" })
     @ResponseBody
     public List<HBaseResponse> getHBaseInfo(@PathVariable String cubeName) {
         List<HBaseResponse> hbase = new ArrayList<HBaseResponse>();
@@ -566,7 +579,7 @@ public class CubeController extends BasicController {
      * @return a list of CubeSegment, each representing a hole
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.GET 
})
+    @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.GET 
}, produces = { "application/json" })
     @ResponseBody
     public List<CubeSegment> getHoles(@PathVariable String cubeName) {
         checkCubeName(cubeName);
@@ -579,7 +592,7 @@ public class CubeController extends BasicController {
      * @return a list of JobInstances to fill the holes
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{cubeName}/holes", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public List<JobInstance> fillHoles(@PathVariable String cubeName) {
         checkCubeName(cubeName);
@@ -635,7 +648,7 @@ public class CubeController extends BasicController {
      * @param cubeName
      * @return
      */
-    @RequestMapping(value = "/{cubeName}/init_start_offsets", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{cubeName}/init_start_offsets", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public GeneralResponse initStartOffsets(@PathVariable String cubeName) {
         checkCubeName(cubeName);
@@ -666,7 +679,7 @@ public class CubeController extends BasicController {
      * @param aggregationGroupStr
      * @return number of cuboid, -1 if failed
      */
-    @RequestMapping(value = "aggregationgroups/cuboid", method = 
RequestMethod.POST)
+    @RequestMapping(value = "aggregationgroups/cuboid", method = 
RequestMethod.POST, produces = { "application/json" })
     @ResponseBody
     public long calculateCuboidCombination(@RequestBody String 
aggregationGroupStr) {
         AggregationGroup aggregationGroup = 
deserializeAggregationGroup(aggregationGroupStr);

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/CubeDescController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeDescController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeDescController.java
index 0c8f487..2c35349 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/CubeDescController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/CubeDescController.java
@@ -24,6 +24,7 @@ import org.apache.kylin.cube.CubeInstance;
 import org.apache.kylin.cube.model.CubeDesc;
 import org.apache.kylin.rest.service.CubeService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -39,6 +40,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 public class CubeDescController extends BasicController {
 
     @Autowired
+    @Qualifier("cubeMgmtService")
     private CubeService cubeService;
 
     /**
@@ -49,7 +51,7 @@ public class CubeDescController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public CubeDesc[] getCube(@PathVariable String cubeName) {
         CubeInstance cubeInstance = 
cubeService.getCubeManager().getCube(cubeName);
@@ -73,7 +75,7 @@ public class CubeDescController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{cubeName}/desc", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{cubeName}/desc", method = { RequestMethod.GET 
}, produces = { "application/json" })
     @ResponseBody
     public CubeDesc getDesc(@PathVariable String cubeName) {
         CubeInstance cubeInstance = 
cubeService.getCubeManager().getCube(cubeName);

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java
index f5e7c24..108ec5a 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/DiagnosisController.java
@@ -32,6 +32,7 @@ import org.apache.kylin.rest.service.DiagnosisService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -47,12 +48,13 @@ public class DiagnosisController extends BasicController {
     private static final Logger logger = 
LoggerFactory.getLogger(DiagnosisController.class);
 
     @Autowired
+    @Qualifier("diagnosisService")
     private DiagnosisService dgService;
 
     /**
      * Get bad query history
      */
-    @RequestMapping(value = "/{project}/sql", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{project}/sql", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public List<BadQueryEntry> getBadQuerySql(@PathVariable String project) {
 
@@ -70,7 +72,7 @@ public class DiagnosisController extends BasicController {
     /**
      * Get diagnosis information for project
      */
-    @RequestMapping(value = "/project/{project}/download", method = { 
RequestMethod.GET })
+    @RequestMapping(value = "/project/{project}/download", method = { 
RequestMethod.GET }, produces = { "application/json" })
     @ResponseBody
     public void dumpProjectDiagnosisInfo(@PathVariable String project, final 
HttpServletRequest request, final HttpServletResponse response) {
         String filePath;
@@ -86,7 +88,7 @@ public class DiagnosisController extends BasicController {
     /**
      * Get diagnosis information for job
      */
-    @RequestMapping(value = "/job/{jobId}/download", method = { 
RequestMethod.GET })
+    @RequestMapping(value = "/job/{jobId}/download", method = { 
RequestMethod.GET }, produces = { "application/json" })
     @ResponseBody
     public void dumpJobDiagnosisInfo(@PathVariable String jobId, final 
HttpServletRequest request, final HttpServletResponse response) {
         String filePath;
@@ -98,4 +100,5 @@ public class DiagnosisController extends BasicController {
 
         setDownloadResponse(filePath, response);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/EncodingController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/EncodingController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/EncodingController.java
index 4a8b122..c095616 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/EncodingController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/EncodingController.java
@@ -29,6 +29,7 @@ import org.apache.kylin.rest.service.EncodingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -44,6 +45,7 @@ public class EncodingController extends BasicController {
     private static final Logger logger = 
LoggerFactory.getLogger(EncodingController.class);
 
     @Autowired
+    @Qualifier("encodingService")
     private EncodingService encodingService;
 
     /**
@@ -51,7 +53,7 @@ public class EncodingController extends BasicController {
      *
      * @return suggestion map
      */
-    @RequestMapping(value = "valid_encodings", method = { RequestMethod.GET })
+    @RequestMapping(value = "valid_encodings", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public EnvelopeResponse getValidEncodings() {
 
@@ -68,4 +70,5 @@ public class EncodingController extends BasicController {
 
         return new EnvelopeResponse(ResponseCode.CODE_SUCCESS, 
datatypeValidEncodings, "");
     }
+
 }

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/ExternalFilterController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ExternalFilterController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ExternalFilterController.java
index 7baa639..4ae7656 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ExternalFilterController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ExternalFilterController.java
@@ -31,6 +31,7 @@ import org.apache.kylin.rest.service.ExtFilterService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -50,9 +51,10 @@ public class ExternalFilterController extends 
BasicController {
     private static final Logger logger = 
LoggerFactory.getLogger(ExternalFilterController.class);
 
     @Autowired
+    @Qualifier("extFilterService")
     private ExtFilterService extFilterService;
 
-    @RequestMapping(value = "/saveExtFilter", method = { RequestMethod.POST })
+    @RequestMapping(value = "/saveExtFilter", method = { RequestMethod.POST }, 
produces = { "application/json" })
     @ResponseBody
     public Map<String, String> saveExternalFilter(@RequestBody 
ExternalFilterRequest request) throws IOException {
         Map<String, String> result = new HashMap();
@@ -65,7 +67,7 @@ public class ExternalFilterController extends BasicController 
{
         return result;
     }
 
-    @RequestMapping(value = "/updateExtFilter", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/updateExtFilter", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public Map<String, String> updateExternalFilter(@RequestBody 
ExternalFilterRequest request) throws IOException {
         Map<String, String> result = new HashMap();
@@ -76,7 +78,7 @@ public class ExternalFilterController extends BasicController 
{
         return result;
     }
 
-    @RequestMapping(value = "/{filter}/{project}", method = { 
RequestMethod.DELETE })
+    @RequestMapping(value = "/{filter}/{project}", method = { 
RequestMethod.DELETE }, produces = { "application/json" })
     @ResponseBody
     public Map<String, String> removeFilter(@PathVariable String filter, 
@PathVariable String project) throws IOException {
         Map<String, String> result = new HashMap<String, String>();
@@ -86,7 +88,7 @@ public class ExternalFilterController extends BasicController 
{
         return result;
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/json" })
     @ResponseBody
     public List<ExternalFilterDesc> getExternalFilters(@RequestParam(value = 
"project", required = true) String project) throws IOException {
         List<ExternalFilterDesc> filterDescs = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/HybridController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/HybridController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/HybridController.java
index 18156b6..f23f26c 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/HybridController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/HybridController.java
@@ -39,7 +39,7 @@ public class HybridController extends BasicController {
     @Autowired
     private HybridService hybridService;
 
-    @RequestMapping(value = "", method = RequestMethod.POST)
+    @RequestMapping(value = "", method = RequestMethod.POST, produces = { 
"application/json" })
     @ResponseBody
     public HybridInstance create(@RequestBody HybridRequest request) {
         checkRequiredArg("hybrid", request.getHybrid());
@@ -50,7 +50,7 @@ public class HybridController extends BasicController {
         return instance;
     }
 
-    @RequestMapping(value = "", method = RequestMethod.PUT)
+    @RequestMapping(value = "", method = RequestMethod.PUT, produces = { 
"application/json" })
     @ResponseBody
     public HybridInstance update(@RequestBody HybridRequest request) {
         checkRequiredArg("hybrid", request.getHybrid());
@@ -61,7 +61,7 @@ public class HybridController extends BasicController {
         return instance;
     }
 
-    @RequestMapping(value = "", method = RequestMethod.DELETE)
+    @RequestMapping(value = "", method = RequestMethod.DELETE, produces = { 
"application/json" })
     @ResponseBody
     public void delete(@RequestBody HybridRequest request) {
         checkRequiredArg("hybrid", request.getHybrid());
@@ -70,15 +70,16 @@ public class HybridController extends BasicController {
         hybridService.deleteHybridCube(request.getHybrid(), 
request.getProject(), request.getModel());
     }
 
-    @RequestMapping(value = "", method = RequestMethod.GET)
+    @RequestMapping(value = "", method = RequestMethod.GET, produces = { 
"application/json" })
     @ResponseBody
     public Collection<HybridInstance> list(@RequestParam(required = false) 
String project, @RequestParam(required = false) String model) {
         return hybridService.listHybrids(project, model);
     }
 
-    @RequestMapping(value = "{hybrid}", method = RequestMethod.GET)
+    @RequestMapping(value = "{hybrid}", method = RequestMethod.GET, produces = 
{ "application/json" })
     @ResponseBody
     public HybridInstance get(@PathVariable String hybrid) {
         return hybridService.getHybridInstance(hybrid);
     }
-}
\ No newline at end of file
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/JobController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/JobController.java 
b/server-base/src/main/java/org/apache/kylin/rest/controller/JobController.java
index 2e6f6cd..7c9c40d 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/JobController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/JobController.java
@@ -34,6 +34,7 @@ import org.apache.kylin.rest.service.JobService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -46,6 +47,7 @@ public class JobController extends BasicController {
     private static final Logger logger = 
LoggerFactory.getLogger(JobController.class);
 
     @Autowired
+    @Qualifier("jobService")
     private JobService jobService;
 
     /**
@@ -54,7 +56,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/json" })
     @ResponseBody
     public List<JobInstance> list(JobListRequest jobRequest) {
 
@@ -84,7 +86,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{jobId}", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public JobInstance get(@PathVariable String jobId) {
         JobInstance jobInstance = null;
@@ -104,7 +106,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/steps/{stepId}/output", method = { 
RequestMethod.GET })
+    @RequestMapping(value = "/{jobId}/steps/{stepId}/output", method = { 
RequestMethod.GET }, produces = { "application/json" })
     @ResponseBody
     public Map<String, String> getStepOutput(@PathVariable String jobId, 
@PathVariable String stepId) {
         Map<String, String> result = new HashMap<String, String>();
@@ -120,7 +122,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/resume", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{jobId}/resume", method = { RequestMethod.PUT }, 
produces = { "application/json" })
     @ResponseBody
     public JobInstance resume(@PathVariable String jobId) {
         try {
@@ -139,7 +141,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/cancel", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{jobId}/cancel", method = { RequestMethod.PUT }, 
produces = { "application/json" })
     @ResponseBody
     public JobInstance cancel(@PathVariable String jobId) {
 
@@ -150,18 +152,15 @@ public class JobController extends BasicController {
             logger.error(e.getLocalizedMessage(), e);
             throw new InternalErrorException(e);
         }
-
     }
 
-
-
     /**
      * Pause a job
      *
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/pause", method = { RequestMethod.PUT })
+    @RequestMapping(value = "/{jobId}/pause", method = { RequestMethod.PUT }, 
produces = { "application/json" })
     @ResponseBody
     public JobInstance pause(@PathVariable String jobId) {
 
@@ -181,7 +180,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/steps/{stepId}/rollback", method = { 
RequestMethod.PUT })
+    @RequestMapping(value = "/{jobId}/steps/{stepId}/rollback", method = { 
RequestMethod.PUT }, produces = { "application/json" })
     @ResponseBody
     public JobInstance rollback(@PathVariable String jobId, @PathVariable 
String stepId) {
         try {
@@ -200,7 +199,7 @@ public class JobController extends BasicController {
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{jobId}/drop", method = { RequestMethod.DELETE })
+    @RequestMapping(value = "/{jobId}/drop", method = { RequestMethod.DELETE 
}, produces = { "application/json" })
     @ResponseBody
     public JobInstance dropJob(@PathVariable String jobId) {
         JobInstance jobInstance = null;

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java
index 4217f86..4226e87 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelController.java
@@ -35,9 +35,11 @@ import 
org.apache.kylin.rest.exception.InternalErrorException;
 import org.apache.kylin.rest.exception.NotFoundException;
 import org.apache.kylin.rest.request.ModelRequest;
 import org.apache.kylin.rest.service.ModelService;
+import org.apache.kylin.rest.service.ProjectService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -64,9 +66,14 @@ public class ModelController extends BasicController {
     private static final char[] VALID_MODELNAME = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
 
     @Autowired
+    @Qualifier("modelMgmtService")
     private ModelService modelService;
 
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @Autowired
+    @Qualifier("projectService")
+    private ProjectService projectService;
+
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/json" })
     @ResponseBody
     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) {
         try {
@@ -82,7 +89,7 @@ public class ModelController extends BasicController {
      * create model
      * @throws java.io.IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.POST })
+    @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { 
"application/json" })
     @ResponseBody
     public ModelRequest saveModelDesc(@RequestBody ModelRequest modelRequest) {
         //Update Model
@@ -116,7 +123,7 @@ public class ModelController extends BasicController {
         return modelRequest;
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.PUT })
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/json" })
     @ResponseBody
     public ModelRequest updateModelDesc(@RequestBody ModelRequest 
modelRequest) throws JsonProcessingException {
         DataModelDesc modelDesc = deserializeDataModelDesc(modelRequest);
@@ -143,7 +150,7 @@ public class ModelController extends BasicController {
         return modelRequest;
     }
 
-    @RequestMapping(value = "/{modelName}", method = { RequestMethod.DELETE })
+    @RequestMapping(value = "/{modelName}", method = { RequestMethod.DELETE }, 
produces = { "application/json" })
     @ResponseBody
     public void deleteModel(@PathVariable String modelName) {
         DataModelDesc desc = 
modelService.getMetadataManager().getDataModelDesc(modelName);
@@ -158,7 +165,7 @@ public class ModelController extends BasicController {
         }
     }
 
-    @RequestMapping(value = "/{modelName}/clone", method = { RequestMethod.PUT 
})
+    @RequestMapping(value = "/{modelName}/clone", method = { RequestMethod.PUT 
}, produces = { "application/json" })
     @ResponseBody
     public ModelRequest cloneModel(@PathVariable String modelName, 
@RequestBody ModelRequest modelRequest) {
         String project = modelRequest.getProject();

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
index 4171afd..e6f337f 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ModelDescController.java
@@ -40,12 +40,12 @@ public class ModelDescController extends BasicController {
     /**
      * Get detail information of the "Model ID"
      * 
-     * @param modelDescName
+     * @param model_name
      *            Model ID
      * @return
      * @throws IOException
      */
-    @RequestMapping(value = "/{model_name}", method = { RequestMethod.GET })
+    @RequestMapping(value = "/{model_name}", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public DataModelDesc getModel(@PathVariable String model_name) {
         MetadataManager metaManager = 
MetadataManager.getInstance(KylinConfig.getInstanceFromEnv());

http://git-wip-us.apache.org/repos/asf/kylin/blob/73a78dbe/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
----------------------------------------------------------------------
diff --git 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
index 40e798a..ae1e419 100644
--- 
a/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
+++ 
b/server-base/src/main/java/org/apache/kylin/rest/controller/ProjectController.java
@@ -38,6 +38,7 @@ import org.apache.kylin.rest.util.AclUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.acls.domain.GrantedAuthoritySid;
 import org.springframework.security.acls.domain.PrincipalSid;
 import org.springframework.security.acls.model.AccessControlEntry;
@@ -62,10 +63,15 @@ public class ProjectController extends BasicController {
     private static final char[] VALID_PROJECTNAME = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_".toCharArray();
 
     @Autowired
+    @Qualifier("projectService")
     private ProjectService projectService;
+
     @Autowired
+    @Qualifier("accessService")
     private AccessService accessService;
+
     @Autowired
+    @Qualifier("cubeMgmtService")
     private CubeService cubeService;
     @Autowired
     private AclUtil aclUtil;
@@ -76,20 +82,20 @@ public class ProjectController extends BasicController {
      * @return Table metadata array
      * @throws IOException
      */
-    @RequestMapping(value = "", method = { RequestMethod.GET })
+    @RequestMapping(value = "", method = { RequestMethod.GET }, produces = { 
"application/json" })
     @ResponseBody
     public List<ProjectInstance> getProjects(@RequestParam(value = "limit", 
required = false) Integer limit, @RequestParam(value = "offset", required = 
false) Integer offset) {
         return projectService.listProjects(limit, offset);
     }
 
-    @RequestMapping(value = "/readable", method = { RequestMethod.GET })
+    @RequestMapping(value = "/readable", method = { RequestMethod.GET }, 
produces = { "application/json" })
     @ResponseBody
     public List<ProjectInstance> getReadableProjects(@RequestParam(value = 
"limit", required = false) Integer limit, @RequestParam(value = "offset", 
required = false) Integer offset) {
         List<ProjectInstance> readableProjects = new 
ArrayList<ProjectInstance>();
         //list all projects first
         List<ProjectInstance> projectInstances = 
projectService.listAllProjects(limit, offset);
 
-        //get user infomation
+        //get user information
         UserDetails userDetails = aclUtil.getCurrentUser();
         String userName = userDetails.getUsername();
 
@@ -159,9 +165,8 @@ public class ProjectController extends BasicController {
         return readableProjects;
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.POST })
+    @RequestMapping(value = "", method = { RequestMethod.POST }, produces = { 
"application/json" })
     @ResponseBody
-
     public ProjectInstance saveProject(@RequestBody ProjectRequest 
projectRequest) {
         ProjectInstance projectDesc = deserializeProjectDesc(projectRequest);
 
@@ -185,7 +190,7 @@ public class ProjectController extends BasicController {
         return createdProj;
     }
 
-    @RequestMapping(value = "", method = { RequestMethod.PUT })
+    @RequestMapping(value = "", method = { RequestMethod.PUT }, produces = { 
"application/json" })
     @ResponseBody
     public ProjectInstance updateProject(@RequestBody ProjectRequest 
projectRequest) {
         String formerProjectName = projectRequest.getFormerProjectName();
@@ -223,7 +228,7 @@ public class ProjectController extends BasicController {
         return projectDesc;
     }
 
-    @RequestMapping(value = "/{projectName}", method = { RequestMethod.DELETE 
})
+    @RequestMapping(value = "/{projectName}", method = { RequestMethod.DELETE 
}, produces = { "application/json" })
     @ResponseBody
     public void deleteProject(@PathVariable String projectName) {
         try {

Reply via email to