Jelajahi Sumber

first batch

Fabien CHERET 5 tahun lalu
melakukan
a8b3b18e73

+ 52 - 0
pom.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.2.5.RELEASE</version>
+		<relativePath/> <!-- lookup parent from repository -->
+	</parent>
+	<groupId>eu.fibane</groupId>
+	<artifactId>parkingtoll</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>parkingtoll</name>
+	<description>Demo project for Spring Boot</description>
+
+	<properties>
+		<java.version>1.8</java.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+			<exclusions>
+				<exclusion>
+					<groupId>org.junit.vintage</groupId>
+					<artifactId>junit-vintage-engine</artifactId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 16 - 0
src/main/java/eu/fibane/parkingtoll/ParkingtollApplication.java

@@ -0,0 +1,16 @@
+package eu.fibane.parkingtoll;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ParkingtollApplication {
+	protected final Log logger = LogFactory.getLog(getClass());
+
+	public static void main(String[] args) {
+		SpringApplication.run(ParkingtollApplication.class, args);
+	}
+
+}

+ 9 - 0
src/main/java/eu/fibane/parkingtoll/api/ApiException.java

@@ -0,0 +1,9 @@
+package eu.fibane.parkingtoll.api;
+
+public class ApiException extends Exception{
+    private int code;
+    public ApiException (int code, String msg) {
+        super(msg);
+        this.code = code;
+    }
+}

+ 9 - 0
src/main/java/eu/fibane/parkingtoll/api/NotFoundException.java

@@ -0,0 +1,9 @@
+package eu.fibane.parkingtoll.api;
+
+public class NotFoundException extends ApiException {
+    private int code;
+    public NotFoundException (int code, String msg) {
+        super(code, msg);
+        this.code = code;
+    }
+}

+ 58 - 0
src/main/java/eu/fibane/parkingtoll/api/ParkingLotApi.java

@@ -0,0 +1,58 @@
+package eu.fibane.parkingtoll.api;
+
+import eu.fibane.parkingtoll.model.CarSlot;
+import eu.fibane.parkingtoll.model.ParkingLot;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.validation.Valid;
+import java.util.List;
+
+public interface ParkingLotApi {
+
+    @RequestMapping(value = "/parking_lot",
+            produces = { "application/json" },
+            consumes = { "application/json" },
+            method = RequestMethod.POST)
+    ResponseEntity<Void> addParkingLot(@Valid @RequestBody ParkingLot parkingLotItem);
+
+
+    @RequestMapping(value = "/parking_lot/{parkingLotId}",
+            method = RequestMethod.DELETE)
+    ResponseEntity<Void> parkingLotParkingLotIdDelete(@PathVariable("parkingLotId") Long parkingLotId);
+
+    @RequestMapping(value = "/parking_lot/{parkingLotId}",
+            produces = { "application/json" },
+            method = RequestMethod.GET)
+    ResponseEntity<ParkingLot> parkingLotParkingLotIdGet(@PathVariable("parkingLotId") Long parkingLotId);
+
+
+    @RequestMapping(value = "/parking_lot/{parkingLotId}/park",
+            method = RequestMethod.DELETE)
+    ResponseEntity<CarSlot> parkingLotParkingLotIdParkDelete(@PathVariable("parkingLotId") Long parkingLotId, @Valid @RequestBody CarSlot carSlotItem);
+
+
+    @RequestMapping(value = "/parking_lot/{parkingLotId}/park",
+            produces = { "application/json" },
+            consumes = { "application/json" },
+            method = RequestMethod.POST)
+    ResponseEntity<CarSlot> parkingLotParkingLotIdParkPost(@PathVariable("parkingLotId") Long parkingLotId, @Valid @RequestBody CarSlot carSlotItem);
+
+
+    @RequestMapping(value = "/parking_lot",
+            produces = { "application/json" },
+            consumes = { "application/json" },
+            method = RequestMethod.PUT)
+    ResponseEntity<ParkingLot> parkingLotPut(@Valid @RequestBody ParkingLot parkingLotItem);
+
+
+    @RequestMapping(value = "/parking_lot",
+            produces = { "application/json" },
+            method = RequestMethod.GET)
+    ResponseEntity<List<ParkingLot>> searchParkingLot(@Valid @RequestParam(value = "searchString", required = false) String searchString);
+
+}

+ 113 - 0
src/main/java/eu/fibane/parkingtoll/api/ParkingLotApiController.java

@@ -0,0 +1,113 @@
+package eu.fibane.parkingtoll.api;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import eu.fibane.parkingtoll.model.CarSlot;
+import eu.fibane.parkingtoll.model.ParkingLot;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+public class ParkingLotApiController implements ParkingLotApi {
+
+    private static final Logger log = LoggerFactory.getLogger(ParkingLotApiController.class);
+
+    private final ObjectMapper objectMapper;
+
+    private final HttpServletRequest request;
+
+    @org.springframework.beans.factory.annotation.Autowired
+    public ParkingLotApiController(ObjectMapper objectMapper, HttpServletRequest request) {
+        this.objectMapper = objectMapper;
+        this.request = request;
+    }
+
+    public ResponseEntity<Void> addParkingLot(@Valid @RequestBody ParkingLot parkingLotItem) {
+        String accept = request.getHeader("Accept");
+        return new ResponseEntity<Void>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<Void> parkingLotParkingLotIdDelete(@PathVariable("parkingLotId") Long parkingLotId) {
+        String accept = request.getHeader("Accept");
+        return new ResponseEntity<Void>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<ParkingLot> parkingLotParkingLotIdGet(@PathVariable("parkingLotId") Long parkingLotId) {
+        String accept = request.getHeader("Accept");
+        if (accept != null && accept.contains("application/json")) {
+            try {
+                return new ResponseEntity<ParkingLot>(objectMapper.readValue("{  \"layout\" : [ {    \"name\" : \"name\",    \"available\" : 0  }, {    \"name\" : \"name\",    \"available\" : 0  } ],  \"pricing_policy\" : {    \"per_hour_fare\" : 2.1,    \"flat_fee\" : 1.1  },  \"name\" : \"Victoria 1 Parking Lot\",  \"id\" : 5}", ParkingLot.class), HttpStatus.NOT_IMPLEMENTED);
+            } catch (IOException e) {
+                log.error("Couldn't serialize response for content type application/json", e);
+                return new ResponseEntity<ParkingLot>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        }
+
+        return new ResponseEntity<ParkingLot>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<CarSlot> parkingLotParkingLotIdParkDelete(@PathVariable("parkingLotId") Long parkingLotId, @Valid @RequestBody CarSlot carSlotItem) {
+        String accept = request.getHeader("Accept");
+        if (accept != null && accept.contains("application/json")) {
+            try {
+                return new ResponseEntity<CarSlot>(objectMapper.readValue("{  \"arrival_time\" : \"2000-01-23T04:56:07.000+00:00\",  \"slot\" : 15,  \"type\" : \"25kW charging point\",  \"parking_lot_id\" : 0}", CarSlot.class), HttpStatus.NOT_IMPLEMENTED);
+            } catch (IOException e) {
+                log.error("Couldn't serialize response for content type application/json", e);
+                return new ResponseEntity<CarSlot>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        }
+
+        return new ResponseEntity<CarSlot>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<CarSlot> parkingLotParkingLotIdParkPost(@PathVariable("parkingLotId") Long parkingLotId, @Valid @RequestBody CarSlot carSlotItem) {
+        String accept = request.getHeader("Accept");
+        if (accept != null && accept.contains("application/json")) {
+            try {
+                return new ResponseEntity<CarSlot>(objectMapper.readValue("{  \"arrival_time\" : \"2000-01-23T04:56:07.000+00:00\",  \"slot\" : 15,  \"type\" : \"25kW charging point\",  \"parking_lot_id\" : 0}", CarSlot.class), HttpStatus.NOT_IMPLEMENTED);
+            } catch (IOException e) {
+                log.error("Couldn't serialize response for content type application/json", e);
+                return new ResponseEntity<CarSlot>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        }
+
+        return new ResponseEntity<CarSlot>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<ParkingLot> parkingLotPut(@Valid @RequestBody ParkingLot parkingLotItem) {
+        String accept = request.getHeader("Accept");
+        if (accept != null && accept.contains("application/json")) {
+            try {
+                return new ResponseEntity<ParkingLot>(objectMapper.readValue("{  \"layout\" : [ {    \"name\" : \"name\",    \"available\" : 0  }, {    \"name\" : \"name\",    \"available\" : 0  } ],  \"pricing_policy\" : {    \"per_hour_fare\" : 2.1,    \"flat_fee\" : 1.1  },  \"name\" : \"Victoria 1 Parking Lot\",  \"id\" : 5}", ParkingLot.class), HttpStatus.NOT_IMPLEMENTED);
+            } catch (IOException e) {
+                log.error("Couldn't serialize response for content type application/json", e);
+                return new ResponseEntity<ParkingLot>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        }
+
+        return new ResponseEntity<ParkingLot>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+    public ResponseEntity<List<ParkingLot>> searchParkingLot(@Valid @RequestParam(value = "searchString", required = false) String searchString) {
+        String accept = request.getHeader("Accept");
+        if (accept != null && accept.contains("application/json")) {
+            try {
+                return new ResponseEntity<List<ParkingLot>>(objectMapper.readValue("[ {  \"layout\" : [ {    \"name\" : \"name\",    \"available\" : 0  }, {    \"name\" : \"name\",    \"available\" : 0  } ],  \"pricing_policy\" : {    \"per_hour_fare\" : 2.1,    \"flat_fee\" : 1.1  },  \"name\" : \"Victoria 1 Parking Lot\",  \"id\" : 5}, {  \"layout\" : [ {    \"name\" : \"name\",    \"available\" : 0  }, {    \"name\" : \"name\",    \"available\" : 0  } ],  \"pricing_policy\" : {    \"per_hour_fare\" : 2.1,    \"flat_fee\" : 1.1  },  \"name\" : \"Victoria 1 Parking Lot\",  \"id\" : 5} ]", List.class), HttpStatus.NOT_IMPLEMENTED);
+            } catch (IOException e) {
+                log.error("Couldn't serialize response for content type application/json", e);
+                return new ResponseEntity<List<ParkingLot>>(HttpStatus.INTERNAL_SERVER_ERROR);
+            }
+        }
+
+        return new ResponseEntity<List<ParkingLot>>(HttpStatus.NOT_IMPLEMENTED);
+    }
+
+}

+ 60 - 0
src/main/java/eu/fibane/parkingtoll/core/InMemoryPersistanceManager.java

@@ -0,0 +1,60 @@
+package eu.fibane.parkingtoll.core;
+
+import eu.fibane.parkingtoll.model.ParkingLot;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class InMemoryPersistanceManager implements PersistanceManager {
+
+    private static final Map<Long, ParkingLot> parkingLotMap = new HashMap<>();
+    private static AtomicLong idCounter = new AtomicLong();
+
+    @Override
+    public Collection<ParkingLot> getAllParkingLots() {
+        //prevent user from deleting items from the collection
+        return Collections.unmodifiableCollection(parkingLotMap.values());
+    }
+
+    @Override
+    public ParkingLot addParkingLot(ParkingLot parkingLot) {
+        //check parking lot integrity
+        //we don't know what the user put
+        parkingLot.setId(createID());
+        parkingLotMap.put(parkingLot.getId(),parkingLot);
+        return parkingLot;
+    }
+
+    @Override
+    public ParkingLot getParkingLotById(Long id) {
+        return parkingLotMap.get(id);
+    }
+
+    @Override
+    public ParkingLot updateParkingLot(ParkingLot parkingLot) {
+        ParkingLot response;
+        if(parkingLot.getId() == null){
+            response = addParkingLot(parkingLot);
+        } else {
+            response = parkingLotMap.put(parkingLot.getId(), parkingLot);
+        }
+        return response;
+    }
+
+    @Override
+    public ParkingLot deleteParkingLot(ParkingLot parkingLot) {
+        return parkingLotMap.remove(parkingLot.getId());
+    }
+
+    @Override
+    public void clearDatabase() {
+        parkingLotMap.clear();
+        idCounter.set(0);
+    }
+
+    private static Long createID(){
+        return idCounter.getAndIncrement();
+    }
+
+
+}

+ 49 - 0
src/main/java/eu/fibane/parkingtoll/core/PersistanceManager.java

@@ -0,0 +1,49 @@
+package eu.fibane.parkingtoll.core;
+
+import eu.fibane.parkingtoll.model.ParkingLot;
+
+import java.math.BigInteger;
+import java.util.Collection;
+
+interface PersistanceManager {
+
+    /**
+     * Get all currently stored parking lots
+     * @return
+     */
+    public Collection<ParkingLot> getAllParkingLots();
+
+    /**
+     * Adds a ParkingLot in database and assigns it a new ID
+     * @param parkingLot the ParkingLot to add
+     * @return
+     */
+    public ParkingLot addParkingLot(ParkingLot parkingLot);
+
+    /**
+     * Search a parking lot by id
+     * @param id the id to look for
+     * @return the requested ParkingLot object
+     */
+    public ParkingLot getParkingLotById(Long id);
+
+    /**
+     * Update the specified ParkingLot in database. If it was not added previously, add it.
+     * @param parkingLot the new value of parkingLot
+     * @return the previous representation of parkingLot
+     */
+    public ParkingLot updateParkingLot(ParkingLot parkingLot);
+
+    /**
+     * Delete parking lot by id
+     * @param parkingLot parking lot to delete - id has to be filled
+     * @return the ParkingLot that was deleted, null if the parking lot was not found in the database
+     */
+    public ParkingLot deleteParkingLot(ParkingLot parkingLot);
+
+    /**
+     * Clear all data stored in the database
+     */
+    public void clearDatabase();
+
+}

+ 123 - 0
src/main/java/eu/fibane/parkingtoll/model/CarSlot.java

@@ -0,0 +1,123 @@
+package eu.fibane.parkingtoll.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Valid;
+import java.time.OffsetDateTime;
+import java.util.Objects;
+
+
+@Validated
+public class CarSlot   {
+  @JsonProperty("slot")
+  private Long slot = null;
+
+  @JsonProperty("parking_lot_id")
+  private Long parkingLotId = null;
+
+  @JsonProperty("arrival_time")
+  private OffsetDateTime arrivalTime = null;
+
+  @JsonProperty("type")
+  private String type = null;
+
+  public CarSlot slot(Long slot) {
+    this.slot = slot;
+    return this;
+  }
+
+  public Long getSlot() {
+    return slot;
+  }
+
+  public void setSlot(Long slot) {
+    this.slot = slot;
+  }
+
+  public CarSlot parkingLotId(Long parkingLotId) {
+    this.parkingLotId = parkingLotId;
+    return this;
+  }
+
+  public Long getParkingLotId() {
+    return parkingLotId;
+  }
+
+  public void setParkingLotId(Long parkingLotId) {
+    this.parkingLotId = parkingLotId;
+  }
+
+  public CarSlot arrivalTime(OffsetDateTime arrivalTime) {
+    this.arrivalTime = arrivalTime;
+    return this;
+  }
+
+  @Valid
+  public OffsetDateTime getArrivalTime() {
+    return arrivalTime;
+  }
+
+  public void setArrivalTime(OffsetDateTime arrivalTime) {
+    this.arrivalTime = arrivalTime;
+  }
+
+  public CarSlot type(String type) {
+    this.type = type;
+    return this;
+  }
+
+  public String getType() {
+    return type;
+  }
+
+  public void setType(String type) {
+    this.type = type;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CarSlot carSlot = (CarSlot) o;
+    return Objects.equals(this.slot, carSlot.slot) &&
+        Objects.equals(this.parkingLotId, carSlot.parkingLotId) &&
+        Objects.equals(this.arrivalTime, carSlot.arrivalTime) &&
+        Objects.equals(this.type, carSlot.type);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(slot, parkingLotId, arrivalTime, type);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class CarSlot {\n");
+
+    sb.append("    slot: ").append(toIndentedString(slot)).append("\n");
+    sb.append("    parkingLotId: ").append(toIndentedString(parkingLotId)).append("\n");
+    sb.append("    arrivalTime: ").append(toIndentedString(arrivalTime)).append("\n");
+    sb.append("    type: ").append(toIndentedString(type)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+}
+

+ 90 - 0
src/main/java/eu/fibane/parkingtoll/model/Layout.java

@@ -0,0 +1,90 @@
+package eu.fibane.parkingtoll.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Objects;
+
+/**
+ * Layout
+ */
+@Validated
+@javax.annotation.Generated(value = "io.swagger.codegen.languages.SpringCodegen", date = "2020-03-03T07:54:35.797Z")
+
+public class Layout   {
+  @JsonProperty("name")
+  private String name = null;
+
+  @JsonProperty("available")
+  private Long available = null;
+
+  public Layout name(String name) {
+    this.name = name;
+    return this;
+  }
+
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public Layout available(Long available) {
+    this.available = available;
+    return this;
+  }
+
+
+  public Long getAvailable() {
+    return available;
+  }
+
+  public void setAvailable(Long available) {
+    this.available = available;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    Layout layout = (Layout) o;
+    return Objects.equals(this.name, layout.name) &&
+        Objects.equals(this.available, layout.available);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(name, available);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class Layout {\n");
+
+    sb.append("    name: ").append(toIndentedString(name)).append("\n");
+    sb.append("    available: ").append(toIndentedString(available)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+}
+

+ 136 - 0
src/main/java/eu/fibane/parkingtoll/model/ParkingLot.java

@@ -0,0 +1,136 @@
+package eu.fibane.parkingtoll.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * ParkingLot
+ */
+@Validated
+public class ParkingLot   {
+  @JsonProperty("id")
+  private Long id = null;
+
+  @JsonProperty("name")
+  private String name = null;
+
+  @JsonProperty("layout")
+  @Valid
+  private List<Layout> layout = new ArrayList<Layout>();
+
+  @JsonProperty("pricing_policy")
+  private PricingPolicy pricingPolicy = null;
+
+  public ParkingLot id(Long id) {
+    this.id = id;
+    return this;
+  }
+
+  @NotNull
+  public Long getId() {
+    return id;
+  }
+
+  public void setId(Long id) {
+    this.id = id;
+  }
+
+  public ParkingLot name(String name) {
+    this.name = name;
+    return this;
+  }
+
+  @NotNull
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public ParkingLot layout(List<Layout> layout) {
+    this.layout = layout;
+    return this;
+  }
+
+  public ParkingLot addLayoutItem(Layout layoutItem) {
+    this.layout.add(layoutItem);
+    return this;
+  }
+
+  @NotNull  @Valid
+  public List<Layout> getLayout() {
+    return layout;
+  }
+
+  public void setLayout(List<Layout> layout) {
+    this.layout = layout;
+  }
+
+  public ParkingLot pricingPolicy(PricingPolicy pricingPolicy) {
+    this.pricingPolicy = pricingPolicy;
+    return this;
+  }
+
+  @NotNull @Valid
+  public PricingPolicy getPricingPolicy() {
+    return pricingPolicy;
+  }
+
+  public void setPricingPolicy(PricingPolicy pricingPolicy) {
+    this.pricingPolicy = pricingPolicy;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    ParkingLot parkingLot = (ParkingLot) o;
+    return Objects.equals(this.id, parkingLot.id) &&
+        Objects.equals(this.name, parkingLot.name) &&
+        Objects.equals(this.layout, parkingLot.layout) &&
+        Objects.equals(this.pricingPolicy, parkingLot.pricingPolicy);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(id, name, layout, pricingPolicy);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class ParkingLot {\n");
+
+    sb.append("    id: ").append(toIndentedString(id)).append("\n");
+    sb.append("    name: ").append(toIndentedString(name)).append("\n");
+    sb.append("    layout: ").append(toIndentedString(layout)).append("\n");
+    sb.append("    pricingPolicy: ").append(toIndentedString(pricingPolicy)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+}
+

+ 91 - 0
src/main/java/eu/fibane/parkingtoll/model/PricingPolicy.java

@@ -0,0 +1,91 @@
+package eu.fibane.parkingtoll.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Valid;
+import java.math.BigDecimal;
+import java.util.Objects;
+
+/**
+ * PricingPolicy
+ */
+@Validated
+
+public class PricingPolicy   {
+  @JsonProperty("flat_fee")
+  private BigDecimal flatFee = null;
+
+  @JsonProperty("per_hour_fare")
+  private BigDecimal perHourFare = null;
+
+  public PricingPolicy flatFee(BigDecimal flatFee) {
+    this.flatFee = flatFee;
+    return this;
+  }
+
+  @Valid
+  public BigDecimal getFlatFee() {
+    return flatFee;
+  }
+
+  public void setFlatFee(BigDecimal flatFee) {
+    this.flatFee = flatFee;
+  }
+
+  public PricingPolicy perHourFare(BigDecimal perHourFare) {
+    this.perHourFare = perHourFare;
+    return this;
+  }
+
+  @Valid
+  public BigDecimal getPerHourFare() {
+    return perHourFare;
+  }
+
+  public void setPerHourFare(BigDecimal perHourFare) {
+    this.perHourFare = perHourFare;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    PricingPolicy pricingPolicy = (PricingPolicy) o;
+    return Objects.equals(this.flatFee, pricingPolicy.flatFee) &&
+        Objects.equals(this.perHourFare, pricingPolicy.perHourFare);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(flatFee, perHourFare);
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    sb.append("class PricingPolicy {\n");
+
+    sb.append("    flatFee: ").append(toIndentedString(flatFee)).append("\n");
+    sb.append("    perHourFare: ").append(toIndentedString(perHourFare)).append("\n");
+    sb.append("}");
+    return sb.toString();
+  }
+
+  /**
+   * Convert the given object to string with each line indented by 4 spaces
+   * (except the first line).
+   */
+  private String toIndentedString(Object o) {
+    if (o == null) {
+      return "null";
+    }
+    return o.toString().replace("\n", "\n    ");
+  }
+}
+

+ 1 - 0
src/main/resources/application.properties

@@ -0,0 +1 @@
+

+ 13 - 0
src/test/java/eu/fibane/parkingtoll/ParkingtollApplicationTests.java

@@ -0,0 +1,13 @@
+package eu.fibane.parkingtoll;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class ParkingtollApplicationTests {
+
+	@Test
+	void contextLoads() {
+	}
+
+}

+ 188 - 0
src/test/java/eu/fibane/parkingtoll/core/InMemoryPersistanceManagerTest.java

@@ -0,0 +1,188 @@
+package eu.fibane.parkingtoll.core;
+
+import eu.fibane.parkingtoll.model.CarSlot;
+import eu.fibane.parkingtoll.model.Layout;
+import eu.fibane.parkingtoll.model.ParkingLot;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import javax.swing.*;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class InMemoryPersistanceManagerTest {
+    private long ids = 0;
+    private final PersistanceManager manager = new InMemoryPersistanceManager();
+    private final SecureRandom random = new SecureRandom();
+    @BeforeEach
+    void clearDatabase() {
+        manager.clearDatabase();
+    }
+
+    @Test
+    void testEmptyDatabase() {
+        assertEquals(0, manager.getAllParkingLots().size());
+        assertNull(manager.getParkingLotById(0L));
+        assertNull(manager.deleteParkingLot(getNewParkingLot()));
+    }
+
+    @Test
+    void addParkingLotTest() {
+        ParkingLot parkingLot = getNewParkingLot();
+        //call the service
+        ParkingLot returnedParkingLot = manager.addParkingLot(parkingLot);
+        assertEquals(1, manager.getAllParkingLots().size());
+
+        assertNotNull(returnedParkingLot);
+        assertNotNull(returnedParkingLot.getId());
+
+        //call again
+        parkingLot = getNewParkingLot();
+        returnedParkingLot = manager.addParkingLot(parkingLot);
+        assertNotNull(returnedParkingLot);
+        assertNotNull(returnedParkingLot.getId());
+        assertEquals(2, manager.getAllParkingLots().size());
+
+    }
+
+    private ParkingLot getNewParkingLot(){
+        ParkingLot parkingLot = new ParkingLot();
+        List<Layout> layouts = new ArrayList<>();
+        Layout layout = new Layout();
+        layout.setAvailable(random.nextLong());
+        layout.setName("Test Parking Lot " + random.nextLong());
+        layouts.add(layout);
+        layout = new Layout();
+        layout.setAvailable(random.nextLong());
+        layout.setName("Test Parking Lot " + random.nextLong());
+        layouts.add(layout);
+        parkingLot.setLayout(layouts);
+        return parkingLot;
+    }
+
+
+    @Test
+    void getAllParkingLots() {
+
+        List<ParkingLot> parkingLots = new ArrayList<>();
+        ParkingLot parkingLot;
+        for (int i = 0; i < 10; i++) {
+            parkingLot = getNewParkingLot();
+            parkingLots.add(parkingLot);
+            manager.addParkingLot(parkingLot);
+        }
+
+        ArrayList<ParkingLot> lots = new ArrayList<>(manager.getAllParkingLots());
+        assertEquals(10, lots.size());
+
+        for (int i = 0; i < parkingLots.size(); i++) {
+            assertEquals(parkingLots.get(i), lots.get(i));
+        }
+    }
+
+    @Test
+    void getParkingLotById() {
+        List<ParkingLot> parkingLots = new ArrayList<>();
+        for (int i = 0; i < 10; i++) {
+            parkingLots.add(getNewParkingLot());
+        }
+        for (ParkingLot parkingLot : parkingLots) {
+            manager.addParkingLot(parkingLot);
+        }
+
+        //Call service and check
+        for (ParkingLot parkingLot : parkingLots) {
+            assertEquals(parkingLot, manager.getParkingLotById(parkingLot.getId()));
+        }
+    }
+
+    @Test
+    void updateParkingLot() {
+        //first scenario, try to update an object that doesn't exist yet in database
+        ParkingLot parkingLot = getNewParkingLot();
+        assertEquals(0, manager.getAllParkingLots().size());
+        assertNull(parkingLot.getId());
+        parkingLot = manager.updateParkingLot(parkingLot);
+        assertEquals(1, manager.getAllParkingLots().size());
+        assertNotNull(parkingLot.getId());
+
+        ParkingLot parkingLot2 = getNewParkingLot();
+        //set the id of parking 1
+        parkingLot2.setId(parkingLot.getId());
+        ParkingLot parkingLotUpdated = manager.updateParkingLot(parkingLot2);
+        assertEquals(1, manager.getAllParkingLots().size());
+        assertEquals(parkingLotUpdated, parkingLot);
+
+    }
+
+    @Test
+    void deleteParkingLot() {
+        ParkingLot parkingLot = getNewParkingLot();
+        assertEquals(0, manager.getAllParkingLots().size());
+        manager.addParkingLot(parkingLot);
+        assertEquals(1, manager.getAllParkingLots().size());
+
+        //call the service
+        ParkingLot result = manager.deleteParkingLot(parkingLot);
+        assertEquals(result,parkingLot);
+        assertEquals(0, manager.getAllParkingLots().size());
+
+        result = manager.deleteParkingLot(parkingLot);
+        assertNull(result);
+        assertEquals(0, manager.getAllParkingLots().size());
+
+        manager.addParkingLot(parkingLot);
+        assertEquals(1, manager.getAllParkingLots().size());
+        //now try to delete something else
+        ParkingLot parkingLot1 = new ParkingLot();
+        parkingLot1.setId(parkingLot.getId() + 1);
+        result = manager.deleteParkingLot(parkingLot1);
+        assertEquals(1, manager.getAllParkingLots().size());
+        assertNull(result);
+    }
+
+    @Test
+    void testIDAllocation() throws ExecutionException, InterruptedException {
+        ExecutorService poolExecutor = Executors.newFixedThreadPool(10);
+
+
+        Callable<Void> myTask = () -> {
+            ParkingLot parkingLot;
+            for (int i = 0; i < 1000; i++) {
+                parkingLot = getNewParkingLot();
+                manager.addParkingLot(parkingLot);
+            }
+            return null;
+        };
+
+        List<Callable<Void>> callables = new ArrayList<>();
+
+        for (int i = 0; i < 10; i++) {
+            callables.add(myTask);
+        }
+
+
+        List<Future<Void>> futures = poolExecutor.invokeAll(callables);
+
+        //wait for finish
+        for (Future<Void> future : futures) {
+            future.get();
+        }
+
+        Collection<ParkingLot> parkingLots = manager.getAllParkingLots();
+        assertEquals(10_000, parkingLots.size());
+
+        Set<Long> ids = parkingLots.stream().map(ParkingLot::getId).collect(Collectors.toSet());
+        assertEquals(10_000,ids.size());
+    }
+
+
+
+}

+ 8 - 0
src/test/java/eu/fibane/parkingtoll/core/TestUtils.java

@@ -0,0 +1,8 @@
+package eu.fibane.parkingtoll.core;
+
+import eu.fibane.parkingtoll.model.ParkingLot;
+import net.bytebuddy.utility.RandomString;
+
+public class TestUtils {
+
+}