http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/error/exception/GriffinException.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/error/exception/GriffinException.java b/service/src/main/java/org/apache/griffin/core/error/exception/GriffinException.java deleted file mode 100644 index 67fa8ae..0000000 --- a/service/src/main/java/org/apache/griffin/core/error/exception/GriffinException.java +++ /dev/null @@ -1,41 +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.griffin.core.error.exception; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.ResponseStatus; - -public abstract class GriffinException extends RuntimeException { - @ResponseStatus(value = HttpStatus.GATEWAY_TIMEOUT, reason = "Fail to Connect Kafka") - public static class KafkaConnectionException extends GriffinException { - } - - @ResponseStatus(value = HttpStatus.GATEWAY_TIMEOUT, reason = "Fail to Connect Hive") - public static class HiveConnectionException extends GriffinException { - } - - @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Fail to Get HealthInfo") - public static class GetHealthInfoFailureException extends GriffinException { - } - - @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Fail to Get Jobs") - public static class GetJobsFailureException extends GriffinException { - } -}
http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/error/exception/RuntimeExceptionHandler.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/error/exception/RuntimeExceptionHandler.java b/service/src/main/java/org/apache/griffin/core/error/exception/RuntimeExceptionHandler.java deleted file mode 100644 index d35fc44..0000000 --- a/service/src/main/java/org/apache/griffin/core/error/exception/RuntimeExceptionHandler.java +++ /dev/null @@ -1,62 +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.griffin.core.error.exception; - -import org.apache.griffin.core.util.GriffinOperationMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.context.request.ServletWebRequest; - -import javax.servlet.http.HttpServletRequest; -import java.util.Map; - -@ControllerAdvice -@ResponseBody -public class RuntimeExceptionHandler { - private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeExceptionHandler.class); - - @ExceptionHandler(RuntimeException.class) - public ResponseEntity<Map<String, Object>> handleUnexpectedRuntimeException(RuntimeException e, HttpServletRequest request) { - LOGGER.error("Unexpected RuntimeException. " + e); - return setExceptionResponse(request, HttpStatus.INTERNAL_SERVER_ERROR, GriffinOperationMessage.UNEXPECTED_RUNTIME_EXCEPTION); - } - - @ExceptionHandler(value = GriffinException.class) - public void handleCustomException(GriffinException e) throws GriffinException { - throw e; - } - - private ResponseEntity<Map<String, Object>> setExceptionResponse(HttpServletRequest request, HttpStatus status, - GriffinOperationMessage message) { - request.setAttribute("javax.servlet.error.status_code", status.value()); - request.setAttribute("javax.servlet.error.message", message.getDescription()); - request.setAttribute("javax.servlet.error.error", status.toString()); - request.setAttribute("javax.servlet.error.request_uri", request.getRequestURI()); - Map<String, Object> map = (new DefaultErrorAttributes()) - .getErrorAttributes(new ServletWebRequest(request), false); - return new ResponseEntity(map, status); - } -} http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/exception/GriffinException.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/exception/GriffinException.java b/service/src/main/java/org/apache/griffin/core/exception/GriffinException.java new file mode 100644 index 0000000..35fc1b5 --- /dev/null +++ b/service/src/main/java/org/apache/griffin/core/exception/GriffinException.java @@ -0,0 +1,62 @@ +/* +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.griffin.core.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +public abstract class GriffinException extends RuntimeException { + + GriffinException(String message) { + super(message); + } + + GriffinException(String message, Throwable cause) { + super(message, cause); + } + + @ResponseStatus(value = HttpStatus.NOT_FOUND) + public static class NotFoundException extends GriffinException { + public NotFoundException(GriffinExceptionMessage message) { + super(message.toString()); + } + } + + @ResponseStatus(value = HttpStatus.CONFLICT) + public static class ConflictException extends GriffinException { + public ConflictException(GriffinExceptionMessage message) { + super(message.toString()); + } + } + + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public static class BadRequestException extends GriffinException { + public BadRequestException(GriffinExceptionMessage message) { + super(message.toString()); + } + } + + public static class ServiceException extends GriffinException { + public ServiceException(String message, Throwable cause) { + super(message, cause); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionHandler.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionHandler.java b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionHandler.java new file mode 100644 index 0000000..6b9a63c --- /dev/null +++ b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionHandler.java @@ -0,0 +1,52 @@ +/* +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.griffin.core.exception; + +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; + +import javax.servlet.http.HttpServletRequest; + +@ControllerAdvice +public class GriffinExceptionHandler { + + @ExceptionHandler(GriffinException.ServiceException.class) + public ResponseEntity handleGriffinExceptionOfServer(HttpServletRequest request, GriffinException.ServiceException e) { + String message = e.getMessage(); + Throwable cause = e.getCause(); + GriffinExceptionResponse body = new GriffinExceptionResponse(HttpStatus.INTERNAL_SERVER_ERROR, + message, request.getRequestURI(), cause.getClass().getName()); + return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(GriffinException.class) + public ResponseEntity handleGriffinExceptionOfClient(HttpServletRequest request, GriffinException e) { + ResponseStatus responseStatus = AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class); + HttpStatus status = responseStatus.code(); + String code = e.getMessage(); + GriffinExceptionMessage message = GriffinExceptionMessage.valueOf(Integer.valueOf(code)); + GriffinExceptionResponse body = new GriffinExceptionResponse(status, message, request.getRequestURI()); + return new ResponseEntity<>(body, status); + } +} http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java new file mode 100644 index 0000000..83fbc23 --- /dev/null +++ b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionMessage.java @@ -0,0 +1,77 @@ +/* +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.griffin.core.exception; + +public enum GriffinExceptionMessage { + + //400, "Bad Request" + MEASURE_TYPE_DOES_NOT_MATCH(40001, "Property 'measure.type' does not match the type of measure in request body"), + INVALID_CONNECTOR_NAME(40002, "Property 'name' in 'connectors' field is invalid"), + MISSING_METRIC_NAME(40003, "Missing property 'metricName'"), + INVALID_JOB_NAME(40004, "Property 'job.name' is invalid"), + MISSING_BASELINE_CONFIG(40005, "Missing 'as.baseline' config in 'data.segments'"), + INVALID_METRIC_RECORDS_OFFSET(40006, "Offset must not be less than zero"), + INVALID_METRIC_RECORDS_SIZE(40007, "Size must not be less than zero"), + INVALID_METRIC_VALUE_FORMAT(40008, "Metric value format is invalid"), + INVALID_MEASURE_ID(40009, "Property 'measure.id' is invalid"), + + //404, "Not Found" + MEASURE_ID_DOES_NOT_EXIST(40401, "Measure id does not exist"), + JOB_ID_DOES_NOT_EXIST(40402, "Job id does not exist"), + JOB_NAME_DOES_NOT_EXIST(40403, "Job name does not exist"), + + //409, "Conflict" + MEASURE_NAME_ALREADY_EXIST(40901, "Measure name already exists"), + QUARTZ_JOB_ALREADY_EXIST(40902, "Quartz job already exist"); + + private final int code; + private final String message; + + GriffinExceptionMessage(int code, String message) { + this.code = code; + this.message = message; + } + + public static GriffinExceptionMessage valueOf(int code) { + GriffinExceptionMessage[] messages = values(); + int len = values().length; + for (int i = 0; i < len; i++) { + GriffinExceptionMessage message = messages[i]; + if (message.code == code) { + return message; + } + } + throw new IllegalArgumentException("No matching constant for [" + code + "]"); + } + + + @Override + public String toString() { + return Integer.toString(code); + } + + public int getCode() { + return code; + } + + public String getMessage() { + return message; + } +} http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionResponse.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionResponse.java b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionResponse.java new file mode 100644 index 0000000..270dfbc --- /dev/null +++ b/service/src/main/java/org/apache/griffin/core/exception/GriffinExceptionResponse.java @@ -0,0 +1,82 @@ +/* +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.griffin.core.exception; + +import com.fasterxml.jackson.annotation.JsonInclude; +import org.springframework.http.HttpStatus; + +import java.util.Date; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class GriffinExceptionResponse { + + private Date timestamp = new Date(); + private int status; + private String error; + private String code; + private String message; + private String exception; + private String path; + + + GriffinExceptionResponse(HttpStatus status, GriffinExceptionMessage message, String path) { + this.status = status.value(); + this.error = status.getReasonPhrase(); + this.code = Integer.toString(message.getCode()); + this.message = message.getMessage(); + this.path = path; + } + + GriffinExceptionResponse(HttpStatus status, String message, String path, String exception) { + this.status = status.value(); + this.error = status.getReasonPhrase(); + this.message = message; + this.path = path; + this.exception = exception; + } + + public Date getTimestamp() { + return timestamp; + } + + public int getStatus() { + return status; + } + + public String getError() { + return error; + } + + public String getCode() { + return code; + } + + public String getMessage() { + return message; + } + + public String getPath() { + return path; + } + + public String getException() { + return exception; + } +} http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/job/JobController.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/job/JobController.java b/service/src/main/java/org/apache/griffin/core/job/JobController.java index 3731d9f..7705e43 100644 --- a/service/src/main/java/org/apache/griffin/core/job/JobController.java +++ b/service/src/main/java/org/apache/griffin/core/job/JobController.java @@ -19,12 +19,9 @@ under the License. package org.apache.griffin.core.job; -import org.apache.griffin.core.job.entity.JobDataBean; -import org.apache.griffin.core.job.entity.JobHealth; -import org.apache.griffin.core.job.entity.JobInstanceBean; -import org.apache.griffin.core.job.entity.JobSchedule; -import org.apache.griffin.core.util.GriffinOperationMessage; +import org.apache.griffin.core.job.entity.*; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -42,18 +39,21 @@ public class JobController { } @RequestMapping(value = "/jobs", method = RequestMethod.POST) - public GriffinOperationMessage addJob(@RequestBody JobSchedule jobSchedule) throws Exception { + @ResponseStatus(HttpStatus.CREATED) + public GriffinJob addJob(@RequestBody JobSchedule jobSchedule) throws Exception { return jobService.addJob(jobSchedule); } @RequestMapping(value = "/jobs", method = RequestMethod.DELETE) - public GriffinOperationMessage deleteJob(@RequestParam("jobName") String jobName) { - return jobService.deleteJob(jobName); + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteJob(@RequestParam("jobName") String jobName) { + jobService.deleteJob(jobName); } @RequestMapping(value = "/jobs/{id}", method = RequestMethod.DELETE) - public GriffinOperationMessage deleteJob(@PathVariable("id") Long id) { - return jobService.deleteJob(id); + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteJob(@PathVariable("id") Long id) { + jobService.deleteJob(id); } @RequestMapping(value = "/jobs/instances", method = RequestMethod.GET) http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/job/JobService.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/job/JobService.java b/service/src/main/java/org/apache/griffin/core/job/JobService.java index 33dce25..8c2c197 100644 --- a/service/src/main/java/org/apache/griffin/core/job/JobService.java +++ b/service/src/main/java/org/apache/griffin/core/job/JobService.java @@ -19,11 +19,7 @@ under the License. package org.apache.griffin.core.job; -import org.apache.griffin.core.job.entity.JobDataBean; -import org.apache.griffin.core.job.entity.JobHealth; -import org.apache.griffin.core.job.entity.JobInstanceBean; -import org.apache.griffin.core.job.entity.JobSchedule; -import org.apache.griffin.core.util.GriffinOperationMessage; +import org.apache.griffin.core.job.entity.*; import org.quartz.SchedulerException; import java.util.List; @@ -32,13 +28,13 @@ public interface JobService { List<JobDataBean> getAliveJobs(); - GriffinOperationMessage addJob(JobSchedule jobSchedule) throws Exception; + GriffinJob addJob(JobSchedule jobSchedule) throws Exception; - boolean pauseJob(String group, String name) throws SchedulerException; + void pauseJob(String group, String name) throws SchedulerException; - GriffinOperationMessage deleteJob(Long jobId); + void deleteJob(Long jobId); - GriffinOperationMessage deleteJob(String jobName); + void deleteJob(String jobName); List<JobInstanceBean> findInstancesOfJob(Long jobId, int page, int size); http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/job/JobServiceImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/job/JobServiceImpl.java b/service/src/main/java/org/apache/griffin/core/job/JobServiceImpl.java index ef2fb9f..226ad64 100644 --- a/service/src/main/java/org/apache/griffin/core/job/JobServiceImpl.java +++ b/service/src/main/java/org/apache/griffin/core/job/JobServiceImpl.java @@ -21,24 +21,20 @@ package org.apache.griffin.core.job; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.lang.StringUtils; -import org.apache.griffin.core.error.exception.GriffinException.GetHealthInfoFailureException; -import org.apache.griffin.core.error.exception.GriffinException.GetJobsFailureException; +import org.apache.griffin.core.exception.GriffinException; import org.apache.griffin.core.job.entity.*; import org.apache.griffin.core.job.repo.GriffinJobRepo; import org.apache.griffin.core.job.repo.JobInstanceRepo; import org.apache.griffin.core.job.repo.JobScheduleRepo; import org.apache.griffin.core.measure.entity.DataSource; import org.apache.griffin.core.measure.entity.GriffinMeasure; -import org.apache.griffin.core.measure.entity.Measure; import org.apache.griffin.core.measure.repo.GriffinMeasureRepo; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.apache.griffin.core.util.JsonUtil; import org.quartz.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.dao.DataAccessException; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -54,7 +50,7 @@ import java.io.IOException; import java.text.ParseException; import java.util.*; -import static org.apache.griffin.core.util.GriffinOperationMessage.*; +import static org.apache.griffin.core.exception.GriffinExceptionMessage.*; import static org.quartz.JobBuilder.newJob; import static org.quartz.JobKey.jobKey; import static org.quartz.TriggerBuilder.newTrigger; @@ -100,9 +96,9 @@ public class JobServiceImpl implements JobService { dataList.add(jobData); } } - } catch (Exception e) { + } catch (SchedulerException e) { LOGGER.error("Failed to get running jobs.", e); - throw new GetJobsFailureException(); + throw new GriffinException.ServiceException("Failed to get running jobs.", e); } return dataList; } @@ -132,7 +128,7 @@ public class JobServiceImpl implements JobService { return null; } - private void setTriggerTime(Trigger trigger, JobDataBean jobBean) throws SchedulerException { + private void setTriggerTime(Trigger trigger, JobDataBean jobBean) { Date nextFireTime = trigger.getNextFireTime(); Date previousFireTime = trigger.getPreviousFireTime(); jobBean.setNextFireTime(nextFireTime != null ? nextFireTime.getTime() : -1); @@ -141,23 +137,22 @@ public class JobServiceImpl implements JobService { @Override @Transactional(rollbackFor = Exception.class) - public GriffinOperationMessage addJob(JobSchedule js) throws Exception { + public GriffinJob addJob(JobSchedule js) throws Exception { Long measureId = js.getMeasureId(); GriffinMeasure measure = getMeasureIfValid(measureId); - if (measure != null) { - String qName = getQuartzName(js); - String qGroup = getQuartzGroupName(); - TriggerKey triggerKey = triggerKey(qName, qGroup); - if (!isJobScheduleParamValid(js, measure) || factory.getObject().checkExists(triggerKey)) { - return CREATE_JOB_FAIL; - } - GriffinJob job = new GriffinJob(measure.getId(), js.getJobName(), qName, qGroup, false); - job = jobRepo.save(job); - js = jobScheduleRepo.save(js); - addJob(triggerKey, js, job); - return CREATE_JOB_SUCCESS; + checkJobScheduleParams(js, measure); + String qName = getQuartzName(js); + String qGroup = getQuartzGroupName(); + TriggerKey triggerKey = triggerKey(qName, qGroup); + if (factory.getObject().checkExists(triggerKey)) { + throw new GriffinException.ConflictException(QUARTZ_JOB_ALREADY_EXIST); } - return CREATE_JOB_FAIL; + GriffinJob job = new GriffinJob(measure.getId(), js.getJobName(), qName, qGroup, false); + job = jobRepo.save(job); + js = jobScheduleRepo.save(js); + addJob(triggerKey, js, job); + return job; + } private void addJob(TriggerKey triggerKey, JobSchedule js, GriffinJob job) throws Exception { @@ -174,15 +169,17 @@ public class JobServiceImpl implements JobService { return "BA"; } - private boolean isJobScheduleParamValid(JobSchedule js, GriffinMeasure measure) throws SchedulerException { + private void checkJobScheduleParams(JobSchedule js, GriffinMeasure measure) { if (!isJobNameValid(js.getJobName())) { - return false; + throw new GriffinException.BadRequestException(INVALID_JOB_NAME); } if (!isBaseLineValid(js.getSegments())) { - return false; + throw new GriffinException.BadRequestException(MISSING_BASELINE_CONFIG); } List<String> names = getConnectorNames(measure); - return names != null && isConnectorNamesValid(js.getSegments(), names); + if (!isConnectorNamesValid(js.getSegments(), names)) { + throw new GriffinException.BadRequestException(INVALID_CONNECTOR_NAME); + } } private boolean isJobNameValid(String jobName) { @@ -239,25 +236,23 @@ public class JobServiceImpl implements JobService { Set<String> sets = new HashSet<>(); List<DataSource> sources = measure.getDataSources(); for (DataSource source : sources) { - source.getConnectors().forEach(dc -> { - sets.add(dc.getName()); - }); + source.getConnectors().forEach(dc -> sets.add(dc.getName())); } if (sets.size() < sources.size()) { LOGGER.warn("Connector names cannot be repeated."); - return null; + return Collections.emptyList(); } names.addAll(sets); return names; } private GriffinMeasure getMeasureIfValid(Long measureId) { - Measure measure = measureRepo.findByIdAndDeleted(measureId, false); + GriffinMeasure measure = measureRepo.findByIdAndDeleted(measureId, false); if (measure == null) { LOGGER.warn("The measure id {} isn't valid. Maybe it doesn't exist or is external measure type.", measureId); - return null; + throw new GriffinException.BadRequestException(INVALID_MEASURE_ID); } - return (GriffinMeasure) measure; + return measure; } @@ -307,51 +302,45 @@ public class JobServiceImpl implements JobService { } private boolean pauseJob(JobInstanceBean instance, List<JobInstanceBean> deletedInstances) { - boolean status; + boolean status = true; try { - status = pauseJob(instance.getPredicateGroup(), instance.getPredicateName()); - if (status) { - instance.setDeleted(true); - deletedInstances.add(instance); - } + pauseJob(instance.getPredicateGroup(), instance.getPredicateName()); + instance.setDeleted(true); + deletedInstances.add(instance); } catch (SchedulerException e) { - LOGGER.error("Pause predicate job({},{}) failure.", instance.getId(), instance.getPredicateName()); + LOGGER.error("Failed to pause predicate job({},{}).", instance.getId(), instance.getPredicateName()); status = false; } return status; } @Override - public boolean pauseJob(String group, String name) throws SchedulerException { + public void pauseJob(String group, String name) throws SchedulerException { Scheduler scheduler = factory.getObject(); JobKey jobKey = new JobKey(name, group); if (!scheduler.checkExists(jobKey)) { LOGGER.warn("Job({},{}) does not exist.", jobKey.getGroup(), jobKey.getName()); - return true; + return; } scheduler.pauseJob(jobKey); - return true; } - private boolean setJobDeleted(GriffinJob job) throws SchedulerException { + private void setJobDeleted(GriffinJob job) { job.setDeleted(true); jobRepo.save(job); - return true; } - private boolean deletePredicateJob(GriffinJob job) throws SchedulerException { - boolean pauseStatus = true; + private void deletePredicateJob(GriffinJob job) throws SchedulerException { List<JobInstanceBean> instances = job.getJobInstances(); for (JobInstanceBean instance : instances) { if (!instance.getDeleted()) { - pauseStatus = pauseStatus && deleteJob(instance.getPredicateGroup(), instance.getPredicateName()); + deleteJob(instance.getPredicateGroup(), instance.getPredicateName()); instance.setDeleted(true); if (instance.getState().equals(LivySessionStates.State.finding)) { instance.setState(LivySessionStates.State.not_found); } } } - return pauseStatus; } /** @@ -360,59 +349,53 @@ public class JobServiceImpl implements JobService { * 2. set these jobs as deleted status * * @param jobId griffin job id - * @return custom information */ @Override - public GriffinOperationMessage deleteJob(Long jobId) { + public void deleteJob(Long jobId) { GriffinJob job = jobRepo.findByIdAndDeleted(jobId, false); - return deleteJob(job) ? DELETE_JOB_SUCCESS : DELETE_JOB_FAIL; + if (job == null) { + LOGGER.warn("Griffin job does not exist."); + throw new GriffinException.NotFoundException(JOB_ID_DOES_NOT_EXIST); + } + deleteJob(job); } /** * logically delete * * @param name griffin job name which may not be unique. - * @return custom information */ @Override - public GriffinOperationMessage deleteJob(String name) { + public void deleteJob(String name) { List<GriffinJob> jobs = jobRepo.findByJobNameAndDeleted(name, false); if (CollectionUtils.isEmpty(jobs)) { LOGGER.warn("There is no job with '{}' name.", name); - return DELETE_JOB_FAIL; + throw new GriffinException.NotFoundException(JOB_NAME_DOES_NOT_EXIST); } for (GriffinJob job : jobs) { - if (!deleteJob(job)) { - return DELETE_JOB_FAIL; - } + deleteJob(job); } - return DELETE_JOB_SUCCESS; } - private boolean deleteJob(GriffinJob job) { - if (job == null) { - LOGGER.warn("Griffin job does not exist."); - return false; - } + private void deleteJob(GriffinJob job) { try { - if (pauseJob(job.getQuartzGroup(), job.getQuartzName()) && deletePredicateJob(job) && setJobDeleted(job)) { - return true; - } + pauseJob(job.getQuartzGroup(), job.getQuartzName()); + deletePredicateJob(job); + setJobDeleted(job); } catch (Exception e) { - LOGGER.error("Delete job failure.", e); + LOGGER.error("Failed to delete job", e); + throw new GriffinException.ServiceException("Failed to delete job", e); } - return false; } - private boolean deleteJob(String group, String name) throws SchedulerException { + private void deleteJob(String group, String name) throws SchedulerException { Scheduler scheduler = factory.getObject(); JobKey jobKey = new JobKey(name, group); if (!scheduler.checkExists(jobKey)) { - LOGGER.warn("Job({},{}) does not exist.", jobKey.getGroup(), jobKey.getName()); - return true; + LOGGER.info("Job({},{}) does not exist.", jobKey.getGroup(), jobKey.getName()); + return; } scheduler.deleteJob(jobKey); - return true; } /** @@ -422,17 +405,15 @@ public class JobServiceImpl implements JobService { * * @param measureId measure id */ - public boolean deleteJobsRelateToMeasure(Long measureId) { + public void deleteJobsRelateToMeasure(Long measureId) { List<GriffinJob> jobs = jobRepo.findByMeasureIdAndDeleted(measureId, false); if (CollectionUtils.isEmpty(jobs)) { LOGGER.info("Measure id {} has no related jobs.", measureId); - return true; + return; } - boolean status = true; for (GriffinJob job : jobs) { - status = status && deleteJob(job); + deleteJob(job); } - return status; } @Override @@ -440,7 +421,7 @@ public class JobServiceImpl implements JobService { AbstractJob job = jobRepo.findByIdAndDeleted(jobId, false); if (job == null) { LOGGER.warn("Job id {} does not exist.", jobId); - return new ArrayList<>(); + throw new GriffinException.NotFoundException(JOB_ID_DOES_NOT_EXIST); } size = size > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : size; size = size <= 0 ? DEFAULT_PAGE_SIZE : size; @@ -492,7 +473,7 @@ public class JobServiceImpl implements JobService { } catch (IllegalArgumentException e) { LOGGER.error("Livy status is illegal. {}", e.getMessage()); } catch (Exception e) { - LOGGER.error("Sync job instances failure. {}",e.getMessage()); + LOGGER.error("Sync job instances failure. {}", e.getMessage()); } } @@ -551,7 +532,7 @@ public class JobServiceImpl implements JobService { triggers = (List<Trigger>) factory.getObject().getTriggersOfJob(jobKey); } catch (SchedulerException e) { LOGGER.error("Job schedule exception. {}", e.getMessage()); - throw new GetHealthInfoFailureException(); + throw new GriffinException.ServiceException("Fail to Get HealthInfo", e); } return triggers; } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/job/SparkSubmitJob.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/job/SparkSubmitJob.java b/service/src/main/java/org/apache/griffin/core/job/SparkSubmitJob.java index e089d15..9a9785f 100644 --- a/service/src/main/java/org/apache/griffin/core/job/SparkSubmitJob.java +++ b/service/src/main/java/org/apache/griffin/core/job/SparkSubmitJob.java @@ -100,7 +100,7 @@ public class SparkSubmitJob implements Job { return result; } - private boolean success(List<SegmentPredicate> predicates) throws IOException { + private boolean success(List<SegmentPredicate> predicates) { if (CollectionUtils.isEmpty(predicates)) { return true; } @@ -197,8 +197,9 @@ public class SparkSubmitJob implements Job { String result = post2Livy(); boolean pauseStatus = false; if (result != null) { - pauseStatus = jobService.pauseJob(jd.getKey().getGroup(), jd.getKey().getName()); - LOGGER.info("Delete predicate job {}.", pauseStatus ? "success" : "failure"); + jobService.pauseJob(jd.getKey().getGroup(), jd.getKey().getName()); + pauseStatus = true; + LOGGER.info("Delete predicate job {} success"); } saveJobInstance(result, LivySessionStates.State.found, pauseStatus); } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/ExternalMeasureOperationImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/ExternalMeasureOperationImpl.java b/service/src/main/java/org/apache/griffin/core/measure/ExternalMeasureOperationImpl.java index ab04567..dc7c056 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/ExternalMeasureOperationImpl.java +++ b/service/src/main/java/org/apache/griffin/core/measure/ExternalMeasureOperationImpl.java @@ -20,18 +20,19 @@ under the License. package org.apache.griffin.core.measure; import org.apache.commons.lang.StringUtils; +import org.apache.griffin.core.exception.GriffinException; import org.apache.griffin.core.job.entity.VirtualJob; import org.apache.griffin.core.job.repo.VirtualJobRepo; import org.apache.griffin.core.measure.entity.ExternalMeasure; import org.apache.griffin.core.measure.entity.Measure; import org.apache.griffin.core.measure.repo.ExternalMeasureRepo; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; -import static org.apache.griffin.core.util.GriffinOperationMessage.*; +import static org.apache.griffin.core.exception.GriffinExceptionMessage.MISSING_METRIC_NAME; @Component("externalOperation") public class ExternalMeasureOperationImpl implements MeasureOperation { @@ -43,56 +44,40 @@ public class ExternalMeasureOperationImpl implements MeasureOperation { private VirtualJobRepo jobRepo; @Override - public GriffinOperationMessage create(Measure measure) { + @Transactional + public Measure create(Measure measure) { ExternalMeasure em = (ExternalMeasure) measure; if (StringUtils.isBlank(em.getMetricName())) { - LOGGER.error("Failed to create external measure {}. Its metric name is blank.", measure.getName()); - return CREATE_MEASURE_FAIL; - } - try { - em.setVirtualJob(new VirtualJob()); - em = measureRepo.save(em); - VirtualJob vj = genVirtualJob(em, em.getVirtualJob()); - jobRepo.save(vj); - return CREATE_MEASURE_SUCCESS; - } catch (Exception e) { - LOGGER.error("Failed to create new measure {}.{}", em.getName(), e.getMessage()); + LOGGER.warn("Failed to create external measure {}. Its metric name is blank.", measure.getName()); + throw new GriffinException.BadRequestException(MISSING_METRIC_NAME); + } - return CREATE_MEASURE_FAIL; + em.setVirtualJob(new VirtualJob()); + em = measureRepo.save(em); + VirtualJob vj = genVirtualJob(em, em.getVirtualJob()); + jobRepo.save(vj); + return em; } @Override - public GriffinOperationMessage update(Measure measure) { + public void update(Measure measure) { ExternalMeasure latestMeasure = (ExternalMeasure) measure; if (StringUtils.isBlank(latestMeasure.getMetricName())) { - LOGGER.error("Failed to create external measure {}. Its metric name is blank.", measure.getName()); - return UPDATE_MEASURE_FAIL; - } - try { - ExternalMeasure originMeasure = measureRepo.findOne(latestMeasure.getId()); - VirtualJob vj = genVirtualJob(latestMeasure, originMeasure.getVirtualJob()); - latestMeasure.setVirtualJob(vj); - measureRepo.save(latestMeasure); - return UPDATE_MEASURE_SUCCESS; - } catch (Exception e) { - LOGGER.error("Failed to update measure. {}", e.getMessage()); + LOGGER.warn("Failed to update external measure {}. Its metric name is blank.", measure.getName()); + throw new GriffinException.BadRequestException(MISSING_METRIC_NAME); } - return UPDATE_MEASURE_FAIL; + ExternalMeasure originMeasure = measureRepo.findOne(latestMeasure.getId()); + VirtualJob vj = genVirtualJob(latestMeasure, originMeasure.getVirtualJob()); + latestMeasure.setVirtualJob(vj); + measureRepo.save(latestMeasure); } @Override - public GriffinOperationMessage delete(Measure measure) { - try { - ExternalMeasure em = (ExternalMeasure) measure; - em.setDeleted(true); - em.getVirtualJob().setDeleted(true); - measureRepo.save(em); - return DELETE_MEASURE_BY_ID_SUCCESS; - } catch (Exception e) { - LOGGER.error("Failed to delete measure. {}", e.getMessage()); - } - return DELETE_MEASURE_BY_ID_FAIL; - + public void delete(Measure measure) { + ExternalMeasure em = (ExternalMeasure) measure; + em.setDeleted(true); + em.getVirtualJob().setDeleted(true); + measureRepo.save(em); } private VirtualJob genVirtualJob(ExternalMeasure em, VirtualJob vj) { http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/GriffinMeasureOperationImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/GriffinMeasureOperationImpl.java b/service/src/main/java/org/apache/griffin/core/measure/GriffinMeasureOperationImpl.java index b5d9805..22561a4 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/GriffinMeasureOperationImpl.java +++ b/service/src/main/java/org/apache/griffin/core/measure/GriffinMeasureOperationImpl.java @@ -20,6 +20,7 @@ under the License. package org.apache.griffin.core.measure; import org.apache.commons.lang.StringUtils; +import org.apache.griffin.core.exception.GriffinException; import org.apache.griffin.core.job.JobServiceImpl; import org.apache.griffin.core.measure.entity.DataConnector; import org.apache.griffin.core.measure.entity.DataSource; @@ -27,7 +28,6 @@ import org.apache.griffin.core.measure.entity.GriffinMeasure; import org.apache.griffin.core.measure.entity.Measure; import org.apache.griffin.core.measure.repo.DataConnectorRepo; import org.apache.griffin.core.measure.repo.MeasureRepo; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -37,7 +37,7 @@ import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; -import static org.apache.griffin.core.util.GriffinOperationMessage.*; +import static org.apache.griffin.core.exception.GriffinExceptionMessage.INVALID_CONNECTOR_NAME; @Component("griffinOperation") public class GriffinMeasureOperationImpl implements MeasureOperation { @@ -52,58 +52,34 @@ public class GriffinMeasureOperationImpl implements MeasureOperation { @Override - public GriffinOperationMessage create(Measure measure) { - if (!isConnectorNamesValid((GriffinMeasure) measure)) { - return CREATE_MEASURE_FAIL; - } - try { - measureRepo.save(measure); - return CREATE_MEASURE_SUCCESS; - } catch (Exception e) { - LOGGER.error("Failed to create new measure {}.", measure.getName(), e); - } - return CREATE_MEASURE_FAIL; + public Measure create(Measure measure) { + checkConnectorNames((GriffinMeasure) measure); + return measureRepo.save(measure); } @Override - public GriffinOperationMessage update(Measure measure) { - try { - measureRepo.save(measure); - return UPDATE_MEASURE_SUCCESS; - } catch (Exception e) { - LOGGER.error("Failed to update measure. {}", e.getMessage()); - } - return UPDATE_MEASURE_FAIL; + public void update(Measure measure) { + measureRepo.save(measure); } @Override - public GriffinOperationMessage delete(Measure measure) { - try { - boolean pauseStatus = jobService.deleteJobsRelateToMeasure(measure.getId()); - if (!pauseStatus) { - return DELETE_MEASURE_BY_ID_FAIL; - } - measure.setDeleted(true); - measureRepo.save(measure); - return DELETE_MEASURE_BY_ID_SUCCESS; - } catch (Exception e) { - LOGGER.error(e.getMessage()); - } - return DELETE_MEASURE_BY_ID_FAIL; + public void delete(Measure measure) { + jobService.deleteJobsRelateToMeasure(measure.getId()); + measure.setDeleted(true); + measureRepo.save(measure); } - private boolean isConnectorNamesValid(GriffinMeasure measure) { + private void checkConnectorNames(GriffinMeasure measure) { List<String> names = getConnectorNames(measure); if (names.size() == 0) { LOGGER.warn("Connector names cannot be empty."); - return false; + throw new GriffinException.BadRequestException(INVALID_CONNECTOR_NAME); } List<DataConnector> connectors = dcRepo.findByConnectorNames(names); if (!CollectionUtils.isEmpty(connectors)) { LOGGER.warn("Failed to create new measure {}. It's connector names already exist. ", measure.getName()); - return false; + throw new GriffinException.BadRequestException(INVALID_CONNECTOR_NAME); } - return true; } private List<String> getConnectorNames(GriffinMeasure measure) { http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/MeasureController.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/MeasureController.java b/service/src/main/java/org/apache/griffin/core/measure/MeasureController.java index 3b557ca..91ffaac 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/MeasureController.java +++ b/service/src/main/java/org/apache/griffin/core/measure/MeasureController.java @@ -20,8 +20,8 @@ under the License. package org.apache.griffin.core.measure; import org.apache.griffin.core.measure.entity.Measure; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -43,13 +43,15 @@ public class MeasureController { } @RequestMapping(value = "/measures/{id}", method = RequestMethod.DELETE) - public GriffinOperationMessage deleteMeasureById(@PathVariable("id") Long id) { - return measureService.deleteMeasureById(id); + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteMeasureById(@PathVariable("id") Long id) { + measureService.deleteMeasureById(id); } @RequestMapping(value = "/measures", method = RequestMethod.PUT) - public GriffinOperationMessage updateMeasure(@RequestBody Measure measure) { - return measureService.updateMeasure(measure); + @ResponseStatus(HttpStatus.NO_CONTENT) + public void updateMeasure(@RequestBody Measure measure) { + measureService.updateMeasure(measure); } @RequestMapping(value = "/measures/owner/{owner}", method = RequestMethod.GET) @@ -58,7 +60,8 @@ public class MeasureController { } @RequestMapping(value = "/measures", method = RequestMethod.POST) - public GriffinOperationMessage createMeasure(@RequestBody Measure measure) { + @ResponseStatus(HttpStatus.CREATED) + public Measure createMeasure(@RequestBody Measure measure) { return measureService.createMeasure(measure); } } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/MeasureOperation.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/MeasureOperation.java b/service/src/main/java/org/apache/griffin/core/measure/MeasureOperation.java index 81e9f06..1ebc06c 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/MeasureOperation.java +++ b/service/src/main/java/org/apache/griffin/core/measure/MeasureOperation.java @@ -21,14 +21,13 @@ package org.apache.griffin.core.measure; import org.apache.griffin.core.measure.entity.Measure; -import org.apache.griffin.core.util.GriffinOperationMessage; public interface MeasureOperation { - GriffinOperationMessage create(Measure measure); + Measure create(Measure measure); - GriffinOperationMessage update(Measure measure); + void update(Measure measure); - GriffinOperationMessage delete(Measure measure); + void delete(Measure measure); } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/MeasureService.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/MeasureService.java b/service/src/main/java/org/apache/griffin/core/measure/MeasureService.java index a330d0a..818db47 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/MeasureService.java +++ b/service/src/main/java/org/apache/griffin/core/measure/MeasureService.java @@ -21,7 +21,6 @@ package org.apache.griffin.core.measure; import org.apache.griffin.core.measure.entity.Measure; -import org.apache.griffin.core.util.GriffinOperationMessage; import java.util.List; @@ -36,16 +35,16 @@ public interface MeasureService { */ - GriffinOperationMessage deleteMeasureById(Long id); + void deleteMeasureById(Long id); /* GriffinOperationMessage deleteMeasureByName(String measureName) ; */ - GriffinOperationMessage updateMeasure(Measure measure); + void updateMeasure(Measure measure); List<Measure> getAliveMeasuresByOwner(String owner); - GriffinOperationMessage createMeasure(Measure measure); + Measure createMeasure(Measure measure); } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/measure/MeasureServiceImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/measure/MeasureServiceImpl.java b/service/src/main/java/org/apache/griffin/core/measure/MeasureServiceImpl.java index 86dc9a9..d9d7cd8 100644 --- a/service/src/main/java/org/apache/griffin/core/measure/MeasureServiceImpl.java +++ b/service/src/main/java/org/apache/griffin/core/measure/MeasureServiceImpl.java @@ -20,10 +20,10 @@ under the License. package org.apache.griffin.core.measure; +import org.apache.griffin.core.exception.GriffinException; import org.apache.griffin.core.measure.entity.GriffinMeasure; import org.apache.griffin.core.measure.entity.Measure; import org.apache.griffin.core.measure.repo.MeasureRepo; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -33,7 +33,7 @@ import org.springframework.util.CollectionUtils; import java.util.List; -import static org.apache.griffin.core.util.GriffinOperationMessage.*; +import static org.apache.griffin.core.exception.GriffinExceptionMessage.*; @Service public class MeasureServiceImpl implements MeasureService { @@ -55,7 +55,11 @@ public class MeasureServiceImpl implements MeasureService { @Override public Measure getMeasureById(long id) { - return measureRepo.findByIdAndDeleted(id, false); + Measure measure = measureRepo.findByIdAndDeleted(id, false); + if (measure == null) { + throw new GriffinException.NotFoundException(MEASURE_ID_DOES_NOT_EXIST); + } + return measure; } @Override @@ -64,38 +68,38 @@ public class MeasureServiceImpl implements MeasureService { } @Override - public GriffinOperationMessage createMeasure(Measure measure) { + public Measure createMeasure(Measure measure) { List<Measure> aliveMeasureList = measureRepo.findByNameAndDeleted(measure.getName(), false); if (!CollectionUtils.isEmpty(aliveMeasureList)) { LOGGER.warn("Failed to create new measure {}, it already exists.", measure.getName()); - return CREATE_MEASURE_FAIL_DUPLICATE; + throw new GriffinException.ConflictException(MEASURE_NAME_ALREADY_EXIST); } MeasureOperation op = getOperation(measure); return op.create(measure); } @Override - public GriffinOperationMessage updateMeasure(Measure measure) { + public void updateMeasure(Measure measure) { Measure m = measureRepo.findByIdAndDeleted(measure.getId(), false); if (m == null) { - return RESOURCE_NOT_FOUND; + throw new GriffinException.NotFoundException(MEASURE_ID_DOES_NOT_EXIST); } if (!m.getType().equals(measure.getType())) { - LOGGER.error("Can't update measure to different type."); - return UPDATE_MEASURE_FAIL; + LOGGER.warn("Can't update measure to different type."); + throw new GriffinException.BadRequestException(MEASURE_TYPE_DOES_NOT_MATCH); } MeasureOperation op = getOperation(measure); - return op.update(measure); + op.update(measure); } @Override - public GriffinOperationMessage deleteMeasureById(Long measureId) { + public void deleteMeasureById(Long measureId) { Measure measure = measureRepo.findByIdAndDeleted(measureId, false); if (measure == null) { - return RESOURCE_NOT_FOUND; + throw new GriffinException.NotFoundException(MEASURE_ID_DOES_NOT_EXIST); } MeasureOperation op = getOperation(measure); - return op.delete(measure); + op.delete(measure); } private MeasureOperation getOperation(Measure measure) { http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metastore/hive/HiveMetaStoreServiceImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metastore/hive/HiveMetaStoreServiceImpl.java b/service/src/main/java/org/apache/griffin/core/metastore/hive/HiveMetaStoreServiceImpl.java index 67f171f..8c41008 100644 --- a/service/src/main/java/org/apache/griffin/core/metastore/hive/HiveMetaStoreServiceImpl.java +++ b/service/src/main/java/org/apache/griffin/core/metastore/hive/HiveMetaStoreServiceImpl.java @@ -73,7 +73,7 @@ public class HiveMetaStoreServiceImpl implements HiveMetaStoreService { Iterable<String> results = null; try { if (client == null) { - LOGGER.warn("Hive client is null.Please check your hive config."); + LOGGER.warn("Hive client is null. Please check your hive config."); return new ArrayList<>(); } results = client.getAllDatabases(); @@ -91,7 +91,7 @@ public class HiveMetaStoreServiceImpl implements HiveMetaStoreService { Iterable<String> results = null; try { if (client == null) { - LOGGER.warn("Hive client is null.Please check your hive config."); + LOGGER.warn("Hive client is null. Please check your hive config."); return new ArrayList<>(); } results = client.getAllTables(getUseDbName(dbName)); @@ -117,7 +117,7 @@ public class HiveMetaStoreServiceImpl implements HiveMetaStoreService { Iterable<String> dbs; // if hive.metastore.uris in application.properties configs wrong, client will be injected failure and will be null. if (client == null) { - LOGGER.warn("Hive client is null.Please check your hive config."); + LOGGER.warn("Hive client is null. Please check your hive config."); return results; } dbs = getAllDatabases(); @@ -136,7 +136,7 @@ public class HiveMetaStoreServiceImpl implements HiveMetaStoreService { Table result = null; try { if (client == null) { - LOGGER.warn("Hive client is null.Please check your hive config."); + LOGGER.warn("Hive client is null. Please check your hive config."); return null; } result = client.getTable(getUseDbName(dbName), tableName); @@ -153,7 +153,7 @@ public class HiveMetaStoreServiceImpl implements HiveMetaStoreService { List<Table> allTables = new ArrayList<>(); try { if (client == null) { - LOGGER.warn("Hive client is null.Please check your hive config."); + LOGGER.warn("Hive client is null. Please check your hive config."); return allTables; } Iterable<String> tables = client.getAllTables(useDbName); http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metric/MetricController.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricController.java b/service/src/main/java/org/apache/griffin/core/metric/MetricController.java index 359858b..6a2c51c 100644 --- a/service/src/main/java/org/apache/griffin/core/metric/MetricController.java +++ b/service/src/main/java/org/apache/griffin/core/metric/MetricController.java @@ -21,8 +21,8 @@ package org.apache.griffin.core.metric; import org.apache.griffin.core.metric.model.Metric; import org.apache.griffin.core.metric.model.MetricValue; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -49,12 +49,13 @@ public class MetricController { } @RequestMapping(value = "/metrics/values", method = RequestMethod.POST) - public ResponseEntity<GriffinOperationMessage> addMetricValues(@RequestBody List<MetricValue> values) { + public ResponseEntity addMetricValues(@RequestBody List<MetricValue> values) { return metricService.addMetricValues(values); } @RequestMapping(value = "/metrics/values", method = RequestMethod.DELETE) - public ResponseEntity<GriffinOperationMessage> deleteMetricValues(@RequestParam("metricName") String metricName) { + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity deleteMetricValues(@RequestParam("metricName") String metricName) { return metricService.deleteMetricValues(metricName); } } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metric/MetricService.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricService.java b/service/src/main/java/org/apache/griffin/core/metric/MetricService.java index 502f254..f68d83c 100644 --- a/service/src/main/java/org/apache/griffin/core/metric/MetricService.java +++ b/service/src/main/java/org/apache/griffin/core/metric/MetricService.java @@ -22,7 +22,6 @@ package org.apache.griffin.core.metric; import org.apache.griffin.core.metric.model.Metric; import org.apache.griffin.core.metric.model.MetricValue; -import org.apache.griffin.core.util.GriffinOperationMessage; import org.springframework.http.ResponseEntity; import java.util.List; @@ -34,7 +33,7 @@ public interface MetricService { List<MetricValue> getMetricValues(String metricName, int offset, int size); - ResponseEntity<GriffinOperationMessage> addMetricValues(List<MetricValue> values); + ResponseEntity addMetricValues(List<MetricValue> values); - ResponseEntity<GriffinOperationMessage> deleteMetricValues(String metricName); + ResponseEntity deleteMetricValues(String metricName); } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java b/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java index 4d992e2..b09c050 100644 --- a/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java +++ b/service/src/main/java/org/apache/griffin/core/metric/MetricServiceImpl.java @@ -22,26 +22,29 @@ package org.apache.griffin.core.metric; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; +import org.apache.griffin.core.exception.GriffinException; import org.apache.griffin.core.job.entity.AbstractJob; import org.apache.griffin.core.job.repo.JobRepo; import org.apache.griffin.core.measure.entity.Measure; import org.apache.griffin.core.measure.repo.MeasureRepo; import org.apache.griffin.core.metric.model.Metric; import org.apache.griffin.core.metric.model.MetricValue; -import org.apache.griffin.core.util.GriffinOperationMessage; -import org.elasticsearch.client.ResponseException; +import org.codehaus.jackson.JsonProcessingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; -import java.util.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; -import static org.apache.griffin.core.util.GriffinOperationMessage.*; +import static org.apache.griffin.core.exception.GriffinExceptionMessage.*; @Service public class MetricServiceImpl implements MetricService { @@ -78,53 +81,49 @@ public class MetricServiceImpl implements MetricService { @Override public List<MetricValue> getMetricValues(String metricName, int offset, int size) { + if (offset < 0) { + throw new GriffinException.BadRequestException(INVALID_METRIC_RECORDS_OFFSET); + } + if (size < 0) { + throw new GriffinException.BadRequestException(INVALID_METRIC_RECORDS_SIZE); + } try { return metricStore.getMetricValues(metricName, offset, size); - } catch (Exception e) { + } catch (IOException e) { LOGGER.error("Failed to get metric values named {}. {}", metricName, e.getMessage()); + throw new GriffinException.ServiceException("Failed to get metric values", e); } - return Collections.emptyList(); } @Override public ResponseEntity addMetricValues(List<MetricValue> values) { for (MetricValue value : values) { - if (!isMetricValueValid(value)) { - LOGGER.warn("Invalid metric value."); - return new ResponseEntity<>(ADD_METRIC_VALUES_FAIL, HttpStatus.BAD_REQUEST); - } + checkFormat(value); } try { - for (MetricValue value : values) { - metricStore.addMetricValue(value); - } - return new ResponseEntity<>(ADD_METRIC_VALUES_SUCCESS, HttpStatus.CREATED); - } catch (ResponseException e) { - LOGGER.error("Failed to add metric values. {}", e.getMessage()); - HttpStatus status = HttpStatus.valueOf(e.getResponse().getStatusLine().getStatusCode()); - return new ResponseEntity<>(ADD_METRIC_VALUES_FAIL, status); - } catch (Exception e) { - LOGGER.error("Failed to add metric values. {}", e.getMessage()); - return new ResponseEntity<>(ADD_METRIC_VALUES_FAIL, HttpStatus.INTERNAL_SERVER_ERROR); + return metricStore.addMetricValues(values); + } catch (JsonProcessingException e) { + LOGGER.warn("Failed to parse metric value.", e.getMessage()); + throw new GriffinException.BadRequestException(INVALID_METRIC_VALUE_FORMAT); + } catch (IOException e) { + LOGGER.error("Failed to add metric values", e); + throw new GriffinException.ServiceException("Failed to add metric values", e); } } - private boolean isMetricValueValid(MetricValue value) { - return StringUtils.isNotBlank(value.getName()) && value.getTmst() != null && MapUtils.isNotEmpty(value.getValue()); - } - @Override - public ResponseEntity<GriffinOperationMessage> deleteMetricValues(String metricName) { + public ResponseEntity deleteMetricValues(String metricName) { try { - metricStore.deleteMetricValues(metricName); - return ResponseEntity.ok(DELETE_METRIC_VALUES_SUCCESS); - } catch (ResponseException e) { - LOGGER.error("Failed to delete metric values named {}. {}", metricName, e.getMessage()); - HttpStatus status = HttpStatus.valueOf(e.getResponse().getStatusLine().getStatusCode()); - return new ResponseEntity<>(DELETE_METRIC_VALUES_FAIL, status); - } catch (Exception e) { + return metricStore.deleteMetricValues(metricName); + } catch (IOException e) { LOGGER.error("Failed to delete metric values named {}. {}", metricName, e.getMessage()); - return new ResponseEntity<>(DELETE_METRIC_VALUES_FAIL, HttpStatus.INTERNAL_SERVER_ERROR); + throw new GriffinException.ServiceException("Failed to delete metric values.", e); + } + } + + private void checkFormat(MetricValue value) { + if (StringUtils.isBlank(value.getName()) || value.getTmst() == null || MapUtils.isEmpty(value.getValue())) { + throw new GriffinException.BadRequestException(INVALID_METRIC_VALUE_FORMAT); } } } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java b/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java index 12068f6..dacac1d 100644 --- a/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java +++ b/service/src/main/java/org/apache/griffin/core/metric/MetricStore.java @@ -20,14 +20,16 @@ under the License. package org.apache.griffin.core.metric; import org.apache.griffin.core.metric.model.MetricValue; +import org.springframework.http.ResponseEntity; +import java.io.IOException; import java.util.List; public interface MetricStore { - List<MetricValue> getMetricValues(String metricName, int from, int size) throws Exception; + List<MetricValue> getMetricValues(String metricName, int from, int size) throws IOException; - void addMetricValue(MetricValue metricValue) throws Exception; + ResponseEntity addMetricValues(List<MetricValue> metricValues) throws IOException; - void deleteMetricValues(String metricName) throws Exception; + ResponseEntity deleteMetricValues(String metricName) throws IOException; } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java b/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java index d055b37..4ddf581 100644 --- a/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java +++ b/service/src/main/java/org/apache/griffin/core/metric/MetricStoreImpl.java @@ -28,12 +28,15 @@ import org.apache.griffin.core.util.JsonUtil; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.entity.ContentType; -import org.apache.http.message.BasicHeader; import org.apache.http.nio.entity.NStringEntity; import org.apache.http.util.EntityUtils; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestClient; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import java.io.IOException; @@ -42,23 +45,36 @@ import java.util.*; @Component public class MetricStoreImpl implements MetricStore { - private RestClient client; + private static final String INDEX = "griffin"; + private static final String TYPE = "accuracy"; + private static final String URL_BASE = "/griffin/accuracy"; - private ObjectMapper mapper = new ObjectMapper(); + private RestClient client; + private HttpHeaders headers; + private String url_get; + private String url_delete; + private String url_post; + private ObjectMapper mapper; - public MetricStoreImpl(@Value("${elasticsearch.host}") String host, @Value("${elasticsearch.port}") int port) throws IOException { + public MetricStoreImpl(@Value("${elasticsearch.host}") String host, @Value("${elasticsearch.port}") int port) { client = RestClient.builder(new HttpHost(host, port, "http")).build(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + this.headers = headers; + this.url_get = URL_BASE + "/_search?filter_path=hits.hits._source"; + this.url_post = URL_BASE + "/_bulk"; + this.url_delete = URL_BASE + "/_delete_by_query"; + this.mapper = new ObjectMapper(); } @Override - public List<MetricValue> getMetricValues(String metricName, int from, int size) throws Exception { - HttpEntity entity = getHttpEntity(metricName, from, size); - Response response = client.performRequest("GET", "/griffin/accuracy/_search?filter_path=hits.hits._source", - Collections.emptyMap(), entity, new BasicHeader("Content-Type", "application/json")); - return getMetricValues(response); + public List<MetricValue> getMetricValues(String metricName, int from, int size) throws IOException { + HttpEntity entity = getHttpEntityForSearch(metricName, from, size); + Response response = client.performRequest("GET", url_get, Collections.emptyMap(), entity); + return getMetricValuesFromResponse(response); } - private HttpEntity getHttpEntity(String metricName, int from, int size) throws JsonProcessingException { + private HttpEntity getHttpEntityForSearch(String metricName, int from, int size) throws JsonProcessingException { Map<String, Object> map = new HashMap<>(); Map<String, Object> queryParam = Collections.singletonMap("term", Collections.singletonMap("name.keyword", metricName)); Map<String, Object> sortParam = Collections.singletonMap("tmst", Collections.singletonMap("order", "desc")); @@ -69,7 +85,7 @@ public class MetricStoreImpl implements MetricStore { return new NStringEntity(JsonUtil.toJson(map), ContentType.APPLICATION_JSON); } - private List<MetricValue> getMetricValues(Response response) throws IOException { + private List<MetricValue> getMetricValuesFromResponse(Response response) throws IOException { List<MetricValue> metricValues = new ArrayList<>(); JsonNode jsonNode = mapper.readTree(EntityUtils.toString(response.getEntity())); if (jsonNode.hasNonNull("hits") && jsonNode.get("hits").hasNonNull("hits")) { @@ -84,19 +100,38 @@ public class MetricStoreImpl implements MetricStore { } @Override - public void addMetricValue(MetricValue metricValue) throws Exception { - HttpEntity entity = new NStringEntity(JsonUtil.toJson(metricValue), ContentType.APPLICATION_JSON); - client.performRequest("POST", "/griffin/accuracy", Collections.emptyMap(), entity, - new BasicHeader("Content-Type", "application/json")); + public ResponseEntity addMetricValues(List<MetricValue> metricValues) throws IOException { + String bulkRequestBody = getBulkRequestBody(metricValues); + HttpEntity entity = new NStringEntity(bulkRequestBody, ContentType.APPLICATION_JSON); + Response response = client.performRequest("POST", url_post, Collections.emptyMap(), entity); + return getResponseEntityFromResponse(response); + + } + private String getBulkRequestBody(List<MetricValue> metricValues) throws JsonProcessingException { + String actionMetaData = String.format("{ \"index\" : { \"_index\" : \"%s\", \"_type\" : \"%s\" } }\n", INDEX, TYPE); + StringBuilder bulkRequestBody = new StringBuilder(); + for (MetricValue metricValue : metricValues) { + bulkRequestBody.append(actionMetaData); + bulkRequestBody.append(JsonUtil.toJson(metricValue)); + bulkRequestBody.append("\n"); + } + return bulkRequestBody.toString(); } + @Override - public void deleteMetricValues(String metricName) throws Exception { + public ResponseEntity deleteMetricValues(String metricName) throws IOException { Map<String, Object> param = Collections.singletonMap("query", Collections.singletonMap("term", Collections.singletonMap("name.keyword", metricName))); HttpEntity entity = new NStringEntity(JsonUtil.toJson(param), ContentType.APPLICATION_JSON); - client.performRequest("POST", "/griffin/accuracy/_delete_by_query", Collections.emptyMap(), - entity, new BasicHeader("Content-Type", "application/json")); + Response response = client.performRequest("POST", url_delete, Collections.emptyMap(), entity); + return getResponseEntityFromResponse(response); + } + + private ResponseEntity getResponseEntityFromResponse(Response response) throws IOException { + String body = EntityUtils.toString(response.getEntity()); + HttpStatus status = HttpStatus.valueOf(response.getStatusLine().getStatusCode()); + return new ResponseEntity<>(body, headers, status); } } http://git-wip-us.apache.org/repos/asf/incubator-griffin/blob/6b1a7000/service/src/main/java/org/apache/griffin/core/util/GriffinOperationMessage.java ---------------------------------------------------------------------- diff --git a/service/src/main/java/org/apache/griffin/core/util/GriffinOperationMessage.java b/service/src/main/java/org/apache/griffin/core/util/GriffinOperationMessage.java deleted file mode 100644 index 86f1aac..0000000 --- a/service/src/main/java/org/apache/griffin/core/util/GriffinOperationMessage.java +++ /dev/null @@ -1,79 +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.griffin.core.util; - - -import com.fasterxml.jackson.annotation.JsonFormat; - -@JsonFormat(shape = JsonFormat.Shape.OBJECT) -public enum GriffinOperationMessage { - //success - CREATE_MEASURE_SUCCESS(201, "Create Measure Succeed"), - DELETE_MEASURE_BY_ID_SUCCESS(202, "Delete Measures By Id Succeed"), - DELETE_MEASURE_BY_NAME_SUCCESS(203, "Delete Measures By Name Succeed"), - UPDATE_MEASURE_SUCCESS(204, "Update Measure Succeed"), - CREATE_JOB_SUCCESS(205, "Create Job Succeed"), - DELETE_JOB_SUCCESS(206, "Delete Job Succeed"), - SET_JOB_DELETED_STATUS_SUCCESS(207, "Set Job Deleted Status Succeed"), - PAUSE_JOB_SUCCESS(208, "Pause Job Succeed"), - UPDATE_JOB_INSTANCE_SUCCESS(209, "Update Job Instance Succeed"), - ADD_METRIC_VALUES_SUCCESS(210, "Add Metric Values Succeed"), - DELETE_METRIC_VALUES_SUCCESS(211, "Delete Metric Values Succeed"), - - //failed - RESOURCE_NOT_FOUND(400, "Resource Not Found"), - CREATE_MEASURE_FAIL(401, "Create Measure Failed"), - DELETE_MEASURE_BY_ID_FAIL(402, "Delete Measures By Id Failed"), - DELETE_MEASURE_BY_NAME_FAIL(403, "Delete Measures By Name Failed"), - UPDATE_MEASURE_FAIL(404, "Update Measure Failed"), - CREATE_JOB_FAIL(405, "Create Job Failed"), - DELETE_JOB_FAIL(406, "Delete Job Failed"), - SET_JOB_DELETED_STATUS_FAIL(407, "Set Job Deleted Status Failed"), - PAUSE_JOB_FAIL(408, "Pause Job Failed"), - UPDATE_JOB_INSTANCE_FAIL(409, "Update Job Instance Failed"), - CREATE_MEASURE_FAIL_DUPLICATE(410, "Create Measure Failed, duplicate records"), - UNEXPECTED_RUNTIME_EXCEPTION(411, "Unexpected RuntimeException"), - ADD_METRIC_VALUES_FAIL(412, "Add Metric Values Failed"), - DELETE_METRIC_VALUES_FAIL(413, "Delete Metric Values Failed"); - - private final int code; - private final String description; - - GriffinOperationMessage(int code, String description) { - this.code = code; - this.description = description; - } - - public int getCode() { - return code; - } - - public String getDescription() { - return description; - } - - @Override - public String toString() { - return "GriffinOperationMessage{" + - "code=" + code + - ", description='" + description + '\'' + - '}'; - } -}
