From a71f5c6c357b4a52dee3a70efa4e2eaa33ecc066 Mon Sep 17 00:00:00 2001 From: anirban das Date: Thu, 18 Mar 2021 06:17:47 +0530 Subject: [PATCH] modified response type of car and polygon services to return detailed cars and strategic respectively, cars are returned in the list by car service sorted according to their vin, implemented end to end flows of position service, impleemnted algorithm to check if a poijht lies within a polygon in position service, implemented unit tests for verifying car and polygon placement algorithm with all edge cases, added networking attributes, host names in docker compose --- .../car/controller/CarSearchController.java | 10 ++ .../sharenow/car/model/entity/CarEntity.java | 7 +- .../sharenow/car/model/vo/CarDetailsVO.java | 6 +- .../sharenow/car/service/CarService.java | 3 + .../car/service/impl/CarServiceImpl.java | 14 ++ .../gateway-service-development.properties | 5 +- .../gateway-service-staging.properties | 3 + .../position-service-development.properties | 6 +- .../position-service-staging.properties | 4 +- docker-compose-1.yml | 50 ++++++ docker-compose.yml | 58 +++++- gateway-service/pom.xml | 4 + .../GatewayServiceConfiguration.java | 16 -- .../src/main/resources/bootstrap.properties | 2 +- .../impl/Car2GoCarRefreshServiceImpl.java | 2 +- .../controller/PolygonSearchController.java | 12 +- .../polygon/model/dto/GeoFeatureDTO.java | 4 +- .../model/dto/StrategicPolygonDTO.java | 3 +- .../model/entity/GeoFeatureEntity.java | 4 +- .../model/entity/StrategicPolygonEntity.java | 4 +- .../polygon/model/vo/GeoFeatureVO.java | 4 +- .../model/vo/StrategicPolygonDetailedVO.java | 3 +- .../polygon/service/PolygonService.java | 6 +- .../service/impl/PolygonServiceImpl.java | 18 +- .../controller/PositionSearchController.java | 36 ++++ .../filter/RestServiceErrorHandler.java | 2 +- .../sharenow/position/model/Orientation.java | 9 + .../car/{CarDetailsVO.java => CarDTO.java} | 10 +- .../car/{CarVO.java => CarDetailsDTO.java} | 10 +- .../dto/car/{ErrorVO.java => ErrorDTO.java} | 2 +- .../dto/car/PositionDTO.java} | 8 +- ...ionsVO.java => ActiveTimedOptionsDTO.java} | 2 +- .../{ComputedVO.java => ComputedDTO.java} | 4 +- .../polygon/{ErrorVO.java => ErrorDTO.java} | 2 +- .../model/dto/polygon/GeoFeatureDTO.java | 19 ++ .../{OptionsVO.java => OptionsDTO.java} | 2 +- ...olygonVO.java => StrategicPolygonDTO.java} | 4 +- .../polygon/StrategicPolygonDetailedDTO.java | 22 +++ .../polygon/StrategicPolygonDetailedVO.java | 36 ---- ...medOptionsVO.java => TimedOptionsDTO.java} | 2 +- .../model/error/PositionErrorCode.java | 8 +- .../Car2StrategicPolygonPositioningVO.java | 18 ++ .../position/model/vo/car/CarMappedVO.java | 19 ++ .../model/{dto => vo}/car/PositionVO.java | 2 +- .../{dto => vo}/polygon/GeoFeatureVO.java | 6 +- .../StrategicPolygon2CarPositioningVO.java | 34 ++++ .../StrategicPolygonMappedComplexVO.java | 25 +++ .../vo/polygon/StrategicPolygonMappedVO.java | 23 +++ .../sharenow/position/quadtree/Point.java | 17 -- .../sharenow/position/quadtree/Quad.java | 170 ------------------ .../position/repository/CarServiceClient.java | 14 +- .../repository/PolygonServiceClient.java | 19 +- .../position/service/PlacementService.java | 13 ++ .../position/service/PositionService.java | 11 ++ .../service/impl/PlacementServiceImpl.java | 115 ++++++++++++ .../service/impl/PositionServiceImpl.java | 158 +++++++++++++++- .../src/main/resources/messages.properties | 7 +- .../service/PlacementServiceTests.java | 159 ++++++++++++++++ 58 files changed, 902 insertions(+), 334 deletions(-) create mode 100644 docker-compose-1.yml delete mode 100644 gateway-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/gateway/configuration/GatewayServiceConfiguration.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/Orientation.java rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/{CarDetailsVO.java => CarDTO.java} (64%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/{CarVO.java => CarDetailsDTO.java} (51%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/{ErrorVO.java => ErrorDTO.java} (92%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/{quadtree/Node.java => model/dto/car/PositionDTO.java} (51%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{ActiveTimedOptionsVO.java => ActiveTimedOptionsDTO.java} (89%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{ComputedVO.java => ComputedDTO.java} (68%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{ErrorVO.java => ErrorDTO.java} (92%) create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureDTO.java rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{OptionsVO.java => OptionsDTO.java} (88%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{StrategicPolygonVO.java => StrategicPolygonDTO.java} (85%) create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedDTO.java delete mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedVO.java rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/{TimedOptionsVO.java => TimedOptionsDTO.java} (85%) create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/Car2StrategicPolygonPositioningVO.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/CarMappedVO.java rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/{dto => vo}/car/PositionVO.java (95%) rename position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/{dto => vo}/polygon/GeoFeatureVO.java (77%) create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygon2CarPositioningVO.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedComplexVO.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedVO.java delete mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Point.java delete mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Quad.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementService.java create mode 100644 position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PlacementServiceImpl.java create mode 100644 position-service/src/test/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementServiceTests.java diff --git a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/controller/CarSearchController.java b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/controller/CarSearchController.java index e5c4b8b..67be814 100644 --- a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/controller/CarSearchController.java +++ b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/controller/CarSearchController.java @@ -14,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.Set; @RestController @RequestMapping("search") @@ -42,4 +43,13 @@ public ResponseEntity getAllCars() throws CarServiceException { return response; } + @GetMapping("withdetails") + public ResponseEntity getAllCarsWithDetails() throws CarServiceException { + LOGGER.info("Requesting all cars and their details"); + Set voList = this.service.retrieveAllCarsWithDetails(); + ResponseEntity> response = ResponseEntity.ok(voList); + LOGGER.info("Responding with all available cars and their details"); + return response; + } + } diff --git a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/entity/CarEntity.java b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/entity/CarEntity.java index d4fad02..67463b8 100644 --- a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/entity/CarEntity.java +++ b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/entity/CarEntity.java @@ -1,9 +1,6 @@ package com.teenthofabud.codingchallenge.sharenow.car.model.entity; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; +import lombok.*; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.redis.core.RedisHash; @@ -18,6 +15,7 @@ @RedisHash("Car") @TypeAlias("Car") @NoArgsConstructor +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class CarEntity implements Serializable { @Indexed @@ -25,6 +23,7 @@ public class CarEntity implements Serializable { private int locationId; @Id @Indexed + @EqualsAndHashCode.Include private String vin; private String numberPlate; private PositionEntity position; diff --git a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/vo/CarDetailsVO.java b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/vo/CarDetailsVO.java index e6e27b1..0ad41b5 100644 --- a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/vo/CarDetailsVO.java +++ b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/model/vo/CarDetailsVO.java @@ -5,7 +5,7 @@ @Getter @Setter -public class CarDetailsVO { +public class CarDetailsVO implements Comparable { private int id; private int locationId; @@ -15,4 +15,8 @@ public class CarDetailsVO { private float fuel; private String model; + @Override + public int compareTo(CarDetailsVO o) { + return this.vin.compareTo(o.getVin()); + } } diff --git a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/CarService.java b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/CarService.java index fa1a280..598dcec 100644 --- a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/CarService.java +++ b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/CarService.java @@ -6,12 +6,15 @@ import org.springframework.stereotype.Service; import java.util.List; +import java.util.Set; @Service public interface CarService { public List retrieveAllCars(); + public Set retrieveAllCarsWithDetails(); + public CarDetailsVO retrieveCarDetailsByVin(String vin) throws CarServiceException; } diff --git a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/impl/CarServiceImpl.java b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/impl/CarServiceImpl.java index 8e5e2a4..18321a8 100644 --- a/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/impl/CarServiceImpl.java +++ b/car-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/car/service/impl/CarServiceImpl.java @@ -92,6 +92,20 @@ public List retrieveAllCars() { return carVOList; } + @Override + public Set retrieveAllCarsWithDetails() { + Set carVOList = new TreeSet<>(); + Iterable entityItr = this.repository.findAll(); + for(CarEntity entity : entityItr) { + if(entity != null && StringUtils.hasText(entity.getVin())) { + CarDetailsVO vo = this.complexVOConverter.convert(entity); + carVOList.add(vo); + } + } + LOGGER.info("Found {} cars", carVOList.size()); + return carVOList; + } + @Override public CarDetailsVO retrieveCarDetailsByVin(String vin) throws CarServiceException { if(StringUtils.hasText(vin)) { diff --git a/configuration-service/src/main/resources/configuration-store/gateway-service-development.properties b/configuration-service/src/main/resources/configuration-store/gateway-service-development.properties index e569dfc..a513e54 100644 --- a/configuration-service/src/main/resources/configuration-store/gateway-service-development.properties +++ b/configuration-service/src/main/resources/configuration-store/gateway-service-development.properties @@ -15,16 +15,17 @@ spring.cloud.gateway.discovery.locator.enabled=true spring.cloud.gateway.routes[0].id=car-service spring.cloud.gateway.routes[0].uri=lb://car-service spring.cloud.gateway.routes[0].predicates[0]=Path=/car-service/** +spring.cloud.gateway.routes[0].filters[0]=RewritePath=/car-service(?/?.*), ${segment} spring.cloud.gateway.routes[1].id=polygon-service spring.cloud.gateway.routes[1].uri=lb://polygon-service -#spring.cloud.gateway.routes[1].predicates[0]=Path=/polygon-service/** spring.cloud.gateway.routes[1].predicates[0]=Path=/polygon/** -#spring.cloud.gateway.routes[1].filters[0]=RewritePath=/polygon-service/(?.*), /polygon-service/${segment} +spring.cloud.gateway.routes[1].filters[0]=RewritePath=/polygon(?/?.*), ${segment} spring.cloud.gateway.routes[2].id=position-service spring.cloud.gateway.routes[2].uri=lb://position-service spring.cloud.gateway.routes[2].predicates[0]=Path=/position-service/** +spring.cloud.gateway.routes[2].filters[0]=RewritePath=/position-service(?/?.*), ${segment} eureka.instance.prefer-ip-address=true diff --git a/configuration-service/src/main/resources/configuration-store/gateway-service-staging.properties b/configuration-service/src/main/resources/configuration-store/gateway-service-staging.properties index 1160032..2107d5b 100644 --- a/configuration-service/src/main/resources/configuration-store/gateway-service-staging.properties +++ b/configuration-service/src/main/resources/configuration-store/gateway-service-staging.properties @@ -16,12 +16,15 @@ eureka.client.service-url.defaultZone=${NAMING_SERVER_URL}/eureka spring.cloud.gateway.routes[0].id=car-service spring.cloud.gateway.routes[0].uri=lb://car-service spring.cloud.gateway.routes[0].predicates[0]=Path=/car-service/** +spring.cloud.gateway.routes[0].filters[0]=RewritePath=/car-service(?/?.*), ${segment} spring.cloud.gateway.routes[1].id=polygon-service spring.cloud.gateway.routes[1].uri=lb://polygon-service spring.cloud.gateway.routes[1].predicates[0]=Path=/polygon-service/** +spring.cloud.gateway.routes[1].filters[0]=RewritePath=/polygon-service(?/?.*), ${segment} spring.cloud.gateway.routes[2].id=position-service spring.cloud.gateway.routes[2].uri=lb://position-service spring.cloud.gateway.routes[2].predicates[0]=Path=/position-service/** +spring.cloud.gateway.routes[2].filters[0]=RewritePath=/position-service(?/?.*), ${segment} diff --git a/configuration-service/src/main/resources/configuration-store/position-service-development.properties b/configuration-service/src/main/resources/configuration-store/position-service-development.properties index daee59d..a6866eb 100644 --- a/configuration-service/src/main/resources/configuration-store/position-service-development.properties +++ b/configuration-service/src/main/resources/configuration-store/position-service-development.properties @@ -7,7 +7,9 @@ spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) spring.zipkin.baseUrl=http://localhost:9411 -poss.polygon-service.url=http://polygon-service -poss.car-service.url=http://car-service +poss.polygon-service.url=localhost:18080 +poss.car-service.url=localhost:17080 + +poss.placement.infinite.end.limit=1000 eureka.instance.prefer-ip-address=true \ No newline at end of file diff --git a/configuration-service/src/main/resources/configuration-store/position-service-staging.properties b/configuration-service/src/main/resources/configuration-store/position-service-staging.properties index db413dc..916f4df 100644 --- a/configuration-service/src/main/resources/configuration-store/position-service-staging.properties +++ b/configuration-service/src/main/resources/configuration-store/position-service-staging.properties @@ -12,4 +12,6 @@ spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) spring.zipkin.baseUrl=${TRACING_SERVER_URL} poss.polygon-service.url=${POLYGON_SERVICE_URL} -poss.car-service.url=${CAR_SERVICE_URL} \ No newline at end of file +poss.car-service.url=${CAR_SERVICE_URL} + +poss.placement.infinite.end.limit=1000 \ No newline at end of file diff --git a/docker-compose-1.yml b/docker-compose-1.yml new file mode 100644 index 0000000..96b6625 --- /dev/null +++ b/docker-compose-1.yml @@ -0,0 +1,50 @@ +version: "3.9" + +services: + + documentdb-service: + image: mongo:4.4-bionic + container_name: documentdb-service + hostname: documentdb-service + volumes: + - "/data/db:/opt/sharenow-coding-challenge-data/mongodb" + ports: + - "27017:27017" + + naming-service: + image: teenthofabud/sharenow-coding-challenge-naming-service:1.0.0-SNAPSHOT + container_name: naming-service + hostname: naming-service + ports: + - "8761:8761" + + configuration-service: + image: teenthofabud/sharenow-coding-challenge-configuration-service:1.0.0-SNAPSHOT + container_name: configuration-service + hostname: configuration-service + ports: + - "8888:8888" + + tracing-service: + image: openzipkin/zipkin + container_name: tracing-service + hostname: tracing-service + ports: + - "9411:9411" + + polygon-service: + image: teenthofabud/sharenow-coding-challenge-polygon-service:1.0.0-SNAPSHOT + container_name: polygon-service + hostname: polygon-service + environment: + - PROFILE=staging + - DOCUMENTDB_SERVER_HOST=documentdb-service + - DOCUMENTDB_SERVER_PORT=27017 + - TRACING_SERVER_URL=http://tracing-service:9411 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 + - NAMING_SERVER_URL=http://naming-service:8761 + depends_on: + - documentdb-service + - configuration-service + - naming-service + - tracing-service \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2910552..b121203 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,47 +5,72 @@ services: cache-service: image: redis:3.0.7-alpine container_name: cache-service + hostname: cache-service ports: - "6379:6379" + networks: + - car documentdb-service: image: mongo:4.4-bionic container_name: documentdb-service + hostname: documentdb-service volumes: - "/data/db:/opt/sharenow-coding-challenge-data/mongodb" ports: - "27017:27017" + networks: + - polygon tracing-service: image: openzipkin/zipkin container_name: tracing-service + hostname: tracing-service ports: - "9411:9411" + networks: + - car + - polygon car2godeveloper-service: image: car2godeveloper/api-for-coding-challenge container_name: car2godeveloper-service + hostname: car2godeveloper-service ports: - "3000:3000" + networks: + - car naming-service: image: teenthofabud/sharenow-coding-challenge-naming-service:1.0.0-SNAPSHOT container_name: naming-service + hostname: naming-service ports: - "8761:8761" + networks: + - car + - polygon configuration-service: image: teenthofabud/sharenow-coding-challenge-configuration-service:1.0.0-SNAPSHOT container_name: configuration-service + hostname: configuration-service ports: - "8888:8888" + networks: + - car + - polygon gateway-service: image: teenthofabud/sharenow-coding-challenge-gateway-service:1.0.0-SNAPSHOT container_name: gateway-service + hostname: gateway-service + networks: + - car + - polygon environment: - PROFILE=staging - - CONFIGURATION_SERVER_URL=http://configuration-service/8888 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 - NAMING_SERVER_URL=http://naming-service:8761 depends_on: - configuration-service @@ -56,11 +81,14 @@ services: polling-service: image: teenthofabud/sharenow-coding-challenge-polling-service:1.0.0-SNAPSHOT container_name: polling-service + hostname: polling-service + networks: + - car environment: - PROFILE=staging - CACHE_SERVER_HOST=cache-service - CACHE_SERVER_PORT=6379 - - CONFIGURATION_SERVER_URL=http://configuration-service/8888 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 - NAMING_SERVER_URL=http://naming-service:8761 - CAR2GO_SERVER_URL=http://car2godeveloper-service:3000 depends_on: @@ -73,12 +101,15 @@ services: car-service: image: teenthofabud/sharenow-coding-challenge-car-service:1.0.0-SNAPSHOT container_name: car-service + hostname: car-service + networks: + - car environment: - PROFILE=staging - CACHE_SERVER_HOST=cache-service - CACHE_SERVER_PORT=6379 - TRACING_SERVER_URL=http://tracing-service:9411 - - CONFIGURATION_SERVER_URL=http://configuration-service/8888 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 - NAMING_SERVER_URL=http://naming-service:8761 depends_on: - cache-service @@ -91,12 +122,15 @@ services: polygon-service: image: teenthofabud/sharenow-coding-challenge-polygon-service:1.0.0-SNAPSHOT container_name: polygon-service + hostname: polygon-service + networks: + - polygon environment: - PROFILE=staging - DOCUMENTDB_SERVER_HOST=documentdb-service - DOCUMENTDB_SERVER_PORT=27017 - TRACING_SERVER_URL=http://tracing-service:9411 - - CONFIGURATION_SERVER_URL=http://configuration-service/8888 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 - NAMING_SERVER_URL=http://naming-service:8761 depends_on: - documentdb-service @@ -108,17 +142,25 @@ services: position-service: image: teenthofabud/sharenow-coding-challenge-position-service:1.0.0-SNAPSHOT container_name: position-service + hostname: position-service + networks: + - car + - polygon environment: - PROFILE=staging - TRACING_SERVER_URL=http://tracing-service:9411 - - CONFIGURATION_SERVER_URL=http://configuration-service/8888 + - CONFIGURATION_SERVER_URL=http://configuration-service:8888 - NAMING_SERVER_URL=http://naming-service:8761 - - CAR_SERVICE_URL=http://car-service - - POLYGON_SERVICE_URL=http://polygon-service + - CAR_SERVICE_URL=car-service + - POLYGON_SERVICE_URL=polygon-service depends_on: - tracing-service - car-service - polygon-service - configuration-service - naming-service - - gateway-service \ No newline at end of file + - gateway-service + +networks: + car: + polygon: \ No newline at end of file diff --git a/gateway-service/pom.xml b/gateway-service/pom.xml index e8957e5..910b175 100644 --- a/gateway-service/pom.xml +++ b/gateway-service/pom.xml @@ -54,6 +54,10 @@ org.springframework.cloud spring-cloud-starter-gateway + + org.springframework.boot + spring-boot-starter-webflux + org.springframework.cloud spring-cloud-starter-netflix-eureka-client diff --git a/gateway-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/gateway/configuration/GatewayServiceConfiguration.java b/gateway-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/gateway/configuration/GatewayServiceConfiguration.java deleted file mode 100644 index 4075661..0000000 --- a/gateway-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/gateway/configuration/GatewayServiceConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -package com.teenthofabud.codingchallenge.sharenow.gateway.configuration; - -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; -import org.springframework.context.annotation.Bean; -import org.springframework.http.codec.ServerCodecConfigurer; -import org.springframework.http.codec.support.DefaultServerCodecConfigurer; -import org.springframework.stereotype.Component; - -@Component -public class GatewayServiceConfiguration { - - - -} -*/ diff --git a/gateway-service/src/main/resources/bootstrap.properties b/gateway-service/src/main/resources/bootstrap.properties index 35b679b..e4c62a4 100644 --- a/gateway-service/src/main/resources/bootstrap.properties +++ b/gateway-service/src/main/resources/bootstrap.properties @@ -1,4 +1,4 @@ spring.application.name=gateway-service spring.profiles.active=development spring.cloud.config.enabled=true -#spring.cloud.config.uri=http://localhost:8888 \ No newline at end of file +spring.cloud.config.uri=http://localhost:8888 \ No newline at end of file diff --git a/polling-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polling/refresh/service/impl/Car2GoCarRefreshServiceImpl.java b/polling-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polling/refresh/service/impl/Car2GoCarRefreshServiceImpl.java index 63f03d3..6066e71 100644 --- a/polling-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polling/refresh/service/impl/Car2GoCarRefreshServiceImpl.java +++ b/polling-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polling/refresh/service/impl/Car2GoCarRefreshServiceImpl.java @@ -55,7 +55,7 @@ public class Car2GoCarRefreshServiceImpl implements CarRefreshService { @Value("${ps.refresh.search.location}") private String searchLocation; - @Value("${car2go.base.url:localhost}") + @Value("${car2go.base.url}") private String car2goBaseURL; @Value("${car2go.vehicles.by.location.uri}") diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/controller/PolygonSearchController.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/controller/PolygonSearchController.java index 2f4040e..9d53fb9 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/controller/PolygonSearchController.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/controller/PolygonSearchController.java @@ -36,8 +36,8 @@ public ResponseEntity getAllPolygons() { @GetMapping("cityid/{cityId}") public ResponseEntity getAllPolygonsByCityId(@PathVariable String cityId) throws PolygonServiceException { LOGGER.info("Requesting all polygons with cityId: {}", cityId); - List voList = this.service.retrieveByCityId(cityId); - ResponseEntity> response = ResponseEntity.ok(voList); + List voList = this.service.retrieveByCityId(cityId); + ResponseEntity> response = ResponseEntity.ok(voList); LOGGER.info("Responding with all available polygons with cityId: {}", cityId); return response; } @@ -45,8 +45,8 @@ public ResponseEntity getAllPolygonsByCityId(@PathVariable String cityId) thr @GetMapping("type/{type}") public ResponseEntity getAllPolygonsByType(@PathVariable String type) throws PolygonServiceException { LOGGER.info("Requesting all polygons of type: {}", type); - List voList = this.service.retrieveByType(type); - ResponseEntity> response = ResponseEntity.ok(voList); + List voList = this.service.retrieveByType(type); + ResponseEntity> response = ResponseEntity.ok(voList); LOGGER.info("Responding with all available polygons with type: {}", type); return response; } @@ -54,8 +54,8 @@ public ResponseEntity getAllPolygonsByType(@PathVariable String type) throws @GetMapping("name/{name}") public ResponseEntity getPolygonByName(@PathVariable String name) throws PolygonServiceException { LOGGER.info("Requesting all polygons with name: {}", name); - List voList = this.service.retrieveByName(name); - ResponseEntity> response = ResponseEntity.ok(voList); + List voList = this.service.retrieveByName(name); + ResponseEntity> response = ResponseEntity.ok(voList); LOGGER.info("Responding with all available polygons with name: {}", name); return response; } diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/GeoFeatureDTO.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/GeoFeatureDTO.java index 1c9c171..b3d7b69 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/GeoFeatureDTO.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/GeoFeatureDTO.java @@ -4,7 +4,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.geojson.GeoJsonObject; +import org.geojson.Point; import java.io.Serializable; @@ -14,6 +14,6 @@ public class GeoFeatureDTO implements Serializable { private String name; - private GeoJsonObject geometry; + private Point geometry; } diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/StrategicPolygonDTO.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/StrategicPolygonDTO.java index 50079f1..5dee616 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/StrategicPolygonDTO.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/dto/StrategicPolygonDTO.java @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import org.geojson.GeoJsonObject; +import org.geojson.Polygon; import java.io.Serializable; import java.util.Date; @@ -27,7 +28,7 @@ public class StrategicPolygonDTO implements Serializable { private String type; private List geoFeatures; private OptionsDTO options; - private GeoJsonObject geometry; + private Polygon geometry; private int version; @JsonProperty("$computed") private ComputedDTO computed; diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/GeoFeatureEntity.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/GeoFeatureEntity.java index ca5fcd0..f8e9de5 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/GeoFeatureEntity.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/GeoFeatureEntity.java @@ -4,7 +4,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.geojson.GeoJsonObject; +import org.geojson.Point; @Getter @Setter @@ -12,6 +12,6 @@ public class GeoFeatureEntity { private String name; - private GeoJsonObject geometry; + private Point geometry; } diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/StrategicPolygonEntity.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/StrategicPolygonEntity.java index 88079b9..51e4f27 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/StrategicPolygonEntity.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/entity/StrategicPolygonEntity.java @@ -4,7 +4,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.geojson.GeoJsonObject; +import org.geojson.Polygon; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @@ -30,7 +30,7 @@ public class StrategicPolygonEntity { private String type; private List geoFeatures; private OptionsEntity options; - private GeoJsonObject geometry; + private Polygon geometry; private int version; @JsonProperty("$computed") private ComputedEntity computed; diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/GeoFeatureVO.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/GeoFeatureVO.java index aa87daf..83b1fc6 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/GeoFeatureVO.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/GeoFeatureVO.java @@ -4,7 +4,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.geojson.GeoJsonObject; +import org.geojson.Point; import java.io.Serializable; @@ -14,6 +14,6 @@ public class GeoFeatureVO implements Serializable { private String name; - private GeoJsonObject geometry; + private Point geometry; } diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/StrategicPolygonDetailedVO.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/StrategicPolygonDetailedVO.java index 231dc4b..4fbe22c 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/StrategicPolygonDetailedVO.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/model/vo/StrategicPolygonDetailedVO.java @@ -5,6 +5,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import org.geojson.GeoJsonObject; +import org.geojson.Polygon; import java.io.Serializable; import java.util.Date; @@ -27,7 +28,7 @@ public class StrategicPolygonDetailedVO implements Serializable { private String type; private List geoFeatures; private OptionsVO options; - private GeoJsonObject geometry; + private Polygon geometry; private int version; @JsonProperty("$computed") private ComputedVO computed; diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/PolygonService.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/PolygonService.java index 3d330f8..95712f9 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/PolygonService.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/PolygonService.java @@ -17,10 +17,10 @@ public interface PolygonService { public StrategicPolygonDetailedVO retrieveByLegacyId(String legacyId) throws PolygonServiceException; - public List retrieveByName(String name) throws PolygonServiceException; + public List retrieveByName(String name) throws PolygonServiceException; - public List retrieveByType(String type) throws PolygonServiceException; + public List retrieveByType(String type) throws PolygonServiceException; - public List retrieveByCityId(String cityId) throws PolygonServiceException; + public List retrieveByCityId(String cityId) throws PolygonServiceException; } diff --git a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/impl/PolygonServiceImpl.java b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/impl/PolygonServiceImpl.java index 182b655..7126e72 100644 --- a/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/impl/PolygonServiceImpl.java +++ b/polygon-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/polygon/service/impl/PolygonServiceImpl.java @@ -223,12 +223,12 @@ public StrategicPolygonDetailedVO retrieveByLegacyId(String legacyId) throws Pol } @Override - public List retrieveByType(String type) throws PolygonServiceException { + public List retrieveByType(String type) throws PolygonServiceException { if(StringUtils.hasText(type)) { - List voList = new ArrayList<>(); + List voList = new ArrayList<>(); List entityList = this.repository.findAllByType(type); for(StrategicPolygonEntity entity : entityList) { - StrategicPolygonVO vo = this.strategicPolygonSimpleConverter.convert(entity); + StrategicPolygonDetailedVO vo = this.strategicPolygonComplexConverter.convert(entity); voList.add(vo); } LOGGER.info("Found {} polygons of type: {}", voList.size(), type); @@ -240,12 +240,12 @@ public List retrieveByType(String type) throws PolygonServic } @Override - public List retrieveByCityId(String cityId) throws PolygonServiceException { + public List retrieveByCityId(String cityId) throws PolygonServiceException { if(StringUtils.hasText(cityId)) { - List voList = new ArrayList<>(); + List voList = new ArrayList<>(); List entityList = this.repository.findAllByCityId(cityId); for(StrategicPolygonEntity entity : entityList) { - StrategicPolygonVO vo = this.strategicPolygonSimpleConverter.convert(entity); + StrategicPolygonDetailedVO vo = this.strategicPolygonComplexConverter.convert(entity); voList.add(vo); } LOGGER.info("Found {} polygons of cityId: {}", voList.size(), cityId); @@ -257,12 +257,12 @@ public List retrieveByCityId(String cityId) throws PolygonSe } @Override - public List retrieveByName(String name) throws PolygonServiceException { + public List retrieveByName(String name) throws PolygonServiceException { if(StringUtils.hasText(name)) { - List voList = new ArrayList<>(); + List voList = new ArrayList<>(); List entityList = this.repository.findAllByName(name); for(StrategicPolygonEntity entity : entityList) { - StrategicPolygonVO vo = this.strategicPolygonSimpleConverter.convert(entity); + StrategicPolygonDetailedVO vo = this.strategicPolygonComplexConverter.convert(entity); voList.add(vo); } LOGGER.info("Found {} polygons of name: {}", voList.size(), name); diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/controller/PositionSearchController.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/controller/PositionSearchController.java index fe4e4c0..c496ea9 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/controller/PositionSearchController.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/controller/PositionSearchController.java @@ -1,7 +1,43 @@ package com.teenthofabud.codingchallenge.sharenow.position.controller; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.Car2StrategicPolygonPositioningVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygon2CarPositioningVO; +import com.teenthofabud.codingchallenge.sharenow.position.service.PositionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@RequestMapping("search") public class PositionSearchController { + + private static final Logger LOGGER = LoggerFactory.getLogger(PositionSearchController.class); + + @Autowired + private PositionService service; + + @GetMapping("car/vin/{vin}") + public ResponseEntity getVehicleAndItsEnclosingStrategicPolygon(@PathVariable String vin) throws PositionServiceException { + LOGGER.info("Determining polygon enclosing the car with vin"); + Car2StrategicPolygonPositioningVO vo = this.service.retrievePositionOfCarAndItsEnclosingPolygonByVin(vin); + ResponseEntity response = ResponseEntity.ok(vo); + LOGGER.info("Determined enclosed polygon for the car with vin"); + return response; + } + + @GetMapping("polygon/id/{id}") + public ResponseEntity getStrategicPolygonAndTheVehiclesItContains(@PathVariable String id) throws PositionServiceException { + LOGGER.info("Determining all cars enclosed within the polygon by id"); + StrategicPolygon2CarPositioningVO vo = this.service.retrievePositionsOfCarsByPolygonById(id); + ResponseEntity response = ResponseEntity.ok(vo); + LOGGER.info("Determined all cars enclosed within this polygon by its id"); + return response; + } + } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/filter/RestServiceErrorHandler.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/filter/RestServiceErrorHandler.java index e53990e..9d2e997 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/filter/RestServiceErrorHandler.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/filter/RestServiceErrorHandler.java @@ -22,7 +22,7 @@ public class RestServiceErrorHandler { private MessageSource messageSource; @ExceptionHandler(PositionServiceException.class) - public ResponseEntity handleVehicleServiceException(PositionServiceException psex) { + public ResponseEntity handlePositionServiceException(PositionServiceException psex) { LOGGER.error("Error encountered: {}", psex); ErrorVO vo = new ErrorVO(); String msg = messageSource.getMessage(psex.getError().getErrorCode(), null, Locale.US); diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/Orientation.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/Orientation.java new file mode 100644 index 0000000..e4df445 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/Orientation.java @@ -0,0 +1,9 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model; + +public enum Orientation { + + COLLINEAR, + CLOCKWISE, + ANTI_CLOCKWISE + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDTO.java similarity index 64% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDTO.java index 3b45ef9..a4d42ae 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDTO.java @@ -1,18 +1,18 @@ package com.teenthofabud.codingchallenge.sharenow.position.model.dto.car; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @Getter @Setter -public class CarDetailsVO { +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class CarDTO { private int id; - private int locationId; + @EqualsAndHashCode.Include private String vin; private String numberPlate; - private PositionVO position; - private float fuel; - private String model; + private int locationId; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsDTO.java similarity index 51% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsDTO.java index 59fd671..7c4a0d8 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/CarDetailsDTO.java @@ -1,15 +1,21 @@ package com.teenthofabud.codingchallenge.sharenow.position.model.dto.car; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @Getter @Setter -public class CarVO { +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class CarDetailsDTO { private int id; + private int locationId; + @EqualsAndHashCode.Include private String vin; private String numberPlate; - private int locationId; + private PositionDTO position; + private float fuel; + private String model; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorDTO.java similarity index 92% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorDTO.java index be292ef..8aa515b 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/ErrorDTO.java @@ -9,7 +9,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class ErrorVO { +public class ErrorDTO { private String errorCode; private String errorMessage; diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Node.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionDTO.java similarity index 51% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Node.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionDTO.java index 1791678..73356bf 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Node.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionDTO.java @@ -1,4 +1,4 @@ -package com.teenthofabud.codingchallenge.sharenow.position.quadtree; +package com.teenthofabud.codingchallenge.sharenow.position.model.dto.car; import lombok.AllArgsConstructor; import lombok.Getter; @@ -9,9 +9,9 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class Node { +public class PositionDTO { - private T data; - private Point point; + private double longitude; + private double latitude; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsDTO.java similarity index 89% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsDTO.java index fdef9ca..11aa85a 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ActiveTimedOptionsDTO.java @@ -10,7 +10,7 @@ @Getter @Setter @NoArgsConstructor -public class ActiveTimedOptionsVO implements Serializable { +public class ActiveTimedOptionsDTO implements Serializable { private int min; private int max; diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedDTO.java similarity index 68% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedDTO.java index 16fe908..483fecc 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ComputedDTO.java @@ -9,8 +9,8 @@ @Getter @Setter @NoArgsConstructor -public class ComputedVO implements Serializable { +public class ComputedDTO implements Serializable { - private ActiveTimedOptionsVO activeTimedOptions; + private ActiveTimedOptionsDTO activeTimedOptions; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorDTO.java similarity index 92% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorDTO.java index e22c30b..0d7eeb0 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/ErrorDTO.java @@ -9,7 +9,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class ErrorVO { +public class ErrorDTO { private String errorCode; private String errorMessage; diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureDTO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureDTO.java new file mode 100644 index 0000000..aa773d0 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureDTO.java @@ -0,0 +1,19 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon; + + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.geojson.Point; + +import java.io.Serializable; + +@Getter +@Setter +@NoArgsConstructor +public class GeoFeatureDTO implements Serializable { + + private String name; + private Point geometry; + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsDTO.java similarity index 88% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsDTO.java index de89b19..73cbdca 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/OptionsDTO.java @@ -10,7 +10,7 @@ @Getter @Setter @NoArgsConstructor -public class OptionsVO implements Serializable { +public class OptionsDTO implements Serializable { private boolean active; @JsonProperty("is_excluded") diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDTO.java similarity index 85% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDTO.java index bbcd74c..dd6b3c8 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDTO.java @@ -12,7 +12,7 @@ @Getter @Setter @NoArgsConstructor -public class StrategicPolygonVO implements Serializable { +public class StrategicPolygonDTO implements Serializable { @JsonProperty("_id") private String id; @@ -25,6 +25,6 @@ public class StrategicPolygonVO implements Serializable { private String legacyId; private String type; private int version; - private List geoFeatures; + private List geoFeatures; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedDTO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedDTO.java new file mode 100644 index 0000000..d013a60 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedDTO.java @@ -0,0 +1,22 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.geojson.Polygon; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +public class StrategicPolygonDetailedDTO extends StrategicPolygonDTO { + + private OptionsDTO options; + private Polygon geometry; + @JsonProperty("$computed") + private ComputedDTO computed; + private List timedOptions; + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedVO.java deleted file mode 100644 index 4d13729..0000000 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/StrategicPolygonDetailedVO.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import org.geojson.GeoJsonObject; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - -@Getter -@Setter -@NoArgsConstructor -public class StrategicPolygonDetailedVO implements Serializable { - - @JsonProperty("_id") - private String id; - private Date updatedAt; - private Date createdAt; - @JsonProperty("__v") - private int v; - private String name; - private String cityId; - private String legacyId; - private String type; - private List geoFeatures; - private OptionsVO options; - private GeoJsonObject geometry; - private int version; - @JsonProperty("$computed") - private ComputedVO computed; - private List timedOptions; - -} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsDTO.java similarity index 85% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsDTO.java index c9af401..4e7f115 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/TimedOptionsDTO.java @@ -10,7 +10,7 @@ @Getter @Setter @NoArgsConstructor -public class TimedOptionsVO implements Serializable { +public class TimedOptionsDTO implements Serializable { private String key; private List> changesOverTime; diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/error/PositionErrorCode.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/error/PositionErrorCode.java index 20a9bcf..e005b9c 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/error/PositionErrorCode.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/error/PositionErrorCode.java @@ -7,9 +7,10 @@ @ToString public enum PositionErrorCode { - NOT_FOUND("SNCC-PLYS-001", 404), - INVALID_PARAMETER("SNCC-PLYS-002", 500), - SYSTEM_ERROR("SNCC-PLYS-003", 400); + NOT_FOUND("SNCC-POSS-001", 404), + INVALID_PARAMETER("SNCC-POSS-002", 400), + SYSTEM_ERROR("SNCC-POSS-003", 500), + UNEXPECTED_PARAMETER("SNCC-POSS-004", 500); @ToString.Include private int statusCode; @@ -21,5 +22,4 @@ private PositionErrorCode(String errorCode, int statusCode) { this.statusCode = statusCode; } - } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/Car2StrategicPolygonPositioningVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/Car2StrategicPolygonPositioningVO.java new file mode 100644 index 0000000..9e66c96 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/Car2StrategicPolygonPositioningVO.java @@ -0,0 +1,18 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.car; + +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygonMappedVO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class Car2StrategicPolygonPositioningVO { + + private CarMappedVO car; + private StrategicPolygonMappedVO polygon; + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/CarMappedVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/CarMappedVO.java new file mode 100644 index 0000000..e664268 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/CarMappedVO.java @@ -0,0 +1,19 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.car; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class CarMappedVO { + + private String vin; + private String model; + private String numberPlate; + private PositionVO position; + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/PositionVO.java similarity index 95% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/PositionVO.java index 190265f..da8622e 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/car/PositionVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/car/PositionVO.java @@ -1,4 +1,4 @@ -package com.teenthofabud.codingchallenge.sharenow.position.model.dto.car; +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.car; import lombok.Getter; import lombok.Setter; diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/GeoFeatureVO.java similarity index 77% rename from position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureVO.java rename to position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/GeoFeatureVO.java index e56cffb..acad1ad 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/dto/polygon/GeoFeatureVO.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/GeoFeatureVO.java @@ -1,10 +1,10 @@ -package com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon; +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.geojson.GeoJsonObject; +import org.geojson.Point; import java.io.Serializable; @@ -14,6 +14,6 @@ public class GeoFeatureVO implements Serializable { private String name; - private GeoJsonObject geometry; + private Point geometry; } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygon2CarPositioningVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygon2CarPositioningVO.java new file mode 100644 index 0000000..4f113c3 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygon2CarPositioningVO.java @@ -0,0 +1,34 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon; + +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.CarMappedVO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StrategicPolygon2CarPositioningVO { + + private List cars; + private StrategicPolygonMappedVO polygon; + + public void addCar(CarMappedVO carVO) { + if(this.cars != null) { + this.cars.add(carVO); + } + } + + public boolean hasCars() { + if(this.cars != null) { + return !this.cars.isEmpty(); + } else { + return false; + } + } + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedComplexVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedComplexVO.java new file mode 100644 index 0000000..94cd326 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedComplexVO.java @@ -0,0 +1,25 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon; + +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.CarMappedVO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StrategicPolygonMappedComplexVO extends StrategicPolygonMappedVO { + + private List cars; + + public void addCar(CarMappedVO carVO) { + if(this.cars != null ) { + this.cars.add(carVO); + } + } + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedVO.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedVO.java new file mode 100644 index 0000000..daead01 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/model/vo/polygon/StrategicPolygonMappedVO.java @@ -0,0 +1,23 @@ +package com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class StrategicPolygonMappedVO { + + private String id; + private String cityId; + private String name; + private String type; + private List geoFeatures; + + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Point.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Point.java deleted file mode 100644 index 033f415..0000000 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Point.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.teenthofabud.codingchallenge.sharenow.position.quadtree; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -public class Point { - - private double x; - private double y; - -} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Quad.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Quad.java deleted file mode 100644 index a05af0b..0000000 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/quadtree/Quad.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.teenthofabud.codingchallenge.sharenow.position.quadtree; - -import lombok.Getter; -import lombok.Setter; - -import java.awt.geom.Point2D; - - -@Getter -@Setter -public class Quad, K> { - - private Point topLeft; - private Point bottomRight; - private Node node; - private Quad topLeftTree; - private Quad bottomLeftTree; - private Quad topRightTree; - private Quad bottomRightTree; - - public Quad() { - this.topLeft = new Point(0.0d, 0.0d); - this.bottomRight = new Point(0.0d, 0.0d); - } - - public Quad(Point topLeft, Point bottomRight) { - this.topLeft = topLeft; - this.bottomRight = bottomRight; - } - - private boolean withinBoundary(Point point) - { - return point.getX() >= this.topLeft.getX() && point.getX() <= this.bottomRight.getX() - && - point.getY() >= this.topLeft.getY() && point.getY() <= this.bottomRight.getY(); - } - - public void insert(Node node) { - if (node == null) { - return; - } - // Current quad cannot contain it - if (!this.withinBoundary(node.getPoint())) { - return; - } - - // We are at a quad of unit area - // We cannot subdivide this quad further - if (Math.abs(this.topLeft.getX() - this.bottomRight.getX()) <= 1 && Math.abs(this.topLeft.getY() - this.bottomRight.getY()) <= 1) { - if (this.node == null) { - this.node = node; - } - return; - } - - if ((this.topLeft.getX() + this.bottomRight.getX()) / 2 >= node.getPoint().getX()) { - if ((this.topLeft.getY() + this.bottomRight.getY()) / 2 >= node.getPoint().getY()) { - // Indicates topLeftTree - if (this.topLeftTree == null) { - Point topLeft = new Point(this.topLeft.getX(), this.topLeft.getY()); - Point bottomRight = new Point( - (this.topLeft.getX() + this.bottomRight.getX()) / 2, - (this.topLeft.getY() + this.bottomRight.getY()) / 2); - this.topLeftTree = new Quad<>(topLeft, bottomRight); - } - this.topLeftTree.insert(node); - } else { - // Indicates bottomLeftTree - if (this.bottomLeftTree == null) { - Point topLeft = new Point(this.topLeft.getX(), - (this.topLeft.getY() + this.bottomRight.getY()) / 2); - Point bottomRight = new Point((this.topLeft.getX() + this.bottomRight.getY()) / 2, - this.bottomRight.getY()); - this.bottomLeftTree = new Quad<>(topLeft, bottomRight); - } - this.bottomLeftTree.insert(node); - } - } else { - if ((this.topLeft.getY() + this.bottomRight.getY()) / 2 >= node.getPoint().getY()) { - // Indicates topRightTree - if (this.topRightTree == null) { - Point topLeft = new Point((this.topLeft.getX() + this.bottomRight.getX()) / 2, - this.topLeft.getY()); - Point bottomRight = new Point(this.bottomRight.getX(), - (this.topLeft.getY() + this.bottomRight.getY()) / 2); - this.topRightTree = new Quad<>(topLeft, bottomRight); - } - this.topRightTree.insert(node); - } else { - // Indicates bottomRightTree - if (this.bottomRightTree == null) { - Point topLeft = new Point((this.topLeft.getX() + this.bottomRight.getX()) / 2, - (this.topLeft.getY() + this.bottomRight.getY()) / 2); - Point bottomRight = new Point(this.bottomRight.getX(), this.bottomRight.getY()); - this.bottomRightTree = new Quad<>(topLeft, bottomRight); - } - this.bottomRightTree.insert(node); - } - } - } - - public Node search(Point point) - { - // Current quad cannot contain it - if (!this.withinBoundary(point)) { - return null; - } - - // We are at a quad of unit length - // We cannot subdivide this quad further - if (this.node != null) - return this.node; - - if ((this.topLeft.getX() + this.bottomRight.getX()) / 2 >= point.getX()) { - if ((this.topLeft.getY() + this.bottomRight.getY()) / 2 >= point.getY()) { - // Indicates topLeftTree - if (this.topLeftTree == null) { - return null; - } - return this.topLeftTree.search(point); - } else { - // Indicates bottomLeftTree - if (this.bottomLeftTree == null) { - return null; - } - return this.bottomLeftTree.search(point); - } - } else { - // Indicates topRightTree - if ((this.topLeft.getY() + this.bottomRight.getY()) / 2 >= point.getY()) - { - if (this.topRightTree == null) { - return null; - } - return this.topRightTree.search(point); - } else { - // Indicates bottomRightTree - if (this.bottomRightTree == null) { - return null; - } - return this.bottomRightTree.search(point); - } - } - }; - - public static void main(String[] args) { - Point topLeft = new Point(0.0d, 0.0d); - Point bottomRight = new Point(8.0d, 8.0d); - Quad, Integer> q = new Quad, Integer>(topLeft, bottomRight); - Point bCoordinates = new Point(2.0d, 5.0d); - Point aCoordinates = new Point(1.0d, 1.0d); - Point cCoordinates = new Point(7.0d, 6.0d); - Point dCoordinates = new Point(17.0d, 66.0d); - Node a = new Node(1, aCoordinates); - Node b = new Node<>(2, bCoordinates); - Node c = new Node<>(3, cCoordinates); - q.insert(a); - q.insert(b); - q.insert(c); - Node result = q.search(aCoordinates); - System.out.println("Node a: " + (result != null ? result.getData() : "NOT FOUND")); - result = q.search(bCoordinates); - System.out.println("Node b: " + (result != null ? result.getData() : "NOT FOUND")); - result = q.search(cCoordinates); - System.out.println("Node c: " + (result != null ? result.getData() : "NOT FOUND")); - result = q.search(dCoordinates); - System.out.println("Node d: " + (result != null ? result.getData() : "NOT FOUND")); - } - -} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/CarServiceClient.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/CarServiceClient.java index 14d9725..90bda0e 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/CarServiceClient.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/CarServiceClient.java @@ -1,6 +1,7 @@ package com.teenthofabud.codingchallenge.sharenow.position.repository; -import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -10,10 +11,13 @@ @FeignClient(value = "carServiceClient", url = "${poss.car-service.url}") public interface CarServiceClient { - @GetMapping("search") - public List getAllCars(); + @GetMapping("car-service/search") + public List getAllCars(); - @GetMapping("search/vin/{vin}") - public List getCarDetailsByVin(@PathVariable String vin); + @GetMapping("car-service/search/vin/{vin}") + public CarDetailsDTO getCarDetailsByVin(@PathVariable String vin); + + @GetMapping("car-service/search/withdetails") + public List getAllCarsWithDetails(); } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/PolygonServiceClient.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/PolygonServiceClient.java index cf5e852..2c06531 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/PolygonServiceClient.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/repository/PolygonServiceClient.java @@ -1,6 +1,7 @@ package com.teenthofabud.codingchallenge.sharenow.position.repository; -import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -11,16 +12,16 @@ @FeignClient(value = "polygonServiceClient", url = "${poss.polygon-service.url}") public interface PolygonServiceClient { - @GetMapping("search") - public List getAllPolygons(); + @GetMapping("polygon-service/search") + public List getAllPolygons(); - @GetMapping("search/cityid/{cityId}") - public List getAllPolygonsByCityId(@PathVariable String cityId); + @GetMapping("polygon-service/search/cityid/{cityId}") + public List getAllPolygonsByCityId(@PathVariable String cityId); - @GetMapping("search/name/{name}") - public List getAllPolygonsByName(@PathVariable String name); + @GetMapping("polygon-service/search/name/{name}") + public List getAllPolygonsByName(@PathVariable String name); - @GetMapping("search/id/{id}") - public List getPolygonDetailsById(@PathVariable String id); + @GetMapping("polygon-service/search/id/{id}") + public StrategicPolygonDetailedDTO getPolygonDetailsById(@PathVariable String id); } \ No newline at end of file diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementService.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementService.java new file mode 100644 index 0000000..908b9eb --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementService.java @@ -0,0 +1,13 @@ +package com.teenthofabud.codingchallenge.sharenow.position.service; + +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import org.springframework.stereotype.Service; + +@Service +public interface PlacementService { + + public boolean isCarInsidePolygonConsiderOnlyOuterRing(CarDetailsDTO carDTO, StrategicPolygonDetailedDTO polygonDTO) throws PositionServiceException; + +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PositionService.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PositionService.java index f6e1c1c..d8ed4d6 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PositionService.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/PositionService.java @@ -1,7 +1,18 @@ package com.teenthofabud.codingchallenge.sharenow.position.service; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.Car2StrategicPolygonPositioningVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygon2CarPositioningVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.StrategicPolygonMappedComplexVO; import org.springframework.stereotype.Service; +import java.util.List; + @Service public interface PositionService { + + public Car2StrategicPolygonPositioningVO retrievePositionOfCarAndItsEnclosingPolygonByVin(String vin) throws PositionServiceException; + + public StrategicPolygon2CarPositioningVO retrievePositionsOfCarsByPolygonById(String polygonId) throws PositionServiceException; + } diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PlacementServiceImpl.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PlacementServiceImpl.java new file mode 100644 index 0000000..95207f9 --- /dev/null +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PlacementServiceImpl.java @@ -0,0 +1,115 @@ +package com.teenthofabud.codingchallenge.sharenow.position.service.impl; + +import com.teenthofabud.codingchallenge.sharenow.position.model.Orientation; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionErrorCode; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import com.teenthofabud.codingchallenge.sharenow.position.service.PlacementService; +import org.geojson.LngLatAlt; +import org.geojson.Point; +import org.geojson.Polygon; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class PlacementServiceImpl implements PlacementService { + + private static final Logger LOGGER = LoggerFactory.getLogger(PlacementServiceImpl.class); + + @Value("${poss.placement.infinite.end.limit}") + private int infiniteEnd; + + private boolean checkCollinearity(Point a, Point b, Point c) { + LngLatAlt aCoordinates = a.getCoordinates(); + LngLatAlt bCoordinates = b.getCoordinates(); + LngLatAlt cCoordinates = c.getCoordinates(); + if (bCoordinates.getLongitude() <= Math.max(aCoordinates.getLongitude(), cCoordinates.getLongitude()) + && bCoordinates.getLongitude() >= Math.min(aCoordinates.getLongitude(), cCoordinates.getLongitude()) + && bCoordinates.getLatitude() <= Math.max(aCoordinates.getLatitude(), cCoordinates.getLatitude()) + && bCoordinates.getLatitude() >= Math.min(aCoordinates.getLatitude(), cCoordinates.getLatitude())) { + return true; + } else { + return false; + } + } + + private Orientation determineOrientation(Point a, Point b, Point c) { + LngLatAlt aCoordinates = a.getCoordinates(); + LngLatAlt bCoordinates = b.getCoordinates(); + LngLatAlt cCoordinates = c.getCoordinates(); + double slopeDifference = (bCoordinates.getLatitude() - aCoordinates.getLatitude()) * (cCoordinates.getLongitude() - bCoordinates.getLongitude()) + - (bCoordinates.getLongitude() - aCoordinates.getLongitude()) * (cCoordinates.getLatitude() - bCoordinates.getLatitude()); + Orientation orientation = Orientation.COLLINEAR; + if ((int)slopeDifference == 1) { + orientation = Orientation.CLOCKWISE; + } else if((int)slopeDifference == 2) { + orientation = Orientation.ANTI_CLOCKWISE; + } + return orientation; + } + + private boolean doesIntersect(Point a1, Point b1, Point a2, Point b2) { + boolean status = false; + Orientation orientation1 = this.determineOrientation(a1, b1, a2); + Orientation orientation2 = this.determineOrientation(a1, b1, b2); + Orientation orientation3 = this.determineOrientation(a2, b2, a1); + Orientation orientation4 = this.determineOrientation(a2, b2, a2); + if (orientation1 != orientation2 && orientation3 != orientation4) { + status = true; + } + if (orientation1 == Orientation.COLLINEAR && this.checkCollinearity(a1, a2, b1)) { + status = true; + } + if (orientation2 == Orientation.COLLINEAR && this.checkCollinearity(a1, b2, b1)) { + status = true; + } + if (orientation3 == Orientation.COLLINEAR && this.checkCollinearity(a2, a1, b2)) { + status = true; + } + if (orientation4 == Orientation.COLLINEAR && this.checkCollinearity(a2, b1, b2)) { + status = true; + } + return status; + } + + @Override + public boolean isCarInsidePolygonConsiderOnlyOuterRing(CarDetailsDTO carDTO, StrategicPolygonDetailedDTO polygonDTO) throws PositionServiceException { + if(carDTO == null) { + throw new PositionServiceException("Invalid car", PositionErrorCode.UNEXPECTED_PARAMETER, new Object[] {"car is null"}); + } else if(polygonDTO == null) { + throw new PositionServiceException("Invalid polygon", PositionErrorCode.UNEXPECTED_PARAMETER, new Object[] {"polygon is null"}); + } else { + Polygon polygon = polygonDTO.getGeometry(); + if(polygon != null) { + List coordinates = polygon.getExteriorRing(); + if (coordinates != null && coordinates.size() < 3) { + throw new PositionServiceException("Invalid polygon", PositionErrorCode.UNEXPECTED_PARAMETER, new Object[] {"polygon vertex count < 3"}); + } else { + Point carCoordinates = new Point(carDTO.getPosition().getLongitude(), carDTO.getPosition().getLatitude()); + Point extremeEnd = new Point(infiniteEnd, carCoordinates.getCoordinates().getLatitude()); + int intersectionCount = 0, i = 0; + do { + int j = (i + 1) % coordinates.size(); + Point a1 = new Point(coordinates.get(i)); + Point b1 = new Point(coordinates.get(j)); + if (this.doesIntersect(a1, b1, carCoordinates, extremeEnd)) { + if (this.determineOrientation(a1, carCoordinates, b1) == Orientation.COLLINEAR) { + return this.checkCollinearity(a1, carCoordinates, b1); + } + intersectionCount++; + } + i = j; + } while (i != 0); + return (intersectionCount % 2 == 1); + } + } else { + throw new PositionServiceException("Invalid polygon", PositionErrorCode.INVALID_PARAMETER, new Object[] {"polygon coordinates"}); + } + } + } +} diff --git a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PositionServiceImpl.java b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PositionServiceImpl.java index 88ae6f3..237ba0d 100644 --- a/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PositionServiceImpl.java +++ b/position-service/src/main/java/com/teenthofabud/codingchallenge/sharenow/position/service/impl/PositionServiceImpl.java @@ -1,24 +1,180 @@ package com.teenthofabud.codingchallenge.sharenow.position.service.impl; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.PositionDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.GeoFeatureDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionErrorCode; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.*; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.Car2StrategicPolygonPositioningVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.CarMappedVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.car.PositionVO; +import com.teenthofabud.codingchallenge.sharenow.position.model.vo.polygon.*; import com.teenthofabud.codingchallenge.sharenow.position.repository.CarServiceClient; import com.teenthofabud.codingchallenge.sharenow.position.repository.PolygonServiceClient; +import com.teenthofabud.codingchallenge.sharenow.position.service.PlacementService; import com.teenthofabud.codingchallenge.sharenow.position.service.PositionService; +import feign.FeignException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; +import javax.annotation.PostConstruct; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + @Component public class PositionServiceImpl implements PositionService { private static final Logger LOGGER = LoggerFactory.getLogger(PositionServiceImpl.class); + @Autowired + private PlacementService placementService; + @Autowired private CarServiceClient carClient; @Autowired - private PolygonServiceClient paolygonClient; + private PolygonServiceClient polygonClient; + + private Converter carDetailsDTO2VOConverter; + + private Converter polygonDetailsDTO2VOConverter; + + private Converter positionDTO2VOConverter; + + private Converter geoFeatureDTO2VOConverter; + + @PostConstruct + private void init() { + this.positionDTO2VOConverter = (dto) -> { + PositionVO vo = new PositionVO(); + vo.setLatitude(dto.getLatitude()); + vo.setLongitude(dto.getLongitude()); + return vo; + }; + this.carDetailsDTO2VOConverter = (dto) -> { + CarMappedVO vo = new CarMappedVO(); + vo.setModel(dto.getModel()); + vo.setNumberPlate(dto.getNumberPlate()); + vo.setVin(dto.getVin()); + vo.setPosition(this.positionDTO2VOConverter.convert(dto.getPosition())); + return vo; + }; + this.geoFeatureDTO2VOConverter = (entity) -> { + GeoFeatureVO vo = new GeoFeatureVO(); + if(entity != null) { + vo.setGeometry(entity.getGeometry()); + vo.setName(entity.getName()); + } + return vo; + }; + this.polygonDetailsDTO2VOConverter = (dto) -> { + StrategicPolygonMappedVO vo = new StrategicPolygonMappedVO(); + vo.setCityId(dto.getCityId()); + vo.setGeoFeatures(dto.getGeoFeatures().stream() + .map(gf -> this.geoFeatureDTO2VOConverter.convert(gf)).collect(Collectors.toList())); + vo.setId(dto.getId()); + vo.setType(dto.getType()); + vo.setName(dto.getName()); + return vo; + }; + } + + private PositionServiceException parseFeignErrorResponse(FeignException e) { + LOGGER.error("Error requesting external service {}", e.getMessage()); + e.printStackTrace(); + Optional optResponse = e.responseBody(); + String response = ""; + if(optResponse.isPresent()) { + response = StandardCharsets.UTF_8.decode(optResponse.get()).toString(); + ObjectMapper om = new ObjectMapper(); + try { + ErrorVO errVO = om.readValue(response, ErrorVO.class); + response = errVO.getErrorMessage(); + } catch (JsonProcessingException jsonProcessingException) { + LOGGER.error("Error parsing feign response: {}", jsonProcessingException.getMessage()); + jsonProcessingException.printStackTrace(); + } + } + return new PositionServiceException(e.getMessage(), PositionErrorCode.SYSTEM_ERROR, new Object[] {response}); + } + @Override + public Car2StrategicPolygonPositioningVO retrievePositionOfCarAndItsEnclosingPolygonByVin(String vin) throws PositionServiceException { + try { + Car2StrategicPolygonPositioningVO posVO = new Car2StrategicPolygonPositioningVO(); + boolean found = false; + CarDetailsDTO carDTO = this.carClient.getCarDetailsByVin(vin); + LOGGER.info("Retrieved car details for vin: {}", vin); + List polygonDTOList = this.polygonClient.getAllPolygons(); + if(polygonDTOList != null && !polygonDTOList.isEmpty()) { + LOGGER.info("Retrieved strategic polygons: {}", polygonDTOList.size()); + for(StrategicPolygonDTO litePolygonDTO : polygonDTOList) { + StrategicPolygonDetailedDTO detailedPolygonDTO = this.polygonClient.getPolygonDetailsById(litePolygonDTO.getId()); + if(this.placementService.isCarInsidePolygonConsiderOnlyOuterRing(carDTO, detailedPolygonDTO)) { + CarMappedVO carVO = this.carDetailsDTO2VOConverter.convert(carDTO); + StrategicPolygonMappedVO polygonVO = this.polygonDetailsDTO2VOConverter.convert(detailedPolygonDTO); + posVO.setCar(carVO); + posVO.setPolygon(polygonVO); + found = true; + LOGGER.info("Car with vin {} is present inside polygon with id {}", vin, detailedPolygonDTO.getId()); + break; + } + } + if(found) { + return posVO; + } else { + LOGGER.warn("Car with vin {} is not present in any polygon", vin); + throw new PositionServiceException("Unplaced car", PositionErrorCode.NOT_FOUND, new Object[] {"vin", vin}); + } + } else { + throw new PositionServiceException("No polygons found", PositionErrorCode.NOT_FOUND, new Object[] {"polygons", ""}); + } + } catch (FeignException e) { + throw this.parseFeignErrorResponse(e); + } + } + @Override + public StrategicPolygon2CarPositioningVO retrievePositionsOfCarsByPolygonById(String polygonId) throws PositionServiceException { + try { + StrategicPolygon2CarPositioningVO posVO = new StrategicPolygon2CarPositioningVO(); + StrategicPolygonDetailedDTO polygonDTO = this.polygonClient.getPolygonDetailsById(polygonId); + LOGGER.info("Retrieved strategic polygon details for id: {}", polygonId); + List carDetailsDTOList = this.carClient.getAllCarsWithDetails(); + if(carDetailsDTOList != null && !carDetailsDTOList.isEmpty()) { + LOGGER.info("Retrieved cars: {}", carDetailsDTOList.size()); + for(CarDetailsDTO carDetailsDTO : carDetailsDTOList) { + if(this.placementService.isCarInsidePolygonConsiderOnlyOuterRing(carDetailsDTO, polygonDTO)) { + CarMappedVO carVO = this.carDetailsDTO2VOConverter.convert(carDetailsDTO); + posVO.addCar(carVO); + } + } + if(posVO.hasCars()) { + StrategicPolygonMappedVO polygonVO = this.polygonDetailsDTO2VOConverter.convert(polygonDTO); + posVO.setPolygon(polygonVO); + LOGGER.info("Added {} cars to polygon with id {}", posVO.getCars().size(), polygonId); + return posVO; + } else { + LOGGER.error("No cars could be placed in polygon with id {}", polygonId); + throw new PositionServiceException("No cars available", PositionErrorCode.NOT_FOUND, new Object[] {"cars", "are"}); + } + } else { + throw new PositionServiceException("No cars available", PositionErrorCode.NOT_FOUND, new Object[] {"cars", "are"}); + } + } catch (FeignException e) { + throw this.parseFeignErrorResponse(e); + } + } } diff --git a/position-service/src/main/resources/messages.properties b/position-service/src/main/resources/messages.properties index 24870bf..d6d36bc 100644 --- a/position-service/src/main/resources/messages.properties +++ b/position-service/src/main/resources/messages.properties @@ -1,3 +1,4 @@ -SNCC-PLYS-001=%s: %s not available -SNCC-PLYS-002=%s is not valid -SNCC-PLYS-003=Unexpected system error \ No newline at end of file +SNCC-POSS-001=%s: %s not available +SNCC-POSS-002=%s is not valid +SNCC-POSS-003=Unexpected system error: %s +SNCC-POSS-004=Unexpected value: %s \ No newline at end of file diff --git a/position-service/src/test/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementServiceTests.java b/position-service/src/test/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementServiceTests.java new file mode 100644 index 0000000..5f22354 --- /dev/null +++ b/position-service/src/test/java/com/teenthofabud/codingchallenge/sharenow/position/service/PlacementServiceTests.java @@ -0,0 +1,159 @@ +package com.teenthofabud.codingchallenge.sharenow.position.service; + +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.CarDetailsDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.car.PositionDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.dto.polygon.StrategicPolygonDetailedDTO; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionErrorCode; +import com.teenthofabud.codingchallenge.sharenow.position.model.error.PositionServiceException; +import com.teenthofabud.codingchallenge.sharenow.position.service.impl.PlacementServiceImpl; +import org.geojson.LngLatAlt; +import org.geojson.Polygon; +import org.junit.Assert; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +public class PlacementServiceTests { + + private static PlacementService SERVICE; + + private static CarDetailsDTO CAR; + + private static StrategicPolygonDetailedDTO STRATEGIC_POLYGON; + + @BeforeAll + public static void init() { + SERVICE = new PlacementServiceImpl(); + CAR = new CarDetailsDTO(); + STRATEGIC_POLYGON = new StrategicPolygonDetailedDTO(); + } + + @Test + @DisplayName("Test car lies inside the strategic polygon") + public void testCarLies_InsideTheStrategicPolygon() { + // arrange + PositionDTO carPosition = new PositionDTO(9.137148666666667d, 48.79031233333333d); + List polygonCoordinates = Arrays.asList( + new LngLatAlt(9.137248d, 48.790411d), + new LngLatAlt( 9.137248d, 48.790263d), + new LngLatAlt(9.13695d, 48.790263d), + new LngLatAlt(9.137248d, 48.790411d)); + CAR.setPosition(carPosition); + STRATEGIC_POLYGON.setGeometry(new Polygon(polygonCoordinates)); + boolean actualResult = false; + + // act + try { + actualResult = SERVICE.isCarInsidePolygonConsiderOnlyOuterRing(CAR, STRATEGIC_POLYGON); + } catch (PositionServiceException psex) { + // consume exception because we know this data will not throw any exception + } + + //assert + Assert.assertEquals(true, actualResult); + } + + @Test + @DisplayName("Test car lies outside the strategic polygon") + public void testCarLies_OutsideTheStrategicPolygon() { + // arrange + PositionDTO carPosition = new PositionDTO(20.0d, 20.0d); + List polygonCoordinates = Arrays.asList(new LngLatAlt(0.0d, 0.0d), new LngLatAlt(10.0d, 0.0d), + new LngLatAlt(10.0d, 10.0d), new LngLatAlt(0.0d, 10.0d)); + CAR.setPosition(carPosition); + STRATEGIC_POLYGON.setGeometry(new Polygon(polygonCoordinates)); + boolean actualResult = true; + + // act + try { + actualResult = SERVICE.isCarInsidePolygonConsiderOnlyOuterRing(CAR, STRATEGIC_POLYGON); + } catch (PositionServiceException psex) { + // consume exception because we know this data will not throw any exception + } + + //assert + Assert.assertEquals(false, actualResult); + } + + @Test + @DisplayName("Test car lies exactly on an edge of the strategic polygon") + public void testCarLies_ExactlyOnAnEdge_OfTheStrategicPolygon() { + // arrange + PositionDTO carPosition = new PositionDTO(5.0d, 0.0d); + List polygonCoordinates = Arrays.asList(new LngLatAlt(0.0d, 0.0d), new LngLatAlt(10.0d, 0.0d), + new LngLatAlt(10.0d, 10.0d), new LngLatAlt(0.0d, 10.0d)); + CAR.setPosition(carPosition); + STRATEGIC_POLYGON.setGeometry(new Polygon(polygonCoordinates)); + boolean actualResult = false; + + // act + try { + actualResult = SERVICE.isCarInsidePolygonConsiderOnlyOuterRing(CAR, STRATEGIC_POLYGON); + } catch (PositionServiceException psex) { + // consume exception because we know this data will not throw any exception + } + + //assert + Assert.assertEquals(true, actualResult); + } + + @Test + @DisplayName("Test car lies outside the strategic polygon but is collinear to one of its vertex") + public void testCarLiesOutside_TheStrategicPolygon_ButIsCollinear_ToOneOfItsVertex() { + // arrange + PositionDTO carPosition = new PositionDTO(-5.0d, 5.0d); + List polygonCoordinates = Arrays.asList(new LngLatAlt(0.0d, 0.0d), new LngLatAlt(10.0d, 0.0d), + new LngLatAlt(10.0d, 10.0d), new LngLatAlt(0.0d, 10.0d)); + CAR.setPosition(carPosition); + STRATEGIC_POLYGON.setGeometry(new Polygon(polygonCoordinates)); + boolean actualResult = true; + + // act + try { + actualResult = SERVICE.isCarInsidePolygonConsiderOnlyOuterRing(CAR, STRATEGIC_POLYGON); + } catch (PositionServiceException psex) { + // consume exception because we know this data will not throw any exception + } + + //assert + Assert.assertEquals(false, actualResult); + } + + @Test + @DisplayName("Test service throws exception if strategic polygon provided is not a polygon in nature") + public void testReportError_IfStrategicPolygon_IsNotAPolygon_InNature() { + // arrange + PositionDTO carPosition = new PositionDTO(5.0d, 2.0d); + List polygonCoordinates = Arrays.asList(new LngLatAlt(0.0d, 0.0d), new LngLatAlt(10.0d, 0.0d)); + CAR.setPosition(carPosition); + STRATEGIC_POLYGON.setGeometry(new Polygon(polygonCoordinates)); + boolean actualResult = true; + String expectedMessage = "Invalid polygon"; + PositionErrorCode expectedErrorCode = PositionErrorCode.UNEXPECTED_PARAMETER; + String expectedParameterMessage = "polygon vertex count < 3"; + + String actualMessage = ""; + PositionErrorCode actualErrorCode = null; + String actualParameterMessage = ""; + + + // act + try { + actualResult = SERVICE.isCarInsidePolygonConsiderOnlyOuterRing(CAR, STRATEGIC_POLYGON); + } catch (PositionServiceException psex) { + actualErrorCode = psex.getError(); + actualMessage = psex.getMessage(); + actualParameterMessage = (String) psex.getParams()[0]; + } + + //assert + Assert.assertEquals(expectedMessage, actualMessage); + Assert.assertEquals(expectedErrorCode, actualErrorCode); + Assert.assertEquals(expectedParameterMessage, actualParameterMessage); + } + + +}