You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by lu...@apache.org on 2015/01/07 15:46:25 UTC
[04/51] [partial] incubator-kylin git commit: migrate repo from
github.com to apache git
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/CubeController.java b/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
new file mode 100644
index 0000000..d952ef4
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/CubeController.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.commons.lang.StringUtils;
+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.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+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.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.codahale.metrics.annotation.Metered;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.kylinolap.common.util.JsonUtil;
+import com.kylinolap.cube.CubeBuildTypeEnum;
+import com.kylinolap.cube.CubeInstance;
+import com.kylinolap.cube.CubeSegment;
+import com.kylinolap.cube.exception.CubeIntegrityException;
+import com.kylinolap.cube.project.ProjectInstance;
+import com.kylinolap.job.JobInstance;
+import com.kylinolap.job.exception.InvalidJobInstanceException;
+import com.kylinolap.job.exception.JobException;
+import com.kylinolap.metadata.model.cube.CubeDesc;
+import com.kylinolap.rest.exception.BadRequestException;
+import com.kylinolap.rest.exception.ForbiddenException;
+import com.kylinolap.rest.exception.InternalErrorException;
+import com.kylinolap.rest.exception.NotFoundException;
+import com.kylinolap.rest.request.CubeRequest;
+import com.kylinolap.rest.request.JobBuildRequest;
+import com.kylinolap.rest.response.GeneralResponse;
+import com.kylinolap.rest.response.HBaseResponse;
+import com.kylinolap.rest.service.CubeService;
+import com.kylinolap.rest.service.JobService;
+import com.kylinolap.storage.hbase.observer.CoprocessorEnabler;
+
+/**
+ * CubeController is defined as Restful API entrance for UI.
+ *
+ * @author jianliu
+ */
+@Controller
+@RequestMapping(value = "/cubes")
+public class CubeController extends BasicController {
+ private static final Logger logger = LoggerFactory.getLogger(CubeController.class);
+
+ @Autowired
+ private CubeService cubeService;
+
+ @Autowired
+ private JobService jobService;
+
+ @RequestMapping(value = "", method = { RequestMethod.GET })
+ @ResponseBody
+ @Metered(name = "listCubes")
+ public List<CubeInstance> getCubes(@RequestParam(value = "cubeName", required = false) String cubeName, @RequestParam(value = "projectName", required = false) String projectName, @RequestParam("limit") Integer limit, @RequestParam("offset") Integer offset) {
+ return cubeService.getCubes(cubeName, projectName, (null == limit) ? 20 : limit, offset);
+ }
+
+ /**
+ * Get hive SQL of the cube
+ *
+ * @param cubeName
+ * Cube Name
+ * @return
+ * @throws UnknownHostException
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{cubeName}/segs/{segmentName}/sql", method = { RequestMethod.GET })
+ @ResponseBody
+ public GeneralResponse getSql(@PathVariable String cubeName, @PathVariable String segmentName) {
+ String sql = null;
+ try {
+ sql = cubeService.getJobManager().previewFlatHiveQL(cubeName, segmentName);
+ } catch (JobException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ } catch (UnknownHostException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ GeneralResponse repsonse = new GeneralResponse();
+ repsonse.setProperty("sql", sql);
+
+ return repsonse;
+ }
+
+ /**
+ * Update cube notify list
+ *
+ * @param cubeName
+ * @param notifyList
+ * @throws IOException
+ * @throws CubeIntegrityException
+ */
+ @RequestMapping(value = "/{cubeName}/notify_list", method = { RequestMethod.PUT })
+ @ResponseBody
+ public void updateNotifyList(@PathVariable String cubeName, @RequestBody List<String> notifyList) {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ try {
+ cubeService.updateCubeNotifyList(cube, notifyList);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ }
+
+ @RequestMapping(value = "/{cubeName}/cost", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "updateCubeCost")
+ public CubeInstance updateCubeCost(@PathVariable String cubeName, @RequestParam(value = "cost") int cost) {
+ try {
+ return cubeService.updateCubeCost(cubeName, cost);
+ } catch (Exception e) {
+ String message = "Failed to update cube cost: " + cubeName + " : " + cost;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ @RequestMapping(value = "/{cubeName}/coprocessor", method = { RequestMethod.PUT })
+ @ResponseBody
+ public Map<String, Boolean> updateCubeCoprocessor(@PathVariable String cubeName, @RequestParam(value = "force") String force) {
+ try {
+ CoprocessorEnabler.updateCubeOverride(cubeName, force);
+ return CoprocessorEnabler.getCubeOverrides();
+ } catch (Exception e) {
+ String message = "Failed to update cube coprocessor: " + cubeName + " : " + force;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Force rebuild a cube's lookup table snapshot
+ *
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{cubeName}/segs/{segmentName}/refresh_lookup", method = { RequestMethod.PUT })
+ @ResponseBody
+ public CubeInstance rebuildLookupSnapshot(@PathVariable String cubeName, @PathVariable String segmentName, @RequestParam(value = "lookupTable") String lookupTable) {
+ try {
+ return cubeService.rebuildLookupSnapshot(cubeName, segmentName, lookupTable);
+ } catch (IOException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+ }
+
+ /**
+ * Send a rebuild cube job
+ *
+ * @param cubeName
+ * Cube ID
+ * @return
+ * @throws SchedulerException
+ * @throws IOException
+ * @throws InvalidJobInstanceException
+ */
+ @RequestMapping(value = "/{cubeName}/rebuild", method = { RequestMethod.PUT })
+ @ResponseBody
+ public JobInstance rebuild(@PathVariable String cubeName, @RequestBody JobBuildRequest jobBuildRequest) {
+ JobInstance jobInstance = null;
+ try {
+ CubeInstance cube = jobService.getCubeManager().getCube(cubeName);
+
+ String submitter = SecurityContextHolder.getContext().getAuthentication().getName();
+
+ String jobId = jobService.submitJob(cube, jobBuildRequest.getStartTime(), jobBuildRequest.getEndTime(), CubeBuildTypeEnum.valueOf(jobBuildRequest.getBuildType()),submitter);
+ jobInstance = jobService.getJobInstance(jobId);
+ } catch (JobException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ } catch (IOException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ } catch (InvalidJobInstanceException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ return jobInstance;
+ }
+
+ @RequestMapping(value = "/{cubeName}/disable", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "disableCube")
+ public CubeInstance disableCube(@PathVariable String cubeName) {
+ try {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ return cubeService.disableCube(cube);
+ } catch (Exception e) {
+ String message = "Failed to disable cube: " + cubeName;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ @RequestMapping(value = "/{cubeName}/purge", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "purgeCube")
+ public CubeInstance purgeCube(@PathVariable String cubeName) {
+ try {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+
+ if (cube == null) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ return cubeService.purgeCube(cube);
+ } catch (Exception e) {
+ String message = "Failed to purge cube: " + cubeName;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+
+ @RequestMapping(value = "/{cubeName}/enable", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "enableCube")
+ public CubeInstance enableCube(@PathVariable String cubeName) {
+ try {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+ if (null == cube) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ return cubeService.enableCube(cube);
+ } catch (Exception e) {
+ String message = "Failed to enable cube: " + cubeName;
+ logger.error(message, e);
+ throw new InternalErrorException(message + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ @RequestMapping(value = "/{cubeName}", method = { RequestMethod.DELETE })
+ @ResponseBody
+ @Metered(name = "deleteCube")
+ public void deleteCube(@PathVariable String cubeName) {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+ if (null == cube) {
+ throw new NotFoundException("Cube with name " + cubeName + " not found..");
+ }
+
+ try {
+ cubeService.deleteCube(cube);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException("Failed to delete cube. " + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "", method = { RequestMethod.POST })
+ @ResponseBody
+ @Metered(name = "saveCube")
+ public CubeRequest saveCubeDesc(@RequestBody CubeRequest cubeRequest) {
+ CubeDesc desc = deserializeCubeDesc(cubeRequest);
+ if (desc == null) {
+ return cubeRequest;
+ }
+
+ String name = CubeService.getCubeNameFromDesc(desc.getName());
+ if (StringUtils.isEmpty(name)) {
+ logger.info("Cube name should not be empty.");
+ throw new BadRequestException("Cube name should not be empty.");
+ }
+
+ try {
+ desc.setUuid(UUID.randomUUID().toString());
+ String projectName = (null == cubeRequest.getProject()) ? ProjectInstance.DEFAULT_PROJECT_NAME : cubeRequest.getProject();
+ cubeService.createCubeAndDesc(name, projectName, desc);
+ } catch (Exception e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException(e.getLocalizedMessage(),e);
+ }
+
+ cubeRequest.setUuid(desc.getUuid());
+ cubeRequest.setSuccessful(true);
+ return cubeRequest;
+ }
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return Table metadata array
+ * @throws JsonProcessingException
+ * @throws IOException
+ */
+ @RequestMapping(value = "", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "updateCube")
+ public CubeRequest updateCubeDesc(@RequestBody CubeRequest cubeRequest) throws JsonProcessingException {
+ CubeDesc desc = deserializeCubeDesc(cubeRequest);
+
+ if (desc == null) {
+ return cubeRequest;
+ }
+
+ // Check if the cube is editable
+ if (!cubeService.isCubeDescEditable(desc)) {
+ String error = "Cube desc " + desc.getName().toUpperCase() + " is not editable.";
+ updateRequest(cubeRequest, false, error);
+ return cubeRequest;
+ }
+
+ try {
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeRequest.getCubeName());
+ String projectName = (null == cubeRequest.getProject()) ? ProjectInstance.DEFAULT_PROJECT_NAME : cubeRequest.getProject();
+ desc = cubeService.updateCubeAndDesc(cube, desc, projectName);
+
+ } catch (AccessDeniedException accessDeniedException) {
+ throw new ForbiddenException("You don't have right to update this cube.");
+ } catch (Exception e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException("Failed to deal with the request: " + e.getMessage());
+ }
+
+ if (desc.getError().isEmpty()) {
+ cubeRequest.setSuccessful(true);
+ } else {
+ logger.warn("Cube " + desc.getName() + " fail to create because " + desc.getError());
+ updateRequest(cubeRequest, false, omitMessage(desc.getError()));
+ }
+ String descData = JsonUtil.writeValueAsIndentString(desc);
+ cubeRequest.setCubeDescData(descData);
+
+ return cubeRequest;
+ }
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return true
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{cubeName}/hbase", method = { RequestMethod.GET })
+ @ResponseBody
+ @Metered(name = "getHBaseInfo")
+ public List<HBaseResponse> getHBaseInfo(@PathVariable String cubeName) {
+ List<HBaseResponse> hbase = new ArrayList<HBaseResponse>();
+
+ CubeInstance cube = cubeService.getCubeManager().getCube(cubeName);
+ if (null == cube) {
+ throw new InternalErrorException("Cannot find cube " + cubeName);
+ }
+
+ List<CubeSegment> segments = cube.getSegments();
+
+ for (CubeSegment segment : segments) {
+ String tableName = segment.getStorageLocationIdentifier();
+ HBaseResponse hr = null;
+
+ // Get info of given table.
+ try {
+ hr = cubeService.getHTableInfo(tableName);
+ } catch (IOException e) {
+ logger.error("Failed to calcuate size of HTable \"" + tableName + "\".", e);
+ }
+
+ if (null == hr) {
+ logger.info("Failed to calcuate size of HTable \"" + tableName + "\".");
+ hr = new HBaseResponse();
+ }
+
+ hr.setTableName(tableName);
+ hbase.add(hr);
+ }
+
+ return hbase;
+ }
+
+ private CubeDesc deserializeCubeDesc(CubeRequest cubeRequest) {
+ CubeDesc desc = null;
+ try {
+ logger.debug("Saving cube " + cubeRequest.getCubeDescData());
+ desc = JsonUtil.readValue(cubeRequest.getCubeDescData(), CubeDesc.class);
+ } catch (JsonParseException e) {
+ logger.error("The cube definition is not valid.", e);
+ updateRequest(cubeRequest, false, e.getMessage());
+ } catch (JsonMappingException e) {
+ logger.error("The cube definition is not valid.", e);
+ updateRequest(cubeRequest, false, e.getMessage());
+ } catch (IOException e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException("Failed to deal with the request:"+e.getMessage(), e);
+ }
+ return desc;
+ }
+
+ /**
+ * @param error
+ * @return
+ */
+ private String omitMessage(List<String> errors) {
+ StringBuffer buffer = new StringBuffer();
+ for (Iterator<String> iterator = errors.iterator(); iterator.hasNext();) {
+ String string = (String) iterator.next();
+ buffer.append(string);
+ buffer.append("\n");
+ }
+ return buffer.toString();
+ }
+
+ private void updateRequest(CubeRequest request, boolean success, String message) {
+ request.setCubeDescData("");
+ request.setSuccessful(success);
+ request.setMessage(message);
+ }
+
+ public void setCubeService(CubeService cubeService) {
+ this.cubeService = cubeService;
+ }
+
+ public void setJobService(JobService jobService) {
+ this.jobService = jobService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/CubeDescController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/CubeDescController.java b/server/src/main/java/com/kylinolap/rest/controller/CubeDescController.java
new file mode 100644
index 0000000..173c3b6
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/CubeDescController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.kylinolap.cube.CubeInstance;
+import com.kylinolap.metadata.model.cube.CubeDesc;
+import com.kylinolap.rest.service.CubeService;
+
+/**
+ * @author xduo
+ *
+ */
+@Controller
+@RequestMapping(value = "/cube_desc")
+public class CubeDescController {
+
+ @Autowired
+ private CubeService cubeService;
+
+ /**
+ * Get detail information of the "Cube ID"
+ *
+ * @param cubeDescName
+ * Cube ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{cubeName}", method = { RequestMethod.GET })
+ @ResponseBody
+ public CubeDesc[] getCube(@PathVariable String cubeName) {
+ CubeInstance cubeInstance = cubeService.getCubeManager().getCube(cubeName);
+ CubeDesc cSchema = cubeInstance.getDescriptor();
+ if (cSchema != null) {
+ return new CubeDesc[] { cSchema };
+ } else {
+ return null;
+ }
+ }
+
+ public void setCubeService(CubeService cubeService) {
+ this.cubeService = cubeService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/JobController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/JobController.java b/server/src/main/java/com/kylinolap/rest/controller/JobController.java
new file mode 100644
index 0000000..5f26ad9
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/JobController.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.kylinolap.common.KylinConfig;
+import com.kylinolap.job.JobInstance;
+import com.kylinolap.job.JobManager;
+import com.kylinolap.job.constant.JobStatusEnum;
+import com.kylinolap.rest.constant.Constant;
+import com.kylinolap.rest.exception.InternalErrorException;
+import com.kylinolap.rest.request.JobListRequest;
+import com.kylinolap.rest.service.JobService;
+
+/**
+ * @author ysong1
+ * @author Jack
+ *
+ */
+@Controller
+@RequestMapping(value = "jobs")
+public class JobController extends BasicController implements InitializingBean {
+ private static final Logger logger = LoggerFactory.getLogger(JobController.class);
+
+ @Autowired
+ private JobService jobService;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
+ */
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ String timeZone = jobService.getKylinConfig().getTimeZone();
+ TimeZone tzone = TimeZone.getTimeZone(timeZone);
+ TimeZone.setDefault(tzone);
+
+ String serverMode = KylinConfig.getInstanceFromEnv().getServerMode();
+
+ if (Constant.SERVER_MODE_JOB.equals(serverMode.toLowerCase()) || Constant.SERVER_MODE_ALL.equals(serverMode.toLowerCase())) {
+ logger.info("Initializing Job Engine ....");
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ JobManager jobManager = null;
+ try {
+ jobManager = jobService.getJobManager();
+ jobManager.startJobEngine();
+ metricsService.registerJobMetrics(jobManager);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }).start();
+ }
+ }
+
+ /**
+ * get all cube jobs
+ *
+ * @param cubeName
+ * Cube ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "", method = { RequestMethod.GET })
+ @ResponseBody
+ public List<JobInstance> list(JobListRequest jobRequest) {
+
+ List<JobInstance> jobInstanceList = Collections.emptyList();
+ List<JobStatusEnum> statusList = new ArrayList<JobStatusEnum>();
+
+ if (null != jobRequest.getStatus()) {
+ for (int status : jobRequest.getStatus()) {
+ statusList.add(JobStatusEnum.getByCode(status));
+ }
+ }
+
+ try {
+ jobInstanceList = jobService.listAllJobs(jobRequest.getCubeName(), jobRequest.getProjectName(), statusList, jobRequest.getLimit(), jobRequest.getOffset());
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e);
+ }
+ return jobInstanceList;
+ }
+
+ /**
+ * Get a cube job
+ *
+ * @param cubeName
+ * Cube ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{jobId}", method = { RequestMethod.GET })
+ @ResponseBody
+ public JobInstance get(@PathVariable String jobId) {
+ JobInstance jobInstance = null;
+ try {
+ jobInstance = jobService.getJobInstance(jobId);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e);
+ }
+
+ return jobInstance;
+ }
+
+ /**
+ * Get a job step output
+ *
+ * @param cubeName
+ * Cube ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{jobId}/steps/{stepId}/output", method = { RequestMethod.GET })
+ @ResponseBody
+ public Map<String, String> getStepOutput(@PathVariable String jobId, @PathVariable int stepId) {
+ Map<String, String> result = new HashMap<String, String>();
+ result.put("jobId", jobId);
+ result.put("stepId", String.valueOf(stepId));
+ long start = System.currentTimeMillis();
+ String output = "";
+
+ try {
+ output = jobService.getJobManager().getJobStepOutput(jobId, stepId);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e);
+ }
+
+ result.put("cmd_output", output);
+ long end = System.currentTimeMillis();
+ logger.info("Complete fetching step " + jobId + ":" + stepId + " output in " + (end - start) + " seconds");
+ return result;
+ }
+
+ /**
+ * Resume a cube job
+ *
+ * @param String
+ * Job ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{jobId}/resume", method = { RequestMethod.PUT })
+ @ResponseBody
+ public JobInstance resume(@PathVariable String jobId) {
+ JobInstance jobInstance = null;
+ try {
+ jobInstance = jobService.getJobInstance(jobId);
+ jobService.resumeJob(jobInstance);
+ jobInstance = jobService.getJobInstance(jobId);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e);
+ }
+
+ return jobInstance;
+ }
+
+ /**
+ * Cancel a job
+ *
+ * @param String
+ * Job ID
+ * @return
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{jobId}/cancel", method = { RequestMethod.PUT })
+ @ResponseBody
+ public JobInstance cancel(@PathVariable String jobId) {
+
+ JobInstance jobInstance = null;
+ try {
+ jobInstance = jobService.getJobInstance(jobId);
+ jobService.cancelJob(jobInstance);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e);
+ }
+
+ return jobInstance;
+ }
+
+ public void setJobService(JobService jobService) {
+ this.jobService = jobService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/ProjectController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/ProjectController.java b/server/src/main/java/com/kylinolap/rest/controller/ProjectController.java
new file mode 100644
index 0000000..3b15dc9
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/ProjectController.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.codahale.metrics.annotation.Metered;
+import com.kylinolap.cube.project.ProjectInstance;
+import com.kylinolap.rest.exception.InternalErrorException;
+import com.kylinolap.rest.request.CreateProjectRequest;
+import com.kylinolap.rest.request.UpdateProjectRequest;
+import com.kylinolap.rest.service.ProjectService;
+
+/**
+ * @author xduo
+ */
+@Controller
+@RequestMapping(value = "/projects")
+public class ProjectController extends BasicController {
+ private static final Logger logger = LoggerFactory.getLogger(ProjectController.class);
+
+ @Autowired
+ private ProjectService projectService;
+
+ /**
+ * Get available project list
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "", method = { RequestMethod.GET })
+ @ResponseBody
+ public List<ProjectInstance> getProjects(@RequestParam(value = "limit", required = false) Integer limit, @RequestParam(value = "offset", required = false) Integer offset) {
+ return projectService.listAllProjects(limit, offset);
+ }
+
+ @RequestMapping(value = "", method = { RequestMethod.POST })
+ @ResponseBody
+ @Metered(name = "saveProject")
+ public ProjectInstance saveProject(@RequestBody CreateProjectRequest projectRequest) {
+ if (StringUtils.isEmpty(projectRequest.getName())) {
+ throw new InternalErrorException("A project name must be given to create a project");
+ }
+
+ ProjectInstance createdProj = null;
+ try {
+ createdProj = projectService.createProject(projectRequest);
+ } catch (Exception e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ return createdProj;
+ }
+
+ @RequestMapping(value = "", method = { RequestMethod.PUT })
+ @ResponseBody
+ @Metered(name = "updateProject")
+ public ProjectInstance updateProject(@RequestBody UpdateProjectRequest projectRequest) {
+ if (StringUtils.isEmpty(projectRequest.getFormerProjectName())) {
+ throw new InternalErrorException("A project name must be given to update a project");
+ }
+
+ ProjectInstance updatedProj = null;
+ try {
+ updatedProj = projectService.updateProject(projectRequest);
+ } catch (Exception e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ return updatedProj;
+ }
+
+ @RequestMapping(value = "/{projectName}", method = { RequestMethod.DELETE })
+ @ResponseBody
+ @Metered(name = "deleteProject")
+ public void deleteProject(@PathVariable String projectName) {
+ try {
+ projectService.deleteProject(projectName);
+ } catch (Exception e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException("Failed to delete project. " + " Caused by: " + e.getMessage(), e);
+ }
+ }
+
+ public void setProjectService(ProjectService projectService) {
+ this.projectService = projectService;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/QueryController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/QueryController.java b/server/src/main/java/com/kylinolap/rest/controller/QueryController.java
new file mode 100644
index 0000000..e080aff
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/QueryController.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed under the <dependency>
+ <groupId>com.ryantenney.metrics</groupId>
+ <artifactId>metrics-spring</artifactId>
+ <version>3.0.0</version>
+</dependency>che 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
+import org.apache.commons.io.IOUtils;
+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.core.context.SecurityContextHolder;
+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;
+import org.supercsv.io.CsvListWriter;
+import org.supercsv.io.ICsvListWriter;
+import org.supercsv.prefs.CsvPreference;
+
+import com.codahale.metrics.annotation.Timed;
+import com.kylinolap.common.KylinConfig;
+import com.kylinolap.cube.CubeInstance;
+import com.kylinolap.rest.constant.Constant;
+import com.kylinolap.rest.exception.ForbiddenException;
+import com.kylinolap.rest.exception.InternalErrorException;
+import com.kylinolap.rest.model.Query;
+import com.kylinolap.rest.model.SelectedColumnMeta;
+import com.kylinolap.rest.model.TableMeta;
+import com.kylinolap.rest.request.MetaRequest;
+import com.kylinolap.rest.request.PrepareSqlRequest;
+import com.kylinolap.rest.request.SQLRequest;
+import com.kylinolap.rest.request.SaveSqlRequest;
+import com.kylinolap.rest.response.SQLResponse;
+import com.kylinolap.rest.service.QueryService;
+import com.kylinolap.rest.util.QueryUtil;
+
+/**
+ * Handle query requests.
+ *
+ * @author xduo
+ */
+@Controller
+public class QueryController extends BasicController {
+
+ private static final Logger logger = LoggerFactory.getLogger(QueryController.class);
+
+ public static final String SUCCESS_QUERY_CACHE = "SuccessQueryCache";
+ public static final String EXCEPTION_QUERY_CACHE = "ExceptionQueryCache";
+
+ @Autowired
+ private QueryService queryService;
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @RequestMapping(value = "/query", method = RequestMethod.POST)
+ @ResponseBody
+ @Timed(name = "query")
+ public SQLResponse query(@RequestBody SQLRequest sqlRequest) {
+ long startTimestamp = System.currentTimeMillis();
+
+ SQLResponse response = doQuery(sqlRequest);
+ response.setDuration(System.currentTimeMillis() - startTimestamp);
+
+ queryService.logQuery(sqlRequest, response, new Date(startTimestamp), new Date(System.currentTimeMillis()));
+
+ return response;
+ }
+
+ @RequestMapping(value = "/query/prestate", method = RequestMethod.POST, produces = "application/json")
+ @ResponseBody
+ @Timed(name = "query")
+ public SQLResponse prepareQuery(@RequestBody PrepareSqlRequest sqlRequest) {
+ long startTimestamp = System.currentTimeMillis();
+
+ SQLResponse response = doQuery(sqlRequest);
+ response.setDuration(System.currentTimeMillis() - startTimestamp);
+
+ queryService.logQuery(sqlRequest, response, new Date(startTimestamp), new Date(System.currentTimeMillis()));
+
+ if (response.getIsException()) {
+ String errorMsg = response.getExceptionMessage();
+ throw new InternalErrorException(QueryUtil.makeErrorMsgUserFriendly(errorMsg));
+ }
+
+ return response;
+ }
+
+ @RequestMapping(value = "/saved_queries", method = RequestMethod.POST)
+ @ResponseBody
+ @Timed(name = "saveQuery")
+ public void saveQuery(@RequestBody SaveSqlRequest sqlRequest) throws IOException {
+ String creator = SecurityContextHolder.getContext().getAuthentication().getName();
+ Query newQuery = new Query(sqlRequest.getName(), sqlRequest.getProject(), sqlRequest.getSql(), sqlRequest.getDescription());
+
+ queryService.saveQuery(creator, newQuery);
+ }
+
+ @RequestMapping(value = "/saved_queries/{id}", method = RequestMethod.DELETE)
+ @ResponseBody
+ @Timed(name = "removeQuery")
+ public void removeQuery(@PathVariable String id) throws IOException {
+ String creator = SecurityContextHolder.getContext().getAuthentication().getName();
+ queryService.removeQuery(creator, id);
+ }
+
+ @RequestMapping(value = "/saved_queries", method = RequestMethod.GET)
+ @ResponseBody
+ @Timed(name = "getQueries")
+ public List<Query> getQueries() throws IOException {
+ String creator = SecurityContextHolder.getContext().getAuthentication().getName();
+ return queryService.getQueries(creator);
+ }
+
+ @RequestMapping(value = "/query/format/{format}", method = RequestMethod.GET)
+ @ResponseBody
+ @Timed(name = "downloadResult")
+ public void downloadQueryResult(@PathVariable String format, SQLRequest sqlRequest, HttpServletResponse response) {
+ SQLResponse result = doQuery(sqlRequest);
+ response.setContentType("text/" + format + ";charset=utf-8");
+ response.setHeader("Content-Disposition", "attachment; filename=\"result." + format + "\"");
+ ICsvListWriter csvWriter = null;
+
+ try {
+ csvWriter = new CsvListWriter(response.getWriter(), CsvPreference.STANDARD_PREFERENCE);
+
+ List<String> headerList = new ArrayList<String>();
+
+ for (SelectedColumnMeta column : result.getColumnMetas()) {
+ headerList.add(column.getName());
+ }
+
+ String[] headers = new String[headerList.size()];
+ csvWriter.writeHeader(headerList.toArray(headers));
+
+ for (List<String> row : result.getResults()) {
+ csvWriter.write(row);
+ }
+ } catch (IOException e) {
+ logger.error("", e);
+ } finally {
+ IOUtils.closeQuietly(csvWriter);
+ }
+ }
+
+ @RequestMapping(value = "/tables_and_columns", method = RequestMethod.GET)
+ @ResponseBody
+ public List<TableMeta> getMetadata(MetaRequest metaRequest) {
+ try {
+ return queryService.getMetadata(metaRequest.getProject());
+ } catch (SQLException e) {
+ logger.error(e.getLocalizedMessage(), e);
+ throw new InternalErrorException(e.getLocalizedMessage(), e);
+ }
+ }
+
+ private SQLResponse doQuery(SQLRequest sqlRequest) {
+ String sql = sqlRequest.getSql();
+ String project = sqlRequest.getProject();
+ logger.info("Using project: " + project);
+ logger.info("The original query: " + sql);
+
+ String serverMode = KylinConfig.getInstanceFromEnv().getServerMode();
+ if (!(Constant.SERVER_MODE_QUERY.equals(serverMode.toLowerCase()) || Constant.SERVER_MODE_ALL.equals(serverMode.toLowerCase()))) {
+ throw new InternalErrorException("Query is not allowed in " + serverMode + " mode.");
+ }
+
+ if (sql.toLowerCase().contains("select")) {
+ SQLResponse sqlResponse = searchQueryInCache(sqlRequest);
+ try {
+ if (null == sqlResponse) {
+ sqlResponse = queryService.query(sqlRequest);
+
+ long durationThreshold = KylinConfig.getInstanceFromEnv().getQueryDurationCacheThreshold();
+ long scancountThreshold = KylinConfig.getInstanceFromEnv().getQueryScanCountCacheThreshold();
+ if (!sqlResponse.getIsException() && (sqlResponse.getDuration() > durationThreshold || sqlResponse.getTotalScanCount() > scancountThreshold)) {
+ cacheManager.getCache(SUCCESS_QUERY_CACHE).put(new Element(sqlRequest, sqlResponse));
+ }
+ }
+
+ checkQueryAuth(sqlResponse);
+
+ return sqlResponse;
+ } catch (AccessDeniedException ade) {
+ // Access exception is bind with each user, it will not be
+ // cached.
+ logger.error("Exception when execute sql", ade);
+ throw new ForbiddenException(ade.getLocalizedMessage());
+ } catch (Exception e) {
+ SQLResponse exceptionRes = new SQLResponse(null, null, 0, true, e.getMessage());
+ Cache exceptionCache = cacheManager.getCache(EXCEPTION_QUERY_CACHE);
+ exceptionCache.put(new Element(sqlRequest, exceptionRes));
+
+ logger.error("Exception when execute sql", e);
+ throw new InternalErrorException(QueryUtil.makeErrorMsgUserFriendly(e.getLocalizedMessage()));
+ }
+ } else {
+ logger.debug("Directly return expection as not supported");
+ throw new InternalErrorException(QueryUtil.makeErrorMsgUserFriendly("Not Supported SQL."));
+ }
+ }
+
+ private SQLResponse searchQueryInCache(SQLRequest sqlRequest) {
+ SQLResponse response = null;
+ Cache exceptionCache = cacheManager.getCache(EXCEPTION_QUERY_CACHE);
+ Cache queryCache = cacheManager.getCache(SUCCESS_QUERY_CACHE);
+
+ if (KylinConfig.getInstanceFromEnv().isQueryCacheEnabled() && null != exceptionCache.get(sqlRequest)) {
+ Element element = exceptionCache.get(sqlRequest);
+ response = (SQLResponse) element.getObjectValue();
+ response.setHitCache(true);
+ } else if (KylinConfig.getInstanceFromEnv().isQueryCacheEnabled() && null != queryCache.get(sqlRequest)) {
+ Element element = queryCache.get(sqlRequest);
+ response = (SQLResponse) element.getObjectValue();
+ response.setHitCache(true);
+ }
+
+ return response;
+ }
+
+ private void checkQueryAuth(SQLResponse sqlResponse) throws AccessDeniedException {
+ if (!sqlResponse.getIsException() && KylinConfig.getInstanceFromEnv().isQuerySecureEnabled()) {
+ CubeInstance cubeInstance = this.queryService.getCubeManager().getCube(sqlResponse.getCube());
+ queryService.checkAuthorization(cubeInstance);
+ }
+ }
+
+ public void setQueryService(QueryService queryService) {
+ this.queryService = queryService;
+ }
+
+ public void setCacheManager(CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/TableController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/TableController.java b/server/src/main/java/com/kylinolap/rest/controller/TableController.java
new file mode 100644
index 0000000..0ffdfe5
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/TableController.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.codahale.metrics.annotation.Metered;
+import com.kylinolap.metadata.MetadataConstances;
+import com.kylinolap.metadata.model.schema.ColumnDesc;
+import com.kylinolap.metadata.model.schema.TableDesc;
+import com.kylinolap.rest.exception.InternalErrorException;
+import com.kylinolap.rest.request.CardinalityRequest;
+import com.kylinolap.rest.response.TableDescResponse;
+import com.kylinolap.rest.service.CubeService;
+
+/**
+ * @author xduo
+ *
+ */
+@Controller
+@RequestMapping(value = "/tables")
+public class TableController extends BasicController {
+ private static final Logger logger = LoggerFactory.getLogger(TableController.class);
+
+ @Autowired
+ private CubeService cubeMgmtService;
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "", method = { RequestMethod.GET })
+ @ResponseBody
+ @Metered(name = "listSourceTables")
+ public List<TableDesc> getHiveTables(@RequestParam(value = "ext", required = false) boolean withExt,@RequestParam(value = "project", required = false) String project ) {
+ long start = System.currentTimeMillis();
+ List<TableDesc> tables = null;
+ try {
+ tables = cubeMgmtService.getProjectManager().listDefinedTablesInProject(project);
+ } catch (IOException e) {
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException(e.getLocalizedMessage());
+ }
+
+ if (withExt) {
+ tables = cloneTableDesc(tables);
+ }
+ long end = System.currentTimeMillis();
+ logger.info("Return all table metadata in " + (end - start) + " seconds");
+
+ return tables;
+ }
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{tableName}", method = { RequestMethod.GET })
+ @ResponseBody
+ public TableDesc getHiveTable(@PathVariable String tableName) {
+ return cubeMgmtService.getMetadataManager().getTableDesc(tableName);
+ }
+
+ /**
+ * Get available table list of the input database
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{tableName}/exd-map", method = { RequestMethod.GET })
+ @ResponseBody
+ public Map<String, String> getHiveTableExd(@PathVariable String tableName) {
+ Map<String, String> tableExd = cubeMgmtService.getMetadataManager().getTableDescExd(tableName);
+ return tableExd;
+ }
+
+ @RequestMapping(value = "/reload", method = { RequestMethod.PUT })
+ @ResponseBody
+ public String reloadSourceTable() {
+ cubeMgmtService.getMetadataManager().reload();
+ return "ok";
+ }
+
+ @RequestMapping(value = "/{tables}/{project}", method = { RequestMethod.POST })
+ @ResponseBody
+ public Map<String, String[]> loadHiveTable(@PathVariable String tables,@PathVariable String project){
+ Map<String, String[]> result = new HashMap<String, String[]>();
+ try{
+ String[] loadedTables = cubeMgmtService.reloadHiveTable(tables);
+
+ String inputTables[] = tables.split(",");
+ ArrayList<String> unloadedTables = new ArrayList<String>();
+ for (String inputTable : inputTables) {
+ boolean tableLoaded = false;
+ for (String loadedTable : loadedTables) {
+ int cut = loadedTable.indexOf('.');
+ String tableName = cut >= 0 ? loadedTable.substring(cut + 1).trim() : loadedTable.trim();
+ if (inputTable.trim().toUpperCase().equals(tableName)||inputTable.trim().toUpperCase().equals(loadedTable)) {
+ tableLoaded = true;
+ break;
+ }
+ }
+ if(!tableLoaded){
+ unloadedTables.add(inputTable);
+ }
+ }
+
+ cubeMgmtService.syncTableToProject(loadedTables, project);
+ result.put("result.loaded", loadedTables);
+ result.put("result.unloaded",unloadedTables.toArray(new String[unloadedTables.size()]) );
+
+ }catch(IOException e){
+ logger.error("Failed to deal with the request.", e);
+ throw new InternalErrorException("Failed to load table,Please check the table name.");
+ }
+ return result;
+ }
+
+ /**
+ * Regenerate table cardinality
+ *
+ * @return Table metadata array
+ * @throws IOException
+ */
+ @RequestMapping(value = "/{tableNames}/cardinality", method = { RequestMethod.PUT })
+ @ResponseBody
+ public CardinalityRequest generateCardinality(@PathVariable String tableNames, @RequestBody CardinalityRequest request) {
+ String[] tables = tableNames.split(",");
+ for (String table : tables) {
+ cubeMgmtService.generateCardinality(table.trim(), request.getFormat(), request.getDelimiter());
+ }
+ return request;
+ }
+
+ /**
+ * @param tables
+ * @return
+ */
+ private List<TableDesc> cloneTableDesc(List<TableDesc> tables) {
+ if (null == tables) {
+ return Collections.emptyList();
+ }
+
+ List<TableDesc> descs = new ArrayList<TableDesc>();
+ Iterator<TableDesc> it = tables.iterator();
+ while (it.hasNext()) {
+ TableDesc table = it.next();
+ Map<String, String> exd = cubeMgmtService.getMetadataManager().getTableDescExd(table.getName());
+ if (exd == null) {
+ descs.add(table);
+ } else {
+ // Clone TableDesc
+ TableDescResponse rtableDesc = new TableDescResponse(table);
+ rtableDesc.setDescExd(exd);
+ if (exd.containsKey(MetadataConstances.TABLE_EXD_CARDINALITY)) {
+ Map<String, Long> cardinality = new HashMap<String, Long>();
+ String scard = exd.get(MetadataConstances.TABLE_EXD_CARDINALITY);
+ if (!StringUtils.isEmpty(scard)) {
+ String[] cards = StringUtils.split(scard, ",");
+ ColumnDesc[] cdescs = rtableDesc.getColumns();
+ for (int i = 0; i < cdescs.length; i++) {
+ ColumnDesc columnDesc = cdescs[i];
+ if (cards.length > i) {
+ cardinality.put(columnDesc.getName(), Long.parseLong(cards[i]));
+ } else {
+ logger.error("The result cardinality is not identical with hive table metadata, cardinaly : " + scard + " column array length: " + cdescs.length);
+ break;
+ }
+ }
+ rtableDesc.setCardinality(cardinality);
+ }
+ }
+ descs.add(rtableDesc);
+ }
+ }
+ return descs;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/controller/UserController.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/controller/UserController.java b/server/src/main/java/com/kylinolap/rest/controller/UserController.java
new file mode 100644
index 0000000..25b6bb2
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/controller/UserController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import com.kylinolap.rest.service.UserService;
+
+/**
+ * Handle user authentication request to protected kylin rest resources by
+ * spring security.
+ *
+ * @author xduo
+ *
+ */
+@Controller
+@RequestMapping(value = "/user")
+public class UserController {
+
+ @Autowired
+ UserService userService;
+
+ @RequestMapping(value = "/authentication", method = RequestMethod.POST, produces = "application/json")
+ public UserDetails authenticate() {
+ return authenticatedUser();
+ }
+
+ @RequestMapping(value = "/authentication", method = RequestMethod.GET, produces = "application/json")
+ public UserDetails authenticatedUser() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+ if (authentication == null || !(authentication.getPrincipal() instanceof UserDetails)) {
+ return null;
+ }
+
+ return (UserDetails) authentication.getPrincipal();
+ }
+
+ @RequestMapping(value = "/authentication/authorities", method = RequestMethod.GET, produces = "application/json")
+ public List<String> getAuthorities() {
+ return userService.getUserAuthorities();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/exception/BadRequestException.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/exception/BadRequestException.java b/server/src/main/java/com/kylinolap/rest/exception/BadRequestException.java
new file mode 100644
index 0000000..0bf31c9
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/exception/BadRequestException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+
+/**
+ * @author xduo
+ *
+ */
+@ResponseStatus(value = HttpStatus.BAD_REQUEST)
+public class BadRequestException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6798154278095441848L;
+
+ public BadRequestException(String s) {
+ super(s);
+ }
+
+ /**
+ *
+ */
+ public BadRequestException() {
+ super();
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public BadRequestException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+ /**
+ * @param arg0
+ */
+ public BadRequestException(Throwable arg0) {
+ super(arg0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/exception/ForbiddenException.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/exception/ForbiddenException.java b/server/src/main/java/com/kylinolap/rest/exception/ForbiddenException.java
new file mode 100644
index 0000000..25e53a3
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/exception/ForbiddenException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * @author xduo
+ *
+ */
+@ResponseStatus(value = HttpStatus.FORBIDDEN)
+public class ForbiddenException extends RuntimeException {
+
+ private static final long serialVersionUID = 2741885728370162194L;
+
+ public ForbiddenException() {
+ super();
+ }
+
+ public ForbiddenException(String message) {
+ super(message);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/exception/InternalErrorException.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/exception/InternalErrorException.java b/server/src/main/java/com/kylinolap/rest/exception/InternalErrorException.java
new file mode 100644
index 0000000..4198fda
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/exception/InternalErrorException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Class to wrap backend exception
+ *
+ * @author jianliu
+ *
+ */
+@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
+public class InternalErrorException extends RuntimeException {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -6798154278095441848L;
+
+ public InternalErrorException(String s) {
+ super(s);
+ }
+
+ /**
+ *
+ */
+ public InternalErrorException() {
+ super();
+ }
+
+ /**
+ * @param arg0
+ * @param arg1
+ */
+ public InternalErrorException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ }
+
+ /**
+ * @param arg0
+ */
+ public InternalErrorException(Throwable arg0) {
+ super(arg0);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/exception/NotFoundException.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/exception/NotFoundException.java b/server/src/main/java/com/kylinolap/rest/exception/NotFoundException.java
new file mode 100644
index 0000000..ede21bf
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/exception/NotFoundException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * @author xduo
+ *
+ */
+@ResponseStatus(value = HttpStatus.NOT_FOUND)
+public class NotFoundException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public NotFoundException(String s) {
+ super(s);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java b/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
new file mode 100644
index 0000000..2b763dd
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/interceptor/CacheIntercaptor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.interceptor;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+
+import com.kylinolap.common.restclient.Broadcaster;
+
+/**
+ * @author xduo
+ *
+ */
+@Aspect
+@Component("cacheIntercaptor")
+public class CacheIntercaptor {
+
+ @After("execution(public * com.kylinolap.rest.controller.CubeController.*(..)) || execution(public * com.kylinolap.rest.controller.ProjectController.*(..))")
+ public void flush(JoinPoint joinPoint) {
+ String methodName = joinPoint.getSignature().getName();
+
+ if (methodName.matches("(update|create|save|disable|enable|delete|drop|purge)")) {
+ Broadcaster.flush();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/metrics/JobMetrics.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/metrics/JobMetrics.java b/server/src/main/java/com/kylinolap/rest/metrics/JobMetrics.java
new file mode 100644
index 0000000..4fde585
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/metrics/JobMetrics.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricSet;
+import com.kylinolap.job.JobManager;
+
+/**
+ * @author xduo
+ *
+ */
+public class JobMetrics implements MetricSet {
+
+ private JobManager jobManager;
+
+ static class JobMetricsHolder {
+ static final JobMetrics INSTANCE = new JobMetrics();
+ }
+
+ public static JobMetrics getInstance() {
+ return JobMetricsHolder.INSTANCE;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.codahale.metrics.MetricSet#getMetrics()
+ */
+ @Override
+ public Map<String, Metric> getMetrics() {
+ Map<String, Metric> metricSet = new HashMap<String, Metric>();
+
+ metricSet.put("PercentileJobStepDuration", new Gauge<Double>() {
+ @Override
+ public Double getValue() {
+ return jobManager.getPercentileJobStepDuration(95);
+ }
+ });
+
+ metricSet.put("scheduledJobs", new Gauge<Integer>() {
+ @Override
+ public Integer getValue() {
+ return jobManager.getScheduledJobsSzie();
+ }
+ });
+
+ metricSet.put("EngineThreadPool", new Gauge<Integer>() {
+ @Override
+ public Integer getValue() {
+ return jobManager.getEngineThreadPoolSize();
+ }
+ });
+
+ metricSet.put("MaxJobStep", new Gauge<Double>() {
+ @Override
+ public Double getValue() {
+ return jobManager.getMaxJobStepDuration();
+ }
+ });
+
+ metricSet.put("MinJobStep", new Gauge<Double>() {
+ @Override
+ public Double getValue() {
+ return jobManager.getMinJobStepDuration();
+ }
+ });
+
+ metricSet.put("IdleSlots", new Gauge<Integer>() {
+ @Override
+ public Integer getValue() {
+ return jobManager.getNumberOfIdleSlots();
+ }
+ });
+
+ metricSet.put("JobStepsExecuted", new Gauge<Integer>() {
+ @Override
+ public Integer getValue() {
+ return jobManager.getNumberOfJobStepsExecuted();
+ }
+ });
+
+ metricSet.put("JobStepsRunning", new Gauge<Integer>() {
+ @Override
+ public Integer getValue() {
+ return jobManager.getNumberOfJobStepsRunning();
+ }
+ });
+
+ return metricSet;
+ }
+
+ public void setJobManager(JobManager jobManager) {
+ this.jobManager = jobManager;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/metrics/KylinInstrumentedFilterContextListener.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/metrics/KylinInstrumentedFilterContextListener.java b/server/src/main/java/com/kylinolap/rest/metrics/KylinInstrumentedFilterContextListener.java
new file mode 100644
index 0000000..e54db3e
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/metrics/KylinInstrumentedFilterContextListener.java
@@ -0,0 +1,39 @@
+package com.kylinolap.rest.metrics;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.servlet.InstrumentedFilterContextListener;
+
+public class KylinInstrumentedFilterContextListener implements ServletContextListener {
+
+ @Autowired
+ private MetricRegistry metricRegistry;
+
+ private final InnerKylinInstrumentedFilterContextListener innerKylinInstrumentedFilterContextListener = new InnerKylinInstrumentedFilterContextListener();
+
+ @Override
+ public void contextInitialized(ServletContextEvent event) {
+ WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext()).getAutowireCapableBeanFactory().autowireBean(this);
+
+ innerKylinInstrumentedFilterContextListener.contextInitialized(event);
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent event) {
+ }
+
+ class InnerKylinInstrumentedFilterContextListener extends InstrumentedFilterContextListener {
+
+ @Override
+ protected MetricRegistry getMetricRegistry() {
+ return metricRegistry;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/metrics/QueryMetrics.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/metrics/QueryMetrics.java b/server/src/main/java/com/kylinolap/rest/metrics/QueryMetrics.java
new file mode 100644
index 0000000..0748314
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/metrics/QueryMetrics.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.metrics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricSet;
+
+/**
+ * @author xduo
+ *
+ */
+public class QueryMetrics implements MetricSet {
+
+ private Map<String, Float> metrics = new HashMap<String, Float>();
+
+ private QueryMetrics() {
+ // register query metrics
+ this.increase("duration", (float) 0);
+ this.increase("totalScanCount", (float) 0);
+ this.increase("count", (float) 0);
+ }
+
+ static class QueryMetricsHolder {
+ static final QueryMetrics INSTANCE = new QueryMetrics();
+ }
+
+ public static QueryMetrics getInstance() {
+ return QueryMetricsHolder.INSTANCE;
+ }
+
+ public synchronized void increase(String key, Float value) {
+ if (metrics.containsKey(key)) {
+ metrics.put(key, metrics.get(key) + value);
+ } else {
+ metrics.put(key, value);
+ }
+ }
+
+ public synchronized Float getAndReset(String key) {
+ float value = metrics.get(key);
+ metrics.put(key, (float) 0);
+
+ return value;
+ }
+
+ public synchronized Map<String, Metric> getMetrics() {
+ Map<String, Metric> metricSet = new HashMap<String, Metric>();
+
+ for (final String key : metrics.keySet()) {
+ metricSet.put(key, new Gauge<Float>() {
+ @Override
+ public Float getValue() {
+ float value = getAndReset(key);
+
+ return value;
+ }
+ });
+ }
+
+ return metricSet;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/model/ColumnMeta.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/model/ColumnMeta.java b/server/src/main/java/com/kylinolap/rest/model/ColumnMeta.java
new file mode 100644
index 0000000..731684a
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/model/ColumnMeta.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2013-2014 eBay Software Foundation
+ *
+ * Licensed 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 com.kylinolap.rest.model;
+
+import java.io.Serializable;
+
+/**
+ * Created by lukhan on 2/27/14.
+ */
+public class ColumnMeta implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private String TABLE_CAT;
+ private String TABLE_SCHEM;
+ private String TABLE_NAME;
+ private String COLUMN_NAME;
+ private int DATA_TYPE;
+ private String TYPE_NAME;
+ private int COLUMN_SIZE;
+ private int BUFFER_LENGTH;
+ private int DECIMAL_DIGITS;
+ private int NUM_PREC_RADIX;
+ private int NULLABLE;
+ private String REMARKS;
+ private String COLUMN_DEF;
+ private int SQL_DATA_TYPE;
+ private int SQL_DATETIME_SUB;
+ private int CHAR_OCTET_LENGTH;
+ private int ORDINAL_POSITION;
+ private String IS_NULLABLE;
+ private String SCOPE_CATLOG;
+ private String SCOPE_SCHEMA;
+ private String SCOPE_TABLE;
+ private short SOURCE_DATA_TYPE;
+ private String IS_AUTOINCREMENT;
+
+ public ColumnMeta() {
+ }
+
+ public ColumnMeta(String tABLE_CAT, String tABLE_SCHEM, String tABLE_NAME, String cOLUMN_NAME, int dATA_TYPE, String tYPE_NAME, int cOLUMN_SIZE, int bUFFER_LENGTH, int dECIMAL_DIGITS, int nUM_PREC_RADIX, int nULLABLE, String rEMARKS, String cOLUMN_DEF, int sQL_DATA_TYPE, int sQL_DATETIME_SUB, int cHAR_OCTET_LENGTH, int oRDINAL_POSITION, String iS_NULLABLE, String sCOPE_CATLOG, String sCOPE_SCHEMA, String sCOPE_TABLE, short sOURCE_DATA_TYPE, String iS_AUTOINCREMENT) {
+ super();
+ TABLE_CAT = tABLE_CAT;
+ TABLE_SCHEM = tABLE_SCHEM;
+ TABLE_NAME = tABLE_NAME;
+ COLUMN_NAME = cOLUMN_NAME;
+ DATA_TYPE = dATA_TYPE;
+ TYPE_NAME = tYPE_NAME;
+ COLUMN_SIZE = cOLUMN_SIZE;
+ BUFFER_LENGTH = bUFFER_LENGTH;
+ DECIMAL_DIGITS = dECIMAL_DIGITS;
+ NUM_PREC_RADIX = nUM_PREC_RADIX;
+ NULLABLE = nULLABLE;
+ REMARKS = rEMARKS;
+ COLUMN_DEF = cOLUMN_DEF;
+ SQL_DATA_TYPE = sQL_DATA_TYPE;
+ SQL_DATETIME_SUB = sQL_DATETIME_SUB;
+ CHAR_OCTET_LENGTH = cHAR_OCTET_LENGTH;
+ ORDINAL_POSITION = oRDINAL_POSITION;
+ IS_NULLABLE = iS_NULLABLE;
+ SCOPE_CATLOG = sCOPE_CATLOG;
+ SCOPE_SCHEMA = sCOPE_SCHEMA;
+ SCOPE_TABLE = sCOPE_TABLE;
+ SOURCE_DATA_TYPE = sOURCE_DATA_TYPE;
+ IS_AUTOINCREMENT = iS_AUTOINCREMENT;
+ }
+
+ public String getTABLE_CAT() {
+ return TABLE_CAT;
+ }
+
+ public void setTABLE_CAT(String tABLE_CAT) {
+ TABLE_CAT = tABLE_CAT;
+ }
+
+ public String getTABLE_SCHEM() {
+ return TABLE_SCHEM;
+ }
+
+ public void setTABLE_SCHEM(String tABLE_SCHEM) {
+ TABLE_SCHEM = tABLE_SCHEM;
+ }
+
+ public String getTABLE_NAME() {
+ return TABLE_NAME;
+ }
+
+ public void setTABLE_NAME(String tABLE_NAME) {
+ TABLE_NAME = tABLE_NAME;
+ }
+
+ public String getCOLUMN_NAME() {
+ return COLUMN_NAME;
+ }
+
+ public void setCOLUMN_NAME(String cOLUMN_NAME) {
+ COLUMN_NAME = cOLUMN_NAME;
+ }
+
+ public int getDATA_TYPE() {
+ return DATA_TYPE;
+ }
+
+ public void setDATA_TYPE(int dATA_TYPE) {
+ DATA_TYPE = dATA_TYPE;
+ }
+
+ public String getTYPE_NAME() {
+ return TYPE_NAME;
+ }
+
+ public void setTYPE_NAME(String tYPE_NAME) {
+ TYPE_NAME = tYPE_NAME;
+ }
+
+ public int getCOLUMN_SIZE() {
+ return COLUMN_SIZE;
+ }
+
+ public void setCOLUMN_SIZE(int cOLUMN_SIZE) {
+ COLUMN_SIZE = cOLUMN_SIZE;
+ }
+
+ public int getBUFFER_LENGTH() {
+ return BUFFER_LENGTH;
+ }
+
+ public void setBUFFER_LENGTH(int bUFFER_LENGTH) {
+ BUFFER_LENGTH = bUFFER_LENGTH;
+ }
+
+ public int getDECIMAL_DIGITS() {
+ return DECIMAL_DIGITS;
+ }
+
+ public void setDECIMAL_DIGITS(int dECIMAL_DIGITS) {
+ DECIMAL_DIGITS = dECIMAL_DIGITS;
+ }
+
+ public int getNUM_PREC_RADIX() {
+ return NUM_PREC_RADIX;
+ }
+
+ public void setNUM_PREC_RADIX(int nUM_PREC_RADIX) {
+ NUM_PREC_RADIX = nUM_PREC_RADIX;
+ }
+
+ public int getNULLABLE() {
+ return NULLABLE;
+ }
+
+ public void setNULLABLE(int nULLABLE) {
+ NULLABLE = nULLABLE;
+ }
+
+ public String getREMARKS() {
+ return REMARKS;
+ }
+
+ public void setREMARKS(String rEMARKS) {
+ REMARKS = rEMARKS;
+ }
+
+ public String getCOLUMN_DEF() {
+ return COLUMN_DEF;
+ }
+
+ public void setCOLUMN_DEF(String cOLUMN_DEF) {
+ COLUMN_DEF = cOLUMN_DEF;
+ }
+
+ public int getSQL_DATA_TYPE() {
+ return SQL_DATA_TYPE;
+ }
+
+ public void setSQL_DATA_TYPE(int sQL_DATA_TYPE) {
+ SQL_DATA_TYPE = sQL_DATA_TYPE;
+ }
+
+ public int getSQL_DATETIME_SUB() {
+ return SQL_DATETIME_SUB;
+ }
+
+ public void setSQL_DATETIME_SUB(int sQL_DATETIME_SUB) {
+ SQL_DATETIME_SUB = sQL_DATETIME_SUB;
+ }
+
+ public int getCHAR_OCTET_LENGTH() {
+ return CHAR_OCTET_LENGTH;
+ }
+
+ public void setCHAR_OCTET_LENGTH(int cHAR_OCTET_LENGTH) {
+ CHAR_OCTET_LENGTH = cHAR_OCTET_LENGTH;
+ }
+
+ public int getORDINAL_POSITION() {
+ return ORDINAL_POSITION;
+ }
+
+ public void setORDINAL_POSITION(int oRDINAL_POSITION) {
+ ORDINAL_POSITION = oRDINAL_POSITION;
+ }
+
+ public String getIS_NULLABLE() {
+ return IS_NULLABLE;
+ }
+
+ public void setIS_NULLABLE(String iS_NULLABLE) {
+ IS_NULLABLE = iS_NULLABLE;
+ }
+
+ public String getSCOPE_CATLOG() {
+ return SCOPE_CATLOG;
+ }
+
+ public void setSCOPE_CATLOG(String sCOPE_CATLOG) {
+ SCOPE_CATLOG = sCOPE_CATLOG;
+ }
+
+ public String getSCOPE_SCHEMA() {
+ return SCOPE_SCHEMA;
+ }
+
+ public void setSCOPE_SCHEMA(String sCOPE_SCHEMA) {
+ SCOPE_SCHEMA = sCOPE_SCHEMA;
+ }
+
+ public String getSCOPE_TABLE() {
+ return SCOPE_TABLE;
+ }
+
+ public void setSCOPE_TABLE(String sCOPE_TABLE) {
+ SCOPE_TABLE = sCOPE_TABLE;
+ }
+
+ public short getSOURCE_DATA_TYPE() {
+ return SOURCE_DATA_TYPE;
+ }
+
+ public void setSOURCE_DATA_TYPE(short sOURCE_DATA_TYPE) {
+ SOURCE_DATA_TYPE = sOURCE_DATA_TYPE;
+ }
+
+ public String getIS_AUTOINCREMENT() {
+ return IS_AUTOINCREMENT;
+ }
+
+ public void setIS_AUTOINCREMENT(String iS_AUTOINCREMENT) {
+ this.IS_AUTOINCREMENT = iS_AUTOINCREMENT;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-kylin/blob/4b631f92/server/src/main/java/com/kylinolap/rest/model/Query.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/com/kylinolap/rest/model/Query.java b/server/src/main/java/com/kylinolap/rest/model/Query.java
new file mode 100644
index 0000000..9a1a7cf
--- /dev/null
+++ b/server/src/main/java/com/kylinolap/rest/model/Query.java
@@ -0,0 +1,102 @@
+package com.kylinolap.rest.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown=true)
+public class Query {
+
+ private String name;
+ private String project;
+ private String sql;
+ private String description;
+
+ public Query(){}
+
+ public Query(String name, String project, String sql, String description) {
+ super();
+ this.name = name;
+ this.project = project;
+ this.sql = sql;
+ this.description = description;
+ }
+
+ public String getId(){
+ return String.valueOf(this.hashCode());
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getProject() {
+ return project;
+ }
+
+ public void setProject(String project) {
+ this.project = project;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((description == null) ? 0 : description.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((project == null) ? 0 : project.hashCode());
+ result = prime * result + ((sql == null) ? 0 : sql.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;
+ Query other = (Query) obj;
+ if (description == null) {
+ if (other.description != null)
+ return false;
+ } else if (!description.equals(other.description))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (project == null) {
+ if (other.project != null)
+ return false;
+ } else if (!project.equals(other.project))
+ return false;
+ if (sql == null) {
+ if (other.sql != null)
+ return false;
+ } else if (!sql.equals(other.sql))
+ return false;
+ return true;
+ }
+
+}