From accf85a160d8032786ff97d4b4c04d5d4740afee Mon Sep 17 00:00:00 2001 From: Achille Date: Fri, 5 Oct 2018 21:56:56 -0400 Subject: [PATCH] Initial commit: coding test --- configurationapp/pom.xml | 26 +++ .../dao/configurations/ConfigurationDao.java | 38 +++- .../att/data/configurations/ConfigValue.java | 8 + .../ConfigurationException.java | 37 ++++ .../ErrorHandlingController.java | 38 ++++ .../exceptionHandling/ExceptionResponse.java | 31 ++++ .../restapi/configurations/SwaggerConfig.java | 47 +++++ .../ConfigurationController.java | 84 +++++++-- .../src/main/resources/static/index.html | 169 ++++++++++++++---- .../src/main/resources/static/js/app.js | 2 +- 10 files changed, 425 insertions(+), 55 deletions(-) create mode 100644 configurationapp/src/main/java/com/att/exceptionHandling/ConfigurationException.java create mode 100644 configurationapp/src/main/java/com/att/exceptionHandling/ErrorHandlingController.java create mode 100644 configurationapp/src/main/java/com/att/exceptionHandling/ExceptionResponse.java create mode 100644 configurationapp/src/main/java/com/att/restapi/configurations/SwaggerConfig.java diff --git a/configurationapp/pom.xml b/configurationapp/pom.xml index 78931d3..4492ebf 100644 --- a/configurationapp/pom.xml +++ b/configurationapp/pom.xml @@ -21,6 +21,7 @@ UTF-8 UTF-8 1.8 + true @@ -39,6 +40,24 @@ spring-boot-starter-test test + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + org.springframework + spring-web + + @@ -47,6 +66,13 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipTests} + + configurationapp diff --git a/configurationapp/src/main/java/com/att/dao/configurations/ConfigurationDao.java b/configurationapp/src/main/java/com/att/dao/configurations/ConfigurationDao.java index f889558..3c6af6f 100644 --- a/configurationapp/src/main/java/com/att/dao/configurations/ConfigurationDao.java +++ b/configurationapp/src/main/java/com/att/dao/configurations/ConfigurationDao.java @@ -1,3 +1,6 @@ +/** + * The Company Privacy & Copy Right message goes here + */ package com.att.dao.configurations; import com.att.data.configurations.ConfigValue; @@ -8,6 +11,7 @@ import java.util.List; import java.util.Map; + @Service public class ConfigurationDao { private class IdProvider { @@ -33,16 +37,40 @@ public ConfigurationDao() { currentConfigurations = new HashMap<>(); } - public List getConfigurationsForYearMonth(String yearMonth) { - return new ArrayList<>(); - } +public List getConfigurationsForYearMonth(String yearMonth) { + if(currentConfigurations.containsKey(yearMonth)) { + return currentConfigurations.get(yearMonth); + } + return null; + } - public void addConfiguration(String yearMonth, ConfigValue value) { + public ConfigValue addConfiguration(String yearMonth, ConfigValue value) { int newId = idProvider.getNextId(); + value.setConfigId(newId); + if(currentConfigurations.containsKey(yearMonth)) { + currentConfigurations.get(yearMonth).add(value); + } else { + List configValues = new ArrayList(); + configValues.add(value); + currentConfigurations.put(yearMonth, configValues); + } + return value; } - public void removeAllConfigurationsForYearMonth(String yearMonth) { + if(currentConfigurations.containsKey(yearMonth)) { + currentConfigurations.get(yearMonth).clear(); + } + } + public void removeConfigurationsForYearMonth(int configId, String yearMonth) { + if(currentConfigurations.containsKey(yearMonth)) { + ConfigValue configValueSelected = currentConfigurations.get(yearMonth) + .stream() + .filter(c -> c.getConfigId() == configId) + .findFirst() + .get(); + currentConfigurations.get(yearMonth).remove(configValueSelected); + } } } diff --git a/configurationapp/src/main/java/com/att/data/configurations/ConfigValue.java b/configurationapp/src/main/java/com/att/data/configurations/ConfigValue.java index 55339a3..c155b16 100644 --- a/configurationapp/src/main/java/com/att/data/configurations/ConfigValue.java +++ b/configurationapp/src/main/java/com/att/data/configurations/ConfigValue.java @@ -1,9 +1,17 @@ package com.att.data.configurations; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + /** * Data Model */ public class ConfigValue { + + @NotNull + @NotEmpty private String configName; private int configId; diff --git a/configurationapp/src/main/java/com/att/exceptionHandling/ConfigurationException.java b/configurationapp/src/main/java/com/att/exceptionHandling/ConfigurationException.java new file mode 100644 index 0000000..983b259 --- /dev/null +++ b/configurationapp/src/main/java/com/att/exceptionHandling/ConfigurationException.java @@ -0,0 +1,37 @@ +package com.att.exceptionHandling; + +import com.att.web.configuarations.ConfigurationController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Created by Achille on 10/5/2018. + */ +public class ConfigurationException extends Exception{ + + private static final long serialVersionUID = 1L; + private int code; + private String message; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} + + diff --git a/configurationapp/src/main/java/com/att/exceptionHandling/ErrorHandlingController.java b/configurationapp/src/main/java/com/att/exceptionHandling/ErrorHandlingController.java new file mode 100644 index 0000000..530cecb --- /dev/null +++ b/configurationapp/src/main/java/com/att/exceptionHandling/ErrorHandlingController.java @@ -0,0 +1,38 @@ +package com.att.exceptionHandling; + +import com.att.web.configuarations.ConfigurationController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Created by Achille on 10/5/2018. + */ +@ControllerAdvice +public class ErrorHandlingController { + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationController.class); + + @ExceptionHandler(Exception.class) + public ResponseEntity generalException(Exception excception) { + ExceptionResponse ex = new ExceptionResponse(); + ex.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); + ex.setDescription(excception.getMessage()); + LOGGER.error(excception.getMessage(),excception.getStackTrace()); + return new ResponseEntity(ex, HttpStatus.INTERNAL_SERVER_ERROR); + } + + @ExceptionHandler(ConfigurationException.class) + public ResponseEntity configurationlException(Exception excception) { + ExceptionResponse ex = new ExceptionResponse(); + ex.setCode(HttpStatus.BAD_REQUEST.value()); + ex.setDescription(excception.getMessage()); + LOGGER.error(excception.getMessage(),excception.getStackTrace()); + + return new ResponseEntity(ex, HttpStatus.BAD_REQUEST); + } +} + + diff --git a/configurationapp/src/main/java/com/att/exceptionHandling/ExceptionResponse.java b/configurationapp/src/main/java/com/att/exceptionHandling/ExceptionResponse.java new file mode 100644 index 0000000..f5742df --- /dev/null +++ b/configurationapp/src/main/java/com/att/exceptionHandling/ExceptionResponse.java @@ -0,0 +1,31 @@ +package com.att.exceptionHandling; + +/** + * Created by Achille on 10/5/2018. + */ +public class ExceptionResponse extends Exception { + + + private static final long serialVersionUID = 1L; + private int code; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + private String description; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/configurationapp/src/main/java/com/att/restapi/configurations/SwaggerConfig.java b/configurationapp/src/main/java/com/att/restapi/configurations/SwaggerConfig.java new file mode 100644 index 0000000..882b9f9 --- /dev/null +++ b/configurationapp/src/main/java/com/att/restapi/configurations/SwaggerConfig.java @@ -0,0 +1,47 @@ +package com.att.restapi.configurations; + +/** + * Created by Achille on 10/5/2018. + */ +import com.att.web.configuarations.ConfigurationController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@PropertySource("classpath:swagger.properties") +@ComponentScan(basePackageClasses = ConfigurationController.class) +@Configuration +public class SwaggerConfig { + + private static final String SWAGGER_API_VERSION = "1.0"; + private static final String LICENSE_TEXT = "License"; + private static final String title = "ConfigurationController REST API"; + private static final String description = "RESTful API for ConfigurationController"; + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title(title) + .description(description) + .license(LICENSE_TEXT) + .version(SWAGGER_API_VERSION) + .build(); + } + + @Bean + public Docket productsApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .pathMapping("/") + .select() + .paths(PathSelectors.regex("/api.*")) + .build(); + } +} \ No newline at end of file diff --git a/configurationapp/src/main/java/com/att/web/configuarations/ConfigurationController.java b/configurationapp/src/main/java/com/att/web/configuarations/ConfigurationController.java index 995402a..669e8f6 100644 --- a/configurationapp/src/main/java/com/att/web/configuarations/ConfigurationController.java +++ b/configurationapp/src/main/java/com/att/web/configuarations/ConfigurationController.java @@ -1,17 +1,42 @@ +/** + * The Company Privacy & Copy Right message goes here + */ package com.att.web.configuarations; import com.att.dao.configurations.ConfigurationDao; import com.att.data.configurations.ConfigValue; +import com.att.exceptionHandling.ConfigurationException; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import javax.validation.Valid; import java.util.ArrayList; import java.util.List; +/** + * The purpose of this class is to provide CRUD functionality below by exposing REST API endpoints. + * + * Following CRUD operations are implemented: + * 1. Display whatever is currently configured (not having a configuration is not an error) in a grid. + * 2. Add new configurations for a time period. + * 3. Relete all the configurations for a time period. + * 4. Remove a single configuration for a time period. + * + */ @RestController -@RequestMapping(value="/configuration") +@RequestMapping(value = "/api/configuration") +@Api(value = "ConfigurationControllerAPI", produces = MediaType.APPLICATION_JSON_VALUE) public class ConfigurationController { + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationController.class); + private ConfigurationDao dao; @Autowired @@ -19,27 +44,62 @@ public ConfigurationController(ConfigurationDao dao) { this.dao = dao; } - @RequestMapping(value="/{yearMonthNumber}", method=RequestMethod.GET) + @RequestMapping(value = "/findBy/{yearMonthNumber}", method = RequestMethod.GET) @ResponseBody public List getConfigurationsForYearMonth( @PathVariable("yearMonthNumber") String yearMonth) { - - return new ArrayList<>(); + try { + return dao.getConfigurationsForYearMonth(yearMonth); + } catch (Exception e) { + LOGGER.error(e.getMessage()); + } + return null; } - @RequestMapping(value="/{yearMonthNumber}", method=RequestMethod.DELETE) + /** + * Delete all the configurations for a time period. + * + * @param yearMonth + */ + @RequestMapping(value = "/deleteall/{yearMonthNumber}", method = RequestMethod.DELETE) public void deleteConfigurationsForYearMonth(@PathVariable("yearMonthNumber") String yearMonth) { try { - - } catch (Exception ex) { - + dao.removeAllConfigurationsForYearMonth(yearMonth); + } catch (Exception e) { + LOGGER.error(e.getMessage()); } } - @RequestMapping(value="/{yearMonthNumber}", method={ RequestMethod.POST, RequestMethod.PUT }) - public void addConfigurationForYearMonth( - @PathVariable("yearMonthNumber") String yearMonth, - @RequestBody ConfigValue value) { + /** + * Remove a single configuration for a time period + * + * @param configId + * @param yearMonth + */ + @RequestMapping(value = "/delete/{configId}/{yearMonthNumber}", method = RequestMethod.DELETE) + public void deleteConfigurationsForYearMonth( + @PathVariable("configId") int configId, + @PathVariable("yearMonthNumber") String yearMonth) { + try { + dao.removeConfigurationsForYearMonth(configId, yearMonth); + } catch (Exception e) { + LOGGER.error(e.getMessage()); + } + } + /** + * Add new configurations for a time period. + * + * @param yearMonth + * @param value + * @return ConfigValue + */ + @RequestMapping(value = "/add/{yearMonthNumber}", method = { RequestMethod.POST, RequestMethod.PUT }) + @ApiOperation("Return the ConfigValue persisted with id") + @ApiResponses(value = {@ApiResponse(code = 200, message = "OK", response = ConfigValue.class)}) + public ConfigValue addConfigurationForYearMonth( + @PathVariable("yearMonthNumber") String yearMonth, @Valid + @RequestBody ConfigValue value) throws ConfigurationException { + return dao.addConfiguration(yearMonth, value); } } diff --git a/configurationapp/src/main/resources/static/index.html b/configurationapp/src/main/resources/static/index.html index 7cd14ba..a28590c 100644 --- a/configurationapp/src/main/resources/static/index.html +++ b/configurationapp/src/main/resources/static/index.html @@ -1,47 +1,142 @@ - Configuration App - - - - +Configuration App + + + + + + + -

Welcome To The Configuration App

-
-
- -
-
- - - - - - - - - - -
Configuration IdConfiguration Name
-
-
- -
-
- \ No newline at end of file diff --git a/configurationapp/src/main/resources/static/js/app.js b/configurationapp/src/main/resources/static/js/app.js index 2d4b945..4cc5e56 100644 --- a/configurationapp/src/main/resources/static/js/app.js +++ b/configurationapp/src/main/resources/static/js/app.js @@ -4,7 +4,7 @@ } App.prototype.getData = function() { - $.ajax('',{ + $.ajax('http://localhost:9000/api/configuration/findBy/012018',{ }).then(function(data) {