diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/HardinessZoneNotSetException.java b/src/main/java/ch/zhaw/gartenverwaltung/io/HardinessZoneNotSetException.java new file mode 100644 index 0000000..cbb7015 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/HardinessZoneNotSetException.java @@ -0,0 +1,7 @@ +package ch.zhaw.gartenverwaltung.io; + +public class HardinessZoneNotSetException extends Exception { + public HardinessZoneNotSetException() { + super("HardinessZone must be set to retrieve plants!"); + } +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantDatabase.java b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantDatabase.java index e589bc8..4ae2435 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantDatabase.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantDatabase.java @@ -11,12 +11,25 @@ import java.net.URL; import java.time.MonthDay; import java.time.format.DateTimeFormatter; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; +/** + * Implements the {@link PlantDatabase} interface for loading {@link Plant} objects + * from a JSON file. + * The reads are cached to minimize file-io operations. + */ public class JsonPlantDatabase implements PlantDatabase { private final URL dataSource = getClass().getResource("plantdb.json"); + private HardinessZone currentZone; + private Map plantMap = Collections.emptyMap(); + + /** + * Creating constant objects required to deserialize the {@link MonthDay} classes + */ private final static JavaTimeModule timeModule = new JavaTimeModule(); static { DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("MM-dd"); @@ -24,27 +37,62 @@ public class JsonPlantDatabase implements PlantDatabase { timeModule.addDeserializer(MonthDay.class, dateDeserializer); } + /** + * If no data is currently loaded, or the specified zone differs + * from the {@link #currentZone}, data is loaded from {@link #dataSource}. + * In any case, the values of {@link #plantMap} are returned. + * + * @see PlantDatabase#getPlantList(HardinessZone) + */ @Override - public List getPlantList(HardinessZone zone) throws IOException { - List result = Collections.emptyList(); + public List getPlantList(HardinessZone zone) throws IOException, HardinessZoneNotSetException { + if (zone == null) { + throw new HardinessZoneNotSetException(); + } + if (plantMap.isEmpty() || zone != currentZone) { + loadPlantList(zone); + } + return plantMap.values().stream().toList(); + } + /** + * @see PlantDatabase#getPlantById(long) + */ + @Override + public Optional getPlantById(long id) throws HardinessZoneNotSetException, IOException { + if (currentZone == null) { + throw new HardinessZoneNotSetException(); + } + if (plantMap.isEmpty()) { + loadPlantList(currentZone); + } + return Optional.ofNullable(plantMap.get(id)); + } + + /** + * Loads the database from {@link #dataSource} and updates the cached data. + * + * @param zone The {@link HardinessZone} for which data is to be loaded + * @throws IOException If the database cannot be accessed + */ + private void loadPlantList(HardinessZone zone) throws IOException { if (dataSource != null) { + currentZone = zone; ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(timeModule); + List result; result = mapper.readerForListOf(Plant.class).readValue(dataSource); - } - for (Plant plant : result) { - plant.inZone(zone); - } - return result; - } + for (Plant plant : result) { + plant.inZone(currentZone); + } - @Override - public Optional getPlantById(long id, HardinessZone zone) throws IOException { - return getPlantList(zone).stream() - .filter(plant -> plant.id() != id) - .findFirst(); + // Turn list into a HashMap with structure id => Plant + plantMap = result.stream() + .collect(HashMap::new, + (res, plant) -> res.put(plant.id(), plant), + (existing, replacement) -> { }); + } } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/PlantDatabase.java b/src/main/java/ch/zhaw/gartenverwaltung/io/PlantDatabase.java index 4b8fe85..0b6908d 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/PlantDatabase.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/PlantDatabase.java @@ -7,7 +7,28 @@ import java.io.IOException; import java.util.List; import java.util.Optional; +/** + * A database of {@link Plant}s. + * The interface specifies the minimal required operations. + */ public interface PlantDatabase { - List getPlantList(HardinessZone zone) throws IOException; - Optional getPlantById(long id, HardinessZone zone) throws IOException; + /** + * Yields a list of all {@link Plant}s in the database with only data relevant to the specfied {@link HardinessZone} + * + * @param zone The zone for which data should be fetched + * @return A list of {@link Plant}s with data for the specified zone + * @throws IOException If the database cannot be accessed + * @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified + */ + List getPlantList(HardinessZone zone) throws IOException, HardinessZoneNotSetException; + + /** + * Attempts to retrieve the {@link Plant} with the specified id. + * + * @param id The {@link Plant#id()} to look for + * @return {@link Optional} of the found {@link Plant}, {@link Optional#empty()} if no entry matched the criteria + * @throws IOException If the database cannot be accessed + * @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified + */ + Optional getPlantById(long id) throws IOException, HardinessZoneNotSetException; }