kylin-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From liy...@apache.org
Subject [07/13] kylin git commit: KYLIN-1823 split code from kylin-server into kylin-server-base
Date Sat, 25 Jun 2016 23:34:19 GMT
http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java b/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java
new file mode 100644
index 0000000..c0610a2
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/ProjectService.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.service;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.kylin.metadata.project.ProjectInstance;
+import org.apache.kylin.metadata.project.ProjectManager;
+import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.apache.kylin.rest.request.CreateProjectRequest;
+import org.apache.kylin.rest.request.UpdateProjectRequest;
+import org.apache.kylin.rest.security.AclPermission;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author xduo
+ * 
+ */
+@Component("projectService")
+public class ProjectService extends BasicService {
+
+    private static final Logger logger = LoggerFactory.getLogger(ProjectService.class);
+
+    @Autowired
+    private AccessService accessService;
+
+    public ProjectInstance createProject(CreateProjectRequest projectRequest) throws IOException {
+        String projectName = projectRequest.getName();
+        String description = projectRequest.getDescription();
+        ProjectInstance currentProject = getProjectManager().getProject(projectName);
+
+        if (currentProject != null) {
+            throw new InternalErrorException("The project named " + projectName + " already exists");
+        }
+        String owner = SecurityContextHolder.getContext().getAuthentication().getName();
+        ProjectInstance createdProject = getProjectManager().createProject(projectName, owner, description);
+        accessService.init(createdProject, AclPermission.ADMINISTRATION);
+        logger.debug("New project created.");
+
+        return createdProject;
+    }
+
+    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#currentProject, 'ADMINISTRATION') or hasPermission(#currentProject, 'MANAGEMENT')")
+    public ProjectInstance updateProject(UpdateProjectRequest projectRequest, ProjectInstance currentProject) throws IOException {
+        String formerProjectName = projectRequest.getFormerProjectName();
+        String newProjectName = projectRequest.getNewProjectName();
+        String newDescription = projectRequest.getNewDescription();
+
+        if (currentProject == null) {
+            throw new InternalErrorException("The project named " + formerProjectName + " does not exists");
+        }
+
+        ProjectInstance updatedProject = getProjectManager().updateProject(currentProject, newProjectName, newDescription);
+
+        logger.debug("Project updated.");
+
+        return updatedProject;
+    }
+
+    public List<ProjectInstance> listAllProjects(final Integer limit, final Integer offset) {
+        List<ProjectInstance> projects = getProjectManager().listAllProjects();
+
+        int climit = (null == limit) ? Integer.MAX_VALUE : limit;
+        int coffset = (null == offset) ? 0 : offset;
+
+        if (projects.size() <= coffset) {
+            return Collections.emptyList();
+        }
+
+        if ((projects.size() - coffset) < climit) {
+            return projects.subList(coffset, projects.size());
+        }
+
+        return projects.subList(coffset, coffset + climit);
+    }
+
+    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#project, 'ADMINISTRATION') or hasPermission(#cube, 'MANAGEMENT')")
+    public void deleteProject(String projectName, ProjectInstance project) throws IOException {
+        getProjectManager().dropProject(projectName);
+
+        accessService.clean(project, true);
+    }
+
+    public boolean isTableInAnyProject(String tableName) {
+        for (ProjectInstance projectInstance : ProjectManager.getInstance(getConfig()).listAllProjects()) {
+            if (projectInstance.containsTable(tableName.toUpperCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isTableInProject(String tableName, String projectName) {
+        ProjectInstance projectInstance = ProjectManager.getInstance(getConfig()).getProject(projectName);
+        if (projectInstance != null) {
+            if (projectInstance.containsTable(tableName.toUpperCase())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
new file mode 100644
index 0000000..84a5c67
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/QueryService.java
@@ -0,0 +1,517 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.service;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.sql.DataSource;
+
+import org.apache.calcite.avatica.ColumnMetaData.Rep;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.HConnection;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.Bytes;
+import org.apache.kylin.cube.CubeInstance;
+import org.apache.kylin.cube.CubeManager;
+import org.apache.kylin.cube.cuboid.Cuboid;
+import org.apache.kylin.query.relnode.OLAPContext;
+import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.model.ColumnMeta;
+import org.apache.kylin.rest.model.Query;
+import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.rest.model.TableMeta;
+import org.apache.kylin.rest.request.PrepareSqlRequest;
+import org.apache.kylin.rest.request.SQLRequest;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.apache.kylin.rest.util.QueryUtil;
+import org.apache.kylin.rest.util.Serializer;
+import org.apache.kylin.storage.hbase.HBaseConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+
+import com.google.common.collect.Lists;
+
+/**
+ * @author xduo
+ */
+@Component("queryService")
+public class QueryService extends BasicService {
+
+    private static final Logger logger = LoggerFactory.getLogger(QueryService.class);
+
+    @Autowired
+    private CacheService cacheService;
+
+    public static final String USER_QUERY_FAMILY = "q";
+    private static final String DEFAULT_TABLE_PREFIX = "kylin_metadata";
+    private static final String USER_TABLE_NAME = "_user";
+    private static final String USER_QUERY_COLUMN = "c";
+
+    private final Serializer<Query[]> querySerializer = new Serializer<Query[]>(Query[].class);
+    private final BadQueryDetector badQueryDetector = new BadQueryDetector();
+
+    private final String hbaseUrl;
+    private final String tableNameBase;
+    private final String userTableName;
+
+    public QueryService() {
+        String metadataUrl = KylinConfig.getInstanceFromEnv().getMetadataUrl();
+        // split TABLE@HBASE_URL
+        int cut = metadataUrl.indexOf('@');
+        tableNameBase = cut < 0 ? DEFAULT_TABLE_PREFIX : metadataUrl.substring(0, cut);
+        hbaseUrl = cut < 0 ? metadataUrl : metadataUrl.substring(cut + 1);
+        userTableName = tableNameBase + USER_TABLE_NAME;
+
+        badQueryDetector.start();
+    }
+
+    public List<TableMeta> getMetadata(String project) throws SQLException {
+        return getMetadata(getCubeManager(), project, true);
+    }
+
+    public SQLResponse query(SQLRequest sqlRequest) throws Exception {
+        try {
+            badQueryDetector.queryStart(Thread.currentThread(), sqlRequest);
+
+            return queryWithSqlMassage(sqlRequest);
+
+        } finally {
+            badQueryDetector.queryEnd(Thread.currentThread());
+        }
+    }
+
+    public void saveQuery(final String creator, final Query query) throws IOException {
+        List<Query> queries = getQueries(creator);
+        queries.add(query);
+        Query[] queryArray = new Query[queries.size()];
+
+        byte[] bytes = querySerializer.serialize(queries.toArray(queryArray));
+        HTableInterface htable = null;
+        try {
+            htable = HBaseConnection.get(hbaseUrl).getTable(userTableName);
+            Put put = new Put(Bytes.toBytes(creator));
+            put.add(Bytes.toBytes(USER_QUERY_FAMILY), Bytes.toBytes(USER_QUERY_COLUMN), bytes);
+
+            htable.put(put);
+            htable.flushCommits();
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    public void removeQuery(final String creator, final String id) throws IOException {
+        List<Query> queries = getQueries(creator);
+        Iterator<Query> queryIter = queries.iterator();
+
+        boolean changed = false;
+        while (queryIter.hasNext()) {
+            Query temp = queryIter.next();
+            if (temp.getId().equals(id)) {
+                queryIter.remove();
+                changed = true;
+                break;
+            }
+        }
+
+        if (!changed) {
+            return;
+        }
+
+        Query[] queryArray = new Query[queries.size()];
+        byte[] bytes = querySerializer.serialize(queries.toArray(queryArray));
+        HTableInterface htable = null;
+        try {
+            htable = HBaseConnection.get(hbaseUrl).getTable(userTableName);
+            Put put = new Put(Bytes.toBytes(creator));
+            put.add(Bytes.toBytes(USER_QUERY_FAMILY), Bytes.toBytes(USER_QUERY_COLUMN), bytes);
+
+            htable.put(put);
+            htable.flushCommits();
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    public List<Query> getQueries(final String creator) throws IOException {
+        if (null == creator) {
+            return null;
+        }
+
+        List<Query> queries = new ArrayList<Query>();
+        HTableInterface htable = null;
+        try {
+            HConnection conn = HBaseConnection.get(hbaseUrl);
+            HBaseConnection.createHTableIfNeeded(conn, userTableName, USER_QUERY_FAMILY);
+
+            htable = conn.getTable(userTableName);
+            Get get = new Get(Bytes.toBytes(creator));
+            get.addFamily(Bytes.toBytes(USER_QUERY_FAMILY));
+            Result result = htable.get(get);
+            Query[] query = querySerializer.deserialize(result.getValue(Bytes.toBytes(USER_QUERY_FAMILY), Bytes.toBytes(USER_QUERY_COLUMN)));
+
+            if (null != query) {
+                queries.addAll(Arrays.asList(query));
+            }
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+
+        return queries;
+    }
+
+    public void logQuery(final SQLRequest request, final SQLResponse response) {
+        final String user = SecurityContextHolder.getContext().getAuthentication().getName();
+        final Set<String> realizationNames = new HashSet<String>();
+        final Set<Long> cuboidIds = new HashSet<Long>();
+        float duration = response.getDuration() / (float) 1000;
+        boolean storageCacheUsed = response.isStorageCacheUsed();
+
+        if (!response.isHitExceptionCache() && null != OLAPContext.getThreadLocalContexts()) {
+            for (OLAPContext ctx : OLAPContext.getThreadLocalContexts()) {
+                Cuboid cuboid = ctx.storageContext.getCuboid();
+                if (cuboid != null) {
+                    //Some queries do not involve cuboid, e.g. lookup table query
+                    cuboidIds.add(cuboid.getId());
+                }
+
+                if (ctx.realization != null) {
+                    String realizationName = ctx.realization.getName();
+                    realizationNames.add(realizationName);
+                }
+
+            }
+        }
+
+        int resultRowCount = 0;
+        if (!response.getIsException() && response.getResults() != null) {
+            resultRowCount = response.getResults().size();
+        }
+
+        String newLine = System.getProperty("line.separator");
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(newLine);
+        stringBuilder.append("==========================[QUERY]===============================").append(newLine);
+        stringBuilder.append("SQL: ").append(request.getSql()).append(newLine);
+        stringBuilder.append("User: ").append(user).append(newLine);
+        stringBuilder.append("Success: ").append((null == response.getExceptionMessage())).append(newLine);
+        stringBuilder.append("Duration: ").append(duration).append(newLine);
+        stringBuilder.append("Project: ").append(request.getProject()).append(newLine);
+        stringBuilder.append("Realization Names: ").append(realizationNames).append(newLine);
+        stringBuilder.append("Cuboid Ids: ").append(cuboidIds).append(newLine);
+        stringBuilder.append("Total scan count: ").append(response.getTotalScanCount()).append(newLine);
+        stringBuilder.append("Result row count: ").append(resultRowCount).append(newLine);
+        stringBuilder.append("Accept Partial: ").append(request.isAcceptPartial()).append(newLine);
+        stringBuilder.append("Is Partial Result: ").append(response.isPartial()).append(newLine);
+        stringBuilder.append("Hit Exception Cache: ").append(response.isHitExceptionCache()).append(newLine);
+        stringBuilder.append("Storage cache used: ").append(storageCacheUsed).append(newLine);
+        stringBuilder.append("Message: ").append(response.getExceptionMessage()).append(newLine);
+        stringBuilder.append("==========================[QUERY]===============================").append(newLine);
+
+        logger.info(stringBuilder.toString());
+    }
+
+    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#cube, 'ADMINISTRATION') or hasPermission(#cube, 'MANAGEMENT')" + " or hasPermission(#cube, 'OPERATION') or hasPermission(#cube, 'READ')")
+    public void checkAuthorization(CubeInstance cube) throws AccessDeniedException {
+    }
+
+    private SQLResponse queryWithSqlMassage(SQLRequest sqlRequest) throws Exception {
+        SQLResponse fakeResponse = QueryUtil.tableauIntercept(sqlRequest.getSql());
+        if (null != fakeResponse) {
+            logger.debug("Return fake response, is exception? " + fakeResponse.getIsException());
+            return fakeResponse;
+        }
+
+        String correctedSql = QueryUtil.massageSql(sqlRequest);
+        if (correctedSql.equals(sqlRequest.getSql()) == false)
+            logger.info("The corrected query: " + correctedSql);
+
+        // add extra parameters into olap context, like acceptPartial
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(OLAPContext.PRM_ACCEPT_PARTIAL_RESULT, String.valueOf(sqlRequest.isAcceptPartial()));
+        OLAPContext.setParameters(parameters);
+
+        return execute(correctedSql, sqlRequest);
+
+    }
+
+    protected List<TableMeta> getMetadata(CubeManager cubeMgr, String project, boolean cubedOnly) throws SQLException {
+
+        Connection conn = null;
+        ResultSet columnMeta = null;
+        List<TableMeta> tableMetas = null;
+        if (StringUtils.isBlank(project)) {
+            return Collections.emptyList();
+        }
+        ResultSet JDBCTableMeta = null;
+        try {
+            DataSource dataSource = cacheService.getOLAPDataSource(project);
+            conn = dataSource.getConnection();
+            DatabaseMetaData metaData = conn.getMetaData();
+
+            logger.debug("getting table metas");
+            JDBCTableMeta = metaData.getTables(null, null, null, null);
+
+            tableMetas = new LinkedList<TableMeta>();
+            Map<String, TableMeta> tableMap = new HashMap<String, TableMeta>();
+            while (JDBCTableMeta.next()) {
+                String catalogName = JDBCTableMeta.getString(1);
+                String schemaName = JDBCTableMeta.getString(2);
+
+                // Not every JDBC data provider offers full 10 columns, e.g., PostgreSQL has only 5
+                TableMeta tblMeta = new TableMeta(catalogName == null ? Constant.FakeCatalogName : catalogName, schemaName == null ? Constant.FakeSchemaName : schemaName, JDBCTableMeta.getString(3), JDBCTableMeta.getString(4), JDBCTableMeta.getString(5), null, null, null, null, null);
+
+                if (!cubedOnly || getProjectManager().isExposedTable(project, schemaName + "." + tblMeta.getTABLE_NAME())) {
+                    tableMetas.add(tblMeta);
+                    tableMap.put(tblMeta.getTABLE_SCHEM() + "#" + tblMeta.getTABLE_NAME(), tblMeta);
+                }
+            }
+
+            logger.debug("getting column metas");
+            columnMeta = metaData.getColumns(null, null, null, null);
+
+            while (columnMeta.next()) {
+                String catalogName = columnMeta.getString(1);
+                String schemaName = columnMeta.getString(2);
+
+                // kylin(optiq) is not strictly following JDBC specification
+                ColumnMeta colmnMeta = new ColumnMeta(catalogName == null ? Constant.FakeCatalogName : catalogName, schemaName == null ? Constant.FakeSchemaName : schemaName, columnMeta.getString(3), columnMeta.getString(4), columnMeta.getInt(5), columnMeta.getString(6), columnMeta.getInt(7), getInt(columnMeta.getString(8)), columnMeta.getInt(9), columnMeta.getInt(10), columnMeta.getInt(11), columnMeta.getString(12), columnMeta.getString(13), getInt(columnMeta.getString(14)), getInt(columnMeta.getString(15)), columnMeta.getInt(16), columnMeta.getInt(17), columnMeta.getString(18), columnMeta.getString(19), columnMeta.getString(20), columnMeta.getString(21), getShort(columnMeta.getString(22)), columnMeta.getString(23));
+
+                if (!cubedOnly || getProjectManager().isExposedColumn(project, schemaName + "." + colmnMeta.getTABLE_NAME(), colmnMeta.getCOLUMN_NAME())) {
+                    tableMap.get(colmnMeta.getTABLE_SCHEM() + "#" + colmnMeta.getTABLE_NAME()).addColumn(colmnMeta);
+                }
+            }
+            logger.debug("done column metas");
+        } finally {
+            close(columnMeta, null, conn);
+            if (JDBCTableMeta != null) {
+                JDBCTableMeta.close();
+            }
+        }
+
+        return tableMetas;
+    }
+
+    /**
+     * @param sql
+     * @param sqlRequest
+     * @return
+     * @throws Exception
+     */
+    private SQLResponse execute(String sql, SQLRequest sqlRequest) throws Exception {
+        Connection conn = null;
+        Statement stat = null;
+        ResultSet resultSet = null;
+
+        List<List<String>> results = Lists.newArrayList();
+        List<SelectedColumnMeta> columnMetas = Lists.newArrayList();
+
+        try {
+            conn = cacheService.getOLAPDataSource(sqlRequest.getProject()).getConnection();
+
+            if (sqlRequest instanceof PrepareSqlRequest) {
+                PreparedStatement preparedState = conn.prepareStatement(sql);
+
+                for (int i = 0; i < ((PrepareSqlRequest) sqlRequest).getParams().length; i++) {
+                    setParam(preparedState, i + 1, ((PrepareSqlRequest) sqlRequest).getParams()[i]);
+                }
+
+                resultSet = preparedState.executeQuery();
+            } else {
+                stat = conn.createStatement();
+                resultSet = stat.executeQuery(sql);
+            }
+
+            ResultSetMetaData metaData = resultSet.getMetaData();
+            int columnCount = metaData.getColumnCount();
+
+            // Fill in selected column meta
+            for (int i = 1; i <= columnCount; ++i) {
+                columnMetas.add(new SelectedColumnMeta(metaData.isAutoIncrement(i), metaData.isCaseSensitive(i), metaData.isSearchable(i), metaData.isCurrency(i), metaData.isNullable(i), metaData.isSigned(i), metaData.getColumnDisplaySize(i), metaData.getColumnLabel(i), metaData.getColumnName(i), metaData.getSchemaName(i), metaData.getCatalogName(i), metaData.getTableName(i), metaData.getPrecision(i), metaData.getScale(i), metaData.getColumnType(i), metaData.getColumnTypeName(i), metaData.isReadOnly(i), metaData.isWritable(i), metaData.isDefinitelyWritable(i)));
+            }
+
+            // fill in results
+            while (resultSet.next()) {
+                List<String> oneRow = Lists.newArrayListWithCapacity(columnCount);
+                for (int i = 0; i < columnCount; i++) {
+                    oneRow.add((resultSet.getString(i + 1)));
+                }
+
+                results.add(oneRow);
+            }
+        } finally {
+            close(resultSet, stat, conn);
+        }
+
+        boolean isPartialResult = false;
+        String cube = "";
+        StringBuilder sb = new StringBuilder("Scan count for each storageContext: ");
+        long totalScanCount = 0;
+        if (OLAPContext.getThreadLocalContexts() != null) { // contexts can be null in case of 'explain plan for'
+            for (OLAPContext ctx : OLAPContext.getThreadLocalContexts()) {
+                if (ctx.realization != null) {
+                    isPartialResult |= ctx.storageContext.isPartialResultReturned();
+                    cube = ctx.realization.getName();
+                    totalScanCount += ctx.storageContext.getTotalScanCount();
+                    sb.append(ctx.storageContext.getTotalScanCount() + ",");
+                }
+            }
+        }
+        logger.info(sb.toString());
+
+        SQLResponse response = new SQLResponse(columnMetas, results, cube, 0, false, null, isPartialResult);
+        response.setTotalScanCount(totalScanCount);
+
+        return response;
+    }
+
+    /**
+     * @param preparedState
+     * @param param
+     * @throws SQLException
+     */
+    private void setParam(PreparedStatement preparedState, int index, PrepareSqlRequest.StateParam param) throws SQLException {
+        boolean isNull = (null == param.getValue());
+
+        Class<?> clazz;
+        try {
+            clazz = Class.forName(param.getClassName());
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+
+        Rep rep = Rep.of(clazz);
+
+        switch (rep) {
+        case PRIMITIVE_CHAR:
+        case CHARACTER:
+        case STRING:
+            preparedState.setString(index, isNull ? null : String.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_INT:
+        case INTEGER:
+            preparedState.setInt(index, isNull ? 0 : Integer.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_SHORT:
+        case SHORT:
+            preparedState.setShort(index, isNull ? 0 : Short.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_LONG:
+        case LONG:
+            preparedState.setLong(index, isNull ? 0 : Long.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_FLOAT:
+        case FLOAT:
+            preparedState.setFloat(index, isNull ? 0 : Float.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_DOUBLE:
+        case DOUBLE:
+            preparedState.setDouble(index, isNull ? 0 : Double.valueOf(param.getValue()));
+            break;
+        case PRIMITIVE_BOOLEAN:
+        case BOOLEAN:
+            preparedState.setBoolean(index, !isNull && Boolean.parseBoolean(param.getValue()));
+            break;
+        case PRIMITIVE_BYTE:
+        case BYTE:
+            preparedState.setByte(index, isNull ? 0 : Byte.valueOf(param.getValue()));
+            break;
+        case JAVA_UTIL_DATE:
+        case JAVA_SQL_DATE:
+            preparedState.setDate(index, isNull ? null : java.sql.Date.valueOf(param.getValue()));
+            break;
+        case JAVA_SQL_TIME:
+            preparedState.setTime(index, isNull ? null : Time.valueOf(param.getValue()));
+            break;
+        case JAVA_SQL_TIMESTAMP:
+            preparedState.setTimestamp(index, isNull ? null : Timestamp.valueOf(param.getValue()));
+            break;
+        default:
+            preparedState.setObject(index, isNull ? null : param.getValue());
+        }
+    }
+
+    private int getInt(String content) {
+        try {
+            return Integer.parseInt(content);
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    private short getShort(String content) {
+        try {
+            return Short.parseShort(content);
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    private static void close(ResultSet resultSet, Statement stat, Connection conn) {
+        OLAPContext.clearParameter();
+
+        if (resultSet != null)
+            try {
+                resultSet.close();
+            } catch (SQLException e) {
+                logger.error("failed to close", e);
+            }
+        if (stat != null)
+            try {
+                stat.close();
+            } catch (SQLException e) {
+                logger.error("failed to close", e);
+            }
+        if (conn != null)
+            try {
+                conn.close();
+            } catch (SQLException e) {
+                logger.error("failed to close", e);
+            }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/service/StreamingService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/StreamingService.java b/server-base/src/main/java/org/apache/kylin/rest/service/StreamingService.java
new file mode 100644
index 0000000..e49e882
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/StreamingService.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.kylin.engine.streaming.StreamingConfig;
+import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.exception.InternalErrorException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PostFilter;
+import org.springframework.stereotype.Component;
+
+@Component("streamingMgmtService")
+public class StreamingService extends BasicService {
+
+    @Autowired
+    private AccessService accessService;
+
+    @PostFilter(Constant.ACCESS_POST_FILTER_READ)
+    public List<StreamingConfig> listAllStreamingConfigs(final String table) throws IOException {
+        List<StreamingConfig> streamingConfigs = new ArrayList();
+        if (StringUtils.isEmpty(table)) {
+            streamingConfigs = getStreamingManager().listAllStreaming();
+        } else {
+            StreamingConfig config = getStreamingManager().getConfig(table);
+            if (config != null) {
+                streamingConfigs.add(config);
+            }
+        }
+
+        return streamingConfigs;
+    }
+
+    public List<StreamingConfig> getStreamingConfigs(final String table, final Integer limit, final Integer offset) throws IOException {
+
+        List<StreamingConfig> streamingConfigs;
+        streamingConfigs = listAllStreamingConfigs(table);
+
+        if (limit == null || offset == null) {
+            return streamingConfigs;
+        }
+
+        if ((streamingConfigs.size() - offset) < limit) {
+            return streamingConfigs.subList(offset, streamingConfigs.size());
+        }
+
+        return streamingConfigs.subList(offset, offset + limit);
+    }
+
+    public StreamingConfig createStreamingConfig(StreamingConfig config) throws IOException {
+        if (getStreamingManager().getStreamingConfig(config.getName()) != null) {
+            throw new InternalErrorException("The streamingConfig named " + config.getName() + " already exists");
+        }
+        StreamingConfig streamingConfig = getStreamingManager().saveStreamingConfig(config);
+        return streamingConfig;
+    }
+
+    //    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#desc, 'ADMINISTRATION') or hasPermission(#desc, 'MANAGEMENT')")
+    public StreamingConfig updateStreamingConfig(StreamingConfig config) throws IOException {
+        return getStreamingManager().updateStreamingConfig(config);
+    }
+
+    //    @PreAuthorize(Constant.ACCESS_HAS_ROLE_ADMIN + " or hasPermission(#desc, 'ADMINISTRATION') or hasPermission(#desc, 'MANAGEMENT')")
+    public void dropStreamingConfig(StreamingConfig config) throws IOException {
+        getStreamingManager().removeStreamingConfig(config);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java b/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
new file mode 100644
index 0000000..07c7c6f
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/service/UserService.java
@@ -0,0 +1,289 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.kylin.common.util.Bytes;
+import org.apache.kylin.common.util.Pair;
+import org.apache.kylin.rest.security.AclHBaseStorage;
+import org.apache.kylin.rest.util.Serializer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.provisioning.UserDetailsManager;
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+/**
+ */
+@Component("userService")
+public class UserService implements UserDetailsManager {
+
+    private static final String PWD_PREFIX = "PWD:";
+
+    private Serializer<UserGrantedAuthority[]> ugaSerializer = new Serializer<UserGrantedAuthority[]>(UserGrantedAuthority[].class);
+
+    private String userTableName = null;
+
+    @Autowired
+    protected AclHBaseStorage aclHBaseStorage;
+
+    @PostConstruct
+    public void init() throws IOException {
+        userTableName = aclHBaseStorage.prepareHBaseTable(UserService.class);
+    }
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        HTableInterface htable = null;
+        try {
+            htable = aclHBaseStorage.getTable(userTableName);
+
+            Get get = new Get(Bytes.toBytes(username));
+            get.addFamily(Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_FAMILY));
+            Result result = htable.get(get);
+
+            User user = hbaseRowToUser(result);
+            if (user == null)
+                throw new UsernameNotFoundException("User " + username + " not found.");
+
+            return user;
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    private User hbaseRowToUser(Result result) throws JsonParseException, JsonMappingException, IOException {
+        if (null == result || result.isEmpty())
+            return null;
+
+        String username = Bytes.toString(result.getRow());
+
+        byte[] valueBytes = result.getValue(Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_FAMILY), Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_COLUMN));
+        UserGrantedAuthority[] deserialized = ugaSerializer.deserialize(valueBytes);
+
+        String password = "";
+        List<UserGrantedAuthority> authorities = Collections.emptyList();
+
+        // password is stored at [0] of authorities for backward compatibility
+        if (deserialized != null) {
+            if (deserialized.length > 0 && deserialized[0].getAuthority().startsWith(PWD_PREFIX)) {
+                password = deserialized[0].getAuthority().substring(PWD_PREFIX.length());
+                authorities = Arrays.asList(deserialized).subList(1, deserialized.length);
+            } else {
+                authorities = Arrays.asList(deserialized);
+            }
+        }
+
+        return new User(username, password, authorities);
+    }
+
+    private Pair<byte[], byte[]> userToHBaseRow(UserDetails user) throws JsonProcessingException {
+        byte[] key = Bytes.toBytes(user.getUsername());
+
+        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
+        if (authorities == null)
+            authorities = Collections.emptyList();
+
+        UserGrantedAuthority[] serializing = new UserGrantedAuthority[authorities.size() + 1];
+
+        // password is stored as the [0] authority
+        serializing[0] = new UserGrantedAuthority(PWD_PREFIX + user.getPassword());
+        int i = 1;
+        for (GrantedAuthority a : authorities) {
+            serializing[i++] = new UserGrantedAuthority(a.getAuthority());
+        }
+
+        byte[] value = ugaSerializer.serialize(serializing);
+        return Pair.newPair(key, value);
+    }
+
+    @Override
+    public void createUser(UserDetails user) {
+        updateUser(user);
+    }
+
+    @Override
+    public void updateUser(UserDetails user) {
+        HTableInterface htable = null;
+        try {
+            htable = aclHBaseStorage.getTable(userTableName);
+
+            Pair<byte[], byte[]> pair = userToHBaseRow(user);
+            Put put = new Put(pair.getKey());
+            put.add(Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_FAMILY), Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_COLUMN), pair.getSecond());
+
+            htable.put(put);
+            htable.flushCommits();
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    @Override
+    public void deleteUser(String username) {
+        HTableInterface htable = null;
+        try {
+            htable = aclHBaseStorage.getTable(userTableName);
+
+            Delete delete = new Delete(Bytes.toBytes(username));
+
+            htable.delete(delete);
+            htable.flushCommits();
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    @Override
+    public void changePassword(String oldPassword, String newPassword) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean userExists(String username) {
+        HTableInterface htable = null;
+        try {
+            htable = aclHBaseStorage.getTable(userTableName);
+
+            Result result = htable.get(new Get(Bytes.toBytes(username)));
+
+            return null != result && !result.isEmpty();
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            IOUtils.closeQuietly(htable);
+        }
+    }
+
+    public List<String> listUserAuthorities() {
+        List<String> all = new ArrayList<String>();
+        for (UserDetails user : listUsers()) {
+            for (GrantedAuthority auth : user.getAuthorities()) {
+                if (!all.contains(auth.getAuthority())) {
+                    all.add(auth.getAuthority());
+                }
+            }
+        }
+        return all;
+    }
+
+    public List<UserDetails> listUsers() {
+        Scan s = new Scan();
+        s.addColumn(Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_FAMILY), Bytes.toBytes(AclHBaseStorage.USER_AUTHORITY_COLUMN));
+
+        List<UserDetails> all = new ArrayList<UserDetails>();
+        HTableInterface htable = null;
+        ResultScanner scanner = null;
+        try {
+            htable = aclHBaseStorage.getTable(userTableName);
+            scanner = htable.getScanner(s);
+
+            for (Result result = scanner.next(); result != null; result = scanner.next()) {
+                User user = hbaseRowToUser(result);
+                all.add(user);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to scan users", e);
+        } finally {
+            IOUtils.closeQuietly(scanner);
+            IOUtils.closeQuietly(htable);
+        }
+        return all;
+    }
+
+    public static class UserGrantedAuthority implements GrantedAuthority {
+        private static final long serialVersionUID = -5128905636841891058L;
+        private String authority;
+
+        public UserGrantedAuthority() {
+        }
+
+        public UserGrantedAuthority(String authority) {
+            setAuthority(authority);
+        }
+
+        @Override
+        public String getAuthority() {
+            return authority;
+        }
+
+        public void setAuthority(String authority) {
+            this.authority = authority;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((authority == null) ? 0 : authority.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            UserGrantedAuthority other = (UserGrantedAuthority) obj;
+            if (authority == null) {
+                if (other.authority != null)
+                    return false;
+            } else if (!authority.equals(other.authority))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            return authority;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/util/Log4jConfigListener.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/Log4jConfigListener.java b/server-base/src/main/java/org/apache/kylin/rest/util/Log4jConfigListener.java
new file mode 100644
index 0000000..7e79511
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/Log4jConfigListener.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.rest.util;
+
+import javax.servlet.ServletContextEvent;
+
+import org.apache.kylin.common.KylinConfig;
+
+public class Log4jConfigListener extends org.springframework.web.util.Log4jConfigListener {
+
+    private boolean isDebugTomcat;
+
+    public Log4jConfigListener() {
+        this.isDebugTomcat = KylinConfig.getInstanceFromEnv().isDevEnv();
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent event) {
+        if (!isDebugTomcat) {
+            super.contextInitialized(event);
+        }
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent event) {
+        if (!isDebugTomcat) {
+            super.contextDestroyed(event);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java b/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
new file mode 100644
index 0000000..c15e5f9
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/QueryUtil.java
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.util;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.rest.request.SQLRequest;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+public class QueryUtil {
+
+    protected static final Logger logger = LoggerFactory.getLogger(QueryUtil.class);
+
+    private static final String S0 = "\\s*";
+    private static final String S1 = "\\s";
+    private static final String SM = "\\s+";
+    private static final Pattern PTN_GROUP_BY = Pattern.compile(S1 + "GROUP" + SM + "BY" + S1, Pattern.CASE_INSENSITIVE);
+    private static final Pattern PTN_HAVING_COUNT_GREATER_THAN_ZERO = Pattern.compile(S1 + "HAVING" + SM + "[(]?" + S0 + "COUNT" + S0 + "[(]" + S0 + "1" + S0 + "[)]" + S0 + ">" + S0 + "0" + S0 + "[)]?", Pattern.CASE_INSENSITIVE);
+    private static final Pattern PTN_SUM_1 = Pattern.compile(S1 + "SUM" + S0 + "[(]" + S0 + "[1]" + S0 + "[)]" + S1, Pattern.CASE_INSENSITIVE);
+
+    // private static final Pattern PTN_HAVING_ESCAPE_FUNCTION =
+    // Pattern.compile("\\{fn" + "(" + S0 + ")" + "\\}",
+    // Pattern.CASE_INSENSITIVE);
+    private static final Pattern PTN_HAVING_ESCAPE_FUNCTION = Pattern.compile("\\{fn" + "(.*?)" + "\\}", Pattern.CASE_INSENSITIVE);
+
+    private static String[] tableauTestQueries = new String[] { "SELECT 1", //
+            "CREATE LOCAL TEMPORARY TABLE \"XTableau_B_Connect\" ( \"COL\" INTEGER ) ON COMMIT PRESERVE ROWS", //
+            "DROP TABLE \"XTableau_B_Connect\"", //
+            "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"SUBQUERY\"", //
+            "SELECT TOP 1 \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\"", "SELECT \"COL\" FROM (SELECT 1 AS \"COL\") AS \"CHECKTOP\" LIMIT 1", //
+            "SELECT \"SUBCOL\" AS \"COL\"  FROM (   SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 1", "SELECT \"SUBCOL\" AS \"COL\" FROM (   SELECT 1 AS \"SUBCOL\" ) \"SUBQUERY\" GROUP BY 2", "INSERT INTO \"XTableau_C_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1", "DROP TABLE \"XTableau_C_Connect\"", "INSERT INTO \"XTableau_B_Connect\" SELECT * FROM (SELECT 1 AS COL) AS CHECKTEMP LIMIT 1" };
+
+    private static SQLResponse temp = new SQLResponse(new LinkedList<SelectedColumnMeta>() {
+        private static final long serialVersionUID = -8086728462624901359L;
+
+        {
+            add(new SelectedColumnMeta(false, false, true, false, 2, true, 11, "COL", "COL", "", "", "", 10, 0, 4, "int4", false, true, false));
+        }
+    }, new LinkedList<List<String>>() {
+        private static final long serialVersionUID = -470083340592928073L;
+
+        {
+            add(new LinkedList<String>() {
+                private static final long serialVersionUID = -3673192785838230054L;
+
+                {
+                    add("1");
+                }
+            });
+        }
+    }, 0, false, null);
+
+    private static SQLResponse[] fakeResponses = new SQLResponse[] { temp, new SQLResponse(null, null, 0, false, null), //
+            new SQLResponse(null, null, 0, false, null), //
+            temp, //
+            new SQLResponse(null, null, 0, true, "near 1 syntax error"), //
+            temp, //
+            new SQLResponse(null, null, 0, true, "group by 1????"), //
+            new SQLResponse(null, null, 0, true, "group by 2????"), //
+            new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), //
+            new SQLResponse(null, null, 0, true, "XTableau_C_Connect not exist"), new SQLResponse(null, null, 0, true, "XTableau_B_Connect not exist"), };
+
+    private static ArrayList<HashSet<String>> tableauTestQueriesInToken = new ArrayList<HashSet<String>>();
+
+    static {
+        for (String q : tableauTestQueries) {
+            HashSet<String> temp = new HashSet<String>();
+            for (String token : q.split("[\r\n\t \\(\\)]")) {
+                temp.add(token);
+            }
+            temp.add("");
+            tableauTestQueriesInToken.add(temp);
+        }
+    }
+
+    public static String massageSql(SQLRequest sqlRequest) {
+        String sql = sqlRequest.getSql();
+        sql = sql.trim();
+
+        while (sql.endsWith(";"))
+            sql = sql.substring(0, sql.length() - 1);
+
+        int limit = sqlRequest.getLimit();
+        if (limit > 0 && !sql.toLowerCase().contains("limit")) {
+            sql += ("\nLIMIT " + limit);
+        }
+
+        int offset = sqlRequest.getOffset();
+        if (offset > 0 && !sql.toLowerCase().contains("offset")) {
+            sql += ("\nOFFSET " + offset);
+        }
+
+        return healSickSql(sql);
+    }
+
+    // correct sick / invalid SQL
+    private static String healSickSql(String sql) {
+        Matcher m;
+
+        // Case fn{ EXTRACT(...) }
+        // Use non-greedy regrex matching to remove escape functions
+        while (true) {
+            m = PTN_HAVING_ESCAPE_FUNCTION.matcher(sql);
+            if (!m.find())
+                break;
+            sql = sql.substring(0, m.start()) + m.group(1) + sql.substring(m.end());
+        }
+
+        // Case: HAVING COUNT(1)>0 without Group By
+        // Tableau generates: SELECT SUM(1) AS "COL" FROM "VAC_SW" HAVING
+        // COUNT(1)>0
+        m = PTN_HAVING_COUNT_GREATER_THAN_ZERO.matcher(sql);
+        if (m.find() && PTN_GROUP_BY.matcher(sql).find() == false) {
+            sql = sql.substring(0, m.start()) + " " + sql.substring(m.end());
+        }
+
+        // Case: SUM(1)
+        // Replace it with COUNT(1)
+        while (true) {
+            m = PTN_SUM_1.matcher(sql);
+            if (!m.find())
+                break;
+            sql = sql.substring(0, m.start()) + " COUNT(1) " + sql.substring(m.end());
+        }
+
+        return sql;
+    }
+
+    public static SQLResponse tableauIntercept(String sql) {
+
+        String[] tokens = sql.split("[\r\n\t \\(\\)]");
+        for (int i = 0; i < tableauTestQueries.length; ++i) {
+            if (isTokenWiseEqual(tokens, tableauTestQueriesInToken.get(i))) {
+                logger.info("Hit fake response " + i);
+                return fakeResponses[i];
+            }
+        }
+
+        return null;
+    }
+
+    public static String makeErrorMsgUserFriendly(Throwable e) {
+        String msg = e.getMessage();
+
+        // pick ParseException error message if possible
+        Throwable cause = e;
+        while (cause != null) {
+            if (cause.getClass().getName().contains("ParseException")) {
+                msg = cause.getMessage();
+                break;
+            }
+            cause = cause.getCause();
+        }
+
+        return makeErrorMsgUserFriendly(msg);
+    }
+
+    public static String makeErrorMsgUserFriendly(String errorMsg) {
+        try {
+            // make one line
+            errorMsg = errorMsg.replaceAll("\\s", " ");
+
+            // move cause to be ahead of sql, calcite creates the message pattern below
+            Pattern pattern = Pattern.compile("error while executing SQL \"(.*)\":(.*)");
+            Matcher matcher = pattern.matcher(errorMsg);
+            if (matcher.find()) {
+                return matcher.group(2).trim() + "\n" + "while executing SQL: \"" + matcher.group(1).trim() + "\"";
+            } else
+                return errorMsg;
+        } catch (Exception e) {
+            return errorMsg;
+        }
+    }
+
+    private static boolean isTokenWiseEqual(String[] tokens, HashSet<String> tokenSet) {
+        for (String token : tokens) {
+            if (!tokenSet.contains(token)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/main/java/org/apache/kylin/rest/util/Serializer.java
----------------------------------------------------------------------
diff --git a/server-base/src/main/java/org/apache/kylin/rest/util/Serializer.java b/server-base/src/main/java/org/apache/kylin/rest/util/Serializer.java
new file mode 100644
index 0000000..d726e06
--- /dev/null
+++ b/server-base/src/main/java/org/apache/kylin/rest/util/Serializer.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.util;
+
+import java.io.IOException;
+
+import org.apache.kylin.common.util.JsonUtil;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+public class Serializer<T> {
+    private final Class<T> type;
+
+    public Serializer(Class<T> type) {
+        this.type = type;
+    }
+
+    public T deserialize(byte[] value) throws JsonParseException, JsonMappingException, IOException {
+        if (null == value) {
+            return null;
+        }
+
+        return JsonUtil.readValue(value, type);
+    }
+
+    public byte[] serialize(T obj) throws JsonProcessingException {
+        if (null == obj) {
+            return null;
+        }
+
+        return JsonUtil.writeValueAsBytes(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java
----------------------------------------------------------------------
diff --git a/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java
new file mode 100644
index 0000000..03d4dad
--- /dev/null
+++ b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.bean;
+
+import java.beans.IntrospectionException;
+
+import org.apache.kylin.rest.constant.Constant;
+import org.apache.kylin.rest.model.ColumnMeta;
+import org.apache.kylin.rest.model.SelectedColumnMeta;
+import org.apache.kylin.rest.model.TableMeta;
+import org.apache.kylin.rest.request.AccessRequest;
+import org.apache.kylin.rest.request.CubeRequest;
+import org.apache.kylin.rest.request.JobListRequest;
+import org.apache.kylin.rest.request.SQLRequest;
+import org.apache.kylin.rest.response.AccessEntryResponse;
+import org.apache.kylin.rest.response.SQLResponse;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xduo
+ * 
+ */
+public class BeanTest {
+
+    @Test
+    public void test() {
+        try {
+            BeanValidator.validateAccssor(ColumnMeta.class, new String[0]);
+            BeanValidator.validateAccssor(TableMeta.class, new String[0]);
+            BeanValidator.validateAccssor(SelectedColumnMeta.class, new String[0]);
+            BeanValidator.validateAccssor(AccessRequest.class, new String[0]);
+            BeanValidator.validateAccssor(CubeRequest.class, new String[0]);
+            BeanValidator.validateAccssor(JobListRequest.class, new String[0]);
+            BeanValidator.validateAccssor(SQLRequest.class, new String[0]);
+            BeanValidator.validateAccssor(AccessEntryResponse.class, new String[0]);
+            BeanValidator.validateAccssor(SQLResponse.class, new String[0]);
+        } catch (IntrospectionException e) {
+        }
+
+        new SQLResponse(null, null, null, 0, true, null);
+
+        SelectedColumnMeta coulmnMeta = new SelectedColumnMeta(false, false, false, false, 0, false, 0, null, null, null, null, null, 0, 0, 0, null, false, false, false);
+        Assert.assertTrue(!coulmnMeta.isAutoIncrement());
+        Assert.assertTrue(!coulmnMeta.isCaseSensitive());
+        Assert.assertTrue(!coulmnMeta.isSearchable());
+        Assert.assertTrue(!coulmnMeta.isCurrency());
+        Assert.assertTrue(coulmnMeta.getIsNullable() == 0);
+        Assert.assertTrue(!coulmnMeta.isSigned());
+
+        Assert.assertEquals(Constant.ACCESS_HAS_ROLE_ADMIN, "hasRole('ROLE_ADMIN')");
+        Assert.assertEquals(Constant.ACCESS_POST_FILTER_READ, "hasRole('ROLE_ADMIN') or hasPermission(filterObject, 'READ') or hasPermission(filterObject, 'MANAGEMENT') " + "or hasPermission(filterObject, 'OPERATION') or hasPermission(filterObject, 'ADMINISTRATION')");
+        Assert.assertEquals(Constant.FakeCatalogName, "defaultCatalog");
+        Assert.assertEquals(Constant.FakeSchemaName, "defaultSchema");
+        Assert.assertEquals(Constant.IDENTITY_ROLE, "role");
+        Assert.assertEquals(Constant.IDENTITY_USER, "user");
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server-base/src/test/java/org/apache/kylin/rest/bean/BeanValidator.java
----------------------------------------------------------------------
diff --git a/server-base/src/test/java/org/apache/kylin/rest/bean/BeanValidator.java b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanValidator.java
new file mode 100644
index 0000000..08010e4
--- /dev/null
+++ b/server-base/src/test/java/org/apache/kylin/rest/bean/BeanValidator.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+package org.apache.kylin.rest.bean;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Assert;
+
+/**
+ * @author xduo
+ * 
+ */
+public class BeanValidator {
+
+    /**
+     * Tests the get/set methods of the specified class.
+     */
+    public static <T> void validateAccssor(final Class<T> clazz, final String... skipThese) throws IntrospectionException {
+        final PropertyDescriptor[] props = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+        for (PropertyDescriptor prop : props) {
+
+            for (String skipThis : skipThese) {
+                if (skipThis.equals(prop.getName())) {
+                    continue;
+                }
+            }
+
+            findBooleanIsMethods(clazz, prop);
+
+            final Method getter = prop.getReadMethod();
+            final Method setter = prop.getWriteMethod();
+
+            if (getter != null && setter != null) {
+                final Class<?> returnType = getter.getReturnType();
+                final Class<?>[] params = setter.getParameterTypes();
+
+                if (params.length == 1 && params[0] == returnType) {
+                    try {
+                        Object value = buildValue(returnType);
+
+                        T bean = clazz.newInstance();
+
+                        setter.invoke(bean, value);
+
+                        Assert.assertEquals(String.format("Failed while testing property %s", prop.getName()), value, getter.invoke(bean));
+
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                        System.err.println(String.format("An exception was thrown while testing the property %s: %s", prop.getName(), ex.toString()));
+                    }
+                }
+            }
+        }
+    }
+
+    private static Object buildValue(Class<?> clazz) throws InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException {
+
+        final Constructor<?>[] ctrs = clazz.getConstructors();
+        for (Constructor<?> ctr : ctrs) {
+            if (ctr.getParameterTypes().length == 0) {
+                return ctr.newInstance();
+            }
+        }
+
+        // Specific rules for common classes
+        if (clazz.isArray()) {
+            return Array.newInstance(clazz.getComponentType(), 1);
+        } else if (List.class.isAssignableFrom(clazz)) {
+            return Collections.emptyList();
+        } else if (Set.class.isAssignableFrom(clazz)) {
+            return Collections.emptySet();
+        } else if (Map.class.isAssignableFrom(clazz)) {
+            return Collections.emptyMap();
+        } else if (clazz == String.class) {
+            return "TEST";
+        } else if (clazz == boolean.class || clazz == Boolean.class) {
+            return true;
+        } else if (clazz == short.class || clazz == Short.class) {
+            return (short) 1;
+        } else if (clazz == int.class || clazz == Integer.class) {
+            return 1;
+        } else if (clazz == long.class || clazz == Long.class) {
+            return 1L;
+        } else if (clazz == double.class || clazz == Double.class) {
+            return 1.0D;
+        } else if (clazz == float.class || clazz == Float.class) {
+            return 1.0F;
+        } else if (clazz == char.class || clazz == Character.class) {
+            return 'T';
+        } else if (clazz.isEnum()) {
+            return clazz.getEnumConstants()[0];
+        } else if (clazz.isInterface()) {
+            return Proxy.newProxyInstance(clazz.getClassLoader(), new java.lang.Class[] { clazz }, new java.lang.reflect.InvocationHandler() {
+                @Override
+                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                    if (Object.class.getMethod("equals", Object.class).equals(method)) {
+                        return proxy == args[0];
+                    }
+                    if (Object.class.getMethod("hashCode", Object.class).equals(method)) {
+                        return Integer.valueOf(System.identityHashCode(proxy));
+                    }
+                    if (Object.class.getMethod("toString", Object.class).equals(method)) {
+                        return "Bean " + getMockedType(proxy);
+                    }
+
+                    return null;
+                }
+
+            });
+        } else {
+            System.err.println("Unable to build an instance of class " + clazz.getName() + ", please add some code to the " + BeanValidator.class.getName() + " class to do this.");
+            return null;
+        }
+    }
+
+    public static <T> void findBooleanIsMethods(Class<T> clazz, PropertyDescriptor descriptor) throws IntrospectionException {
+        if (descriptor.getReadMethod() == null && descriptor.getPropertyType() == Boolean.class) {
+            try {
+                PropertyDescriptor pd = new PropertyDescriptor(descriptor.getName(), clazz);
+                descriptor.setReadMethod(pd.getReadMethod());
+            } catch (IntrospectionException e) {
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T, V extends T> Class<T> getMockedType(final V proxy) {
+        if (Proxy.isProxyClass(proxy.getClass())) {
+            return (Class<T>) proxy.getClass().getInterfaces()[0];
+        }
+        return (Class<T>) proxy.getClass().getSuperclass();
+    }
+}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server/pom.xml
----------------------------------------------------------------------
diff --git a/server/pom.xml b/server/pom.xml
index 3909d79..e662909 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -39,7 +39,7 @@
 
         <dependency>
             <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-query</artifactId>
+            <artifactId>kylin-server-base</artifactId>
             <version>${project.parent.version}</version>
             <exclusions>
                 <exclusion>
@@ -52,82 +52,7 @@
                 </exclusion>
             </exclusions>
         </dependency>
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-storage-hbase</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-source-hive</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-source-kafka</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-tool</artifactId>
-            <version>${project.parent.version}</version>
-        </dependency>
-
-        <!-- Test & Env -->
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-core-common</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-            <version>${project.parent.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-storage-hbase</artifactId>
-            <type>test-jar</type>
-            <scope>test</scope>
-            <version>${project.parent.version}</version>
-        </dependency>
 
-        <!-- depends on kylin-jdbc just for running jdbc test cases in server module -->
-        <dependency>
-            <groupId>org.apache.kylin</groupId>
-            <artifactId>kylin-jdbc</artifactId>
-            <version>${project.parent.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>xerces</groupId>
-            <artifactId>xercesImpl</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>xalan</groupId>
-            <artifactId>xalan</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <version>${spring.boot.version}</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.springframework.boot</groupId>
-                    <artifactId>spring-boot-starter-tomcat</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>org.slf4j</groupId>
-                    <artifactId>log4j-over-slf4j</artifactId>
-                </exclusion>
-                <exclusion>
-                    <groupId>ch.qos.logback</groupId>
-                    <artifactId>logback-classic</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-        </dependency>
         <dependency>
             <groupId>com.thetransactioncompany</groupId>
             <artifactId>cors-filter</artifactId>
@@ -141,92 +66,6 @@
         </dependency>
 
         <dependency>
-            <groupId>log4j</groupId>
-            <artifactId>log4j</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>jcl-over-slf4j</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-log4j12</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-beans</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-webmvc</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-jdbc</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-web</artifactId>
-            <version>${spring.framework.version}</version>
-            <type>jar</type>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-core</artifactId>
-            <version>${spring.framework.version}</version>
-            <type>jar</type>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-aop</artifactId>
-            <version>${spring.framework.version}</version>
-            <type>jar</type>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-test</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-
-        <!-- Spring Security -->
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-core</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-web</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-config</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-acl</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security</groupId>
-            <artifactId>spring-security-ldap</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.security.extensions</groupId>
-            <artifactId>spring-security-saml2-core</artifactId>
-            <version>${spring.framework.security.extensions.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.opensaml</groupId>
             <artifactId>opensaml</artifactId>
             <version>${opensaml.version}</version>
@@ -249,35 +88,55 @@
                 </exclusion>
             </exclusions>
         </dependency>
+
         <dependency>
-            <groupId>net.sf.ehcache</groupId>
-            <artifactId>ehcache</artifactId>
-            <version>${ehcache.version}</version>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
         </dependency>
         <dependency>
-            <groupId>cglib</groupId>
-            <artifactId>cglib</artifactId>
-            <version>2.2.2</version>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
         </dependency>
         <dependency>
-            <groupId>net.sf.supercsv</groupId>
-            <artifactId>super-csv</artifactId>
-            <version>2.1.0</version>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
         </dependency>
-
-        <!-- spring aop -->
         <dependency>
-            <groupId>org.aspectj</groupId>
-            <artifactId>aspectjrt</artifactId>
-            <version>1.6.11</version>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+        </dependency>
+        
+        <!-- Test & Env -->
+        <dependency>
+            <groupId>org.apache.kylin</groupId>
+            <artifactId>kylin-core-common</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+            <version>${project.parent.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.aspectj</groupId>
-            <artifactId>aspectjweaver</artifactId>
-            <version>1.6.11</version>
+            <groupId>org.apache.kylin</groupId>
+            <artifactId>kylin-storage-hbase</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.kylin</groupId>
+            <artifactId>kylin-server-base</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+            <version>${project.parent.version}</version>
+        </dependency>
+        
+        <!-- depends on kylin-jdbc just for running jdbc test cases in server module -->
+        <dependency>
+            <groupId>org.apache.kylin</groupId>
+            <artifactId>kylin-jdbc</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
         </dependency>
 
-        <!-- Env & Test -->
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-yarn-server-resourcemanager</artifactId>
@@ -407,6 +266,7 @@
                 </exclusion>
             </exclusions>
         </dependency>
+        
         <!-- Tomcat Env -->
         <dependency>
             <groupId>org.apache.tomcat</groupId>
@@ -426,11 +286,7 @@
             <version>7.0.69</version>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
+
         <dependency>
             <groupId>org.apache.hbase</groupId>
             <artifactId>hbase-testing-util</artifactId>
@@ -470,6 +326,11 @@
             <version>${jetty.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server/src/main/java/org/apache/kylin/rest/constant/Constant.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/constant/Constant.java b/server/src/main/java/org/apache/kylin/rest/constant/Constant.java
deleted file mode 100644
index f068e5f..0000000
--- a/server/src/main/java/org/apache/kylin/rest/constant/Constant.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-package org.apache.kylin.rest.constant;
-
-/**
- * @author xduo
- * 
- */
-public class Constant {
-
-    public final static String FakeSchemaName = "defaultSchema";
-    public final static String FakeCatalogName = "defaultCatalog";
-
-    public final static String IDENTITY_USER = "user";
-    public final static String IDENTITY_ROLE = "role";
-
-    public final static String ROLE_ADMIN = "ROLE_ADMIN";
-    public final static String ROLE_MODELER = "ROLE_MODELER";
-    public final static String ROLE_ANALYST = "ROLE_ANALYST";
-
-    public final static String ACCESS_HAS_ROLE_ADMIN = "hasRole('ROLE_ADMIN')";
-    public final static String ACCESS_HAS_ROLE_MODELER = "hasRole('ROLE_MODELER')";
-
-    public final static String ACCESS_POST_FILTER_READ = "hasRole('ROLE_ADMIN') or hasPermission(filterObject, 'READ') or hasPermission(filterObject, 'MANAGEMENT') " + "or hasPermission(filterObject, 'OPERATION') or hasPermission(filterObject, 'ADMINISTRATION')";
-
-    public final static String SERVER_MODE_QUERY = "query";
-    public final static String SERVER_MODE_JOB = "job";
-    public final static String SERVER_MODE_ALL = "all";
-
-}

http://git-wip-us.apache.org/repos/asf/kylin/blob/1a124e68/server/src/main/java/org/apache/kylin/rest/controller/AccessController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/controller/AccessController.java b/server/src/main/java/org/apache/kylin/rest/controller/AccessController.java
deleted file mode 100644
index 461aa3f..0000000
--- a/server/src/main/java/org/apache/kylin/rest/controller/AccessController.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-*/
-
-package org.apache.kylin.rest.controller;
-
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.kylin.common.persistence.AclEntity;
-import org.apache.kylin.rest.request.AccessRequest;
-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.security.acls.model.Acl;
-import org.springframework.security.acls.model.Permission;
-import org.springframework.security.acls.model.Sid;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-/**
- * @author xduo
- * 
- */
-@Controller
-@RequestMapping(value = "/access")
-public class AccessController extends BasicController {
-
-    @Autowired
-    private AccessService accessService;
-
-    /**
-     * Get access entry list of a domain object
-     * 
-     * @param uuid
-     * @return
-     * @throws IOException
-     */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.GET })
-    @ResponseBody
-    public List<AccessEntryResponse> getAccessEntities(@PathVariable String type, @PathVariable String uuid) {
-        AclEntity ae = accessService.getAclEntity(type, uuid);
-        Acl acl = accessService.getAcl(ae);
-
-        return accessService.generateAceResponses(acl);
-    }
-
-    /**
-     * Grant a new access on a domain object to a user/role
-     * 
-     * @param accessRequest
-     */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.POST })
-    @ResponseBody
-    public List<AccessEntryResponse> grant(@PathVariable String type, @PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
-        AclEntity ae = accessService.getAclEntity(type, uuid);
-        Sid sid = accessService.getSid(accessRequest.getSid(), accessRequest.isPrincipal());
-        Permission permission = AclPermissionFactory.getPermission(accessRequest.getPermission());
-        Acl acl = accessService.grant(ae, permission, sid);
-
-        return accessService.generateAceResponses(acl);
-    }
-
-    /**
-     * Update a access on a domain object
-     * 
-     * @param accessRequest
-     */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.PUT })
-    @ResponseBody
-    public List<AccessEntryResponse> update(@PathVariable String type, @PathVariable String uuid, @RequestBody AccessRequest accessRequest) {
-        AclEntity ae = accessService.getAclEntity(type, uuid);
-        Permission permission = AclPermissionFactory.getPermission(accessRequest.getPermission());
-        Acl acl = accessService.update(ae, accessRequest.getAccessEntryId(), permission);
-
-        return accessService.generateAceResponses(acl);
-    }
-
-    /**
-     * Revoke access on a domain object from a user/role
-     * 
-     * @param AccessRequest
-     */
-    @RequestMapping(value = "/{type}/{uuid}", method = { RequestMethod.DELETE })
-    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());
-
-        return accessService.generateAceResponses(acl);
-    }
-
-    /**
-     * @param accessService
-     */
-    public void setAccessService(AccessService accessService) {
-        this.accessService = accessService;
-    }
-
-}


Mime
View raw message