Compare commits

..
Author SHA1 Message Date
David Guler d0959f535b refactor: javadoc and dependencies in HashMap 2022-11-28 11:35:17 +01:00
20 changed files with 94 additions and 193 deletions
@@ -1,14 +0,0 @@
package ch.zhaw.gartenverwaltung;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
@FXML
private Label welcomeText;
@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
}
@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotates a method to be executed after all dependencies annotates with {@link Inject} * Annotates a method to be executed after all dependencies annotated with {@link Inject}
* have been injected. * have been injected.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@@ -1,7 +1,12 @@
package ch.zhaw.gartenverwaltung.bootstrap; package ch.zhaw.gartenverwaltung.bootstrap;
import ch.zhaw.gartenverwaltung.HelloApplication; import ch.zhaw.gartenverwaltung.HelloApplication;
import ch.zhaw.gartenverwaltung.io.*; import ch.zhaw.gartenverwaltung.io.CropList;
import ch.zhaw.gartenverwaltung.io.JsonCropList;
import ch.zhaw.gartenverwaltung.io.JsonPlantList;
import ch.zhaw.gartenverwaltung.io.JsonTaskList;
import ch.zhaw.gartenverwaltung.io.PlantList;
import ch.zhaw.gartenverwaltung.io.TaskList;
import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.Garden;
import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantListModel;
@@ -18,6 +23,10 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
/**
* Class responsible for bootstrapping the application wide dependencies
* and injecting them into JavaFX Controllers.
*/
public class AppLoader { public class AppLoader {
/** /**
* Caching the panes * Caching the panes
@@ -27,18 +36,24 @@ public class AppLoader {
/** /**
* Application-wide dependencies * Application-wide dependencies
*/ */
private final PlantList plantList = new JsonPlantList(); private final Map<String, Object> dependencies = new HashMap<>();
private final CropList cropList = new JsonCropList();
private final TaskList taskList = new JsonTaskList();
private final GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList);
private final WeatherGradenTaskPlanner weatherGradenTaskPlanner = new WeatherGradenTaskPlanner(taskList,plantList,cropList);
private final Garden garden = new Garden(gardenSchedule, cropList);
public AppLoader() throws IOException { public AppLoader() throws IOException {
} PlantList plantList = new JsonPlantList();
CropList cropList = new JsonCropList();
TaskList taskList = new JsonTaskList();
GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList);
dependencies.put(PlantList.class.getSimpleName(), plantList);
dependencies.put(CropList.class.getSimpleName(), cropList);
dependencies.put(TaskList.class.getSimpleName(), taskList);
dependencies.put(PlantListModel.class.getSimpleName(), new PlantListModel(plantList));
dependencies.put(GardenSchedule.class.getSimpleName(), gardenSchedule);
dependencies.put(Garden.class.getSimpleName(), new Garden(gardenSchedule, cropList));
dependencies.put(AppLoader.class.getSimpleName(), this);
}
/** /**
* Loads and returns a {@link Pane} (cached). * Loads and returns a {@link Pane} (cached).
@@ -131,26 +146,18 @@ public class AppLoader {
}); });
Arrays.stream(controller.getClass().getMethods()) Arrays.stream(controller.getClass().getMethods())
.filter(method -> method.isAnnotationPresent(AfterInject.class)) .filter(method -> method.isAnnotationPresent(AfterInject.class) && method.getParameterCount() == 0)
.forEach(afterInjectMethod -> { .forEach(afterInjectMethod -> {
if (afterInjectMethod.getParameterCount() == 0) {
try { try {
afterInjectMethod.invoke(controller); afterInjectMethod.invoke(controller);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
// TODO: Log
e.printStackTrace(); e.printStackTrace();
} }
}
}); });
} }
private Object getAppDependency(Class<?> type) { private Object getAppDependency(Class<?> type) {
return switch (type.getSimpleName()) { return dependencies.get(type.getSimpleName());
case "Garden" -> garden;
case "PlantList" -> plantList;
case "PlantListModel" -> new PlantListModel(plantList);
case "GardenSchedule" -> gardenSchedule;
case "AppLoader" -> this;
default -> null;
};
} }
} }
@@ -3,11 +3,20 @@ package ch.zhaw.gartenverwaltung.bootstrap;
import javafx.event.Event; import javafx.event.Event;
import javafx.event.EventType; import javafx.event.EventType;
/**
* Represents an event that should lead to a view being changed.
*/
public class ChangeViewEvent extends Event { public class ChangeViewEvent extends Event {
private final String view; private final String view;
public static final EventType<ChangeViewEvent> CHANGE_MAIN_VIEW = new EventType<>("CHANGE_MAIN_VIEW"); public static final EventType<ChangeViewEvent> CHANGE_MAIN_VIEW = new EventType<>("CHANGE_MAIN_VIEW");
/**
* Creates an Event that should lead to the main view being changed.
*
* @param eventType The {@link EventType<ChangeViewEvent>} specifying which view should be changed.
* @param view The filename of the View to be changed to
*/
public ChangeViewEvent(EventType<? extends Event> eventType, String view) { public ChangeViewEvent(EventType<? extends Event> eventType, String view) {
super(eventType); super(eventType);
this.view = view; this.view = view;
@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotates a Field to be injected from the application-dependencies * Annotates a Field to be injected from the application-dependencies.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
@@ -6,6 +6,10 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
/**
* Represents a List of {@link Crop}s.
* The interface specifies the operations to add/update and remove entries.
*/
public interface CropList { public interface CropList {
/** /**
* Yields a list of all {@link Crop}s in the database. * Yields a list of all {@link Crop}s in the database.
@@ -1,10 +1,18 @@
package ch.zhaw.gartenverwaltung.io; package ch.zhaw.gartenverwaltung.io;
/**
* Provides an sequential ID starting from the given initial Value.
*/
public class IdProvider { public class IdProvider {
private long currentId; private long currentId;
public IdProvider(long initialValue) { public IdProvider(long initialValue) {
currentId = initialValue; currentId = initialValue;
} }
/**
* Yields the next ID in the sequence.
* @return The next ID
*/
public long incrementAndGet() { public long incrementAndGet() {
return ++currentId; return ++currentId;
} }
@@ -19,6 +19,11 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
/**
* Implements the {@link CropList} interface for reading and writing {@link Crop} objects
* from and to a local JSON file.
* The reads are cached to minimize file-io operations.
*/
public class JsonCropList implements CropList { public class JsonCropList implements CropList {
private final URL dataSource; private final URL dataSource;
@@ -40,7 +45,7 @@ public class JsonCropList implements CropList {
} }
/** /**
* Default constructor * Default constructor. Uses a file from the app resources.
*/ */
public JsonCropList() { public JsonCropList() {
this.dataSource = getClass().getResource("user-crops.json"); this.dataSource = getClass().getResource("user-crops.json");
@@ -20,8 +20,8 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
/** /**
* Implements the {@link PlantList} interface for loading {@link Plant} objects * Implements the {@link PlantList} interface for reading {@link Plant} objects
* from a JSON file. * from a local JSON file.
* The reads are cached to minimize file-io operations. * The reads are cached to minimize file-io operations.
*/ */
public class JsonPlantList implements PlantList { public class JsonPlantList implements PlantList {
@@ -44,9 +44,17 @@ public class JsonPlantList implements PlantList {
imageModule.addDeserializer(Image.class, new PlantImageDeserializer()); imageModule.addDeserializer(Image.class, new PlantImageDeserializer());
} }
/**
* Default constructor. Uses a file from the app resources.
*/
public JsonPlantList() { public JsonPlantList() {
this.dataSource = getClass().getResource("plantdb.json"); this.dataSource = getClass().getResource("plantdb.json");
} }
/**
* Constructor to use a specified {@link URL} as a {@link #dataSource}
* @param dataSource A {@link URL} to the file to be used as a data source
*/
public JsonPlantList(URL dataSource) { public JsonPlantList(URL dataSource) {
this.dataSource = dataSource; this.dataSource = dataSource;
} }
@@ -67,7 +75,7 @@ public class JsonPlantList implements PlantList {
} }
/** /**
* @see PlantList#getPlantById(long) * @see PlantList#getPlantById(HardinessZone, long)
*/ */
@Override @Override
public Optional<Plant> getPlantById(HardinessZone zone, long id) throws HardinessZoneNotSetException, IOException { public Optional<Plant> getPlantById(HardinessZone zone, long id) throws HardinessZoneNotSetException, IOException {
@@ -20,8 +20,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Implements the {@link TaskList} interface for loading and writing {@link Task} objects * Implements the {@link TaskList} interface for reading and writing {@link Task} objects
* from and to a JSON file. * from and to a local JSON file.
* The reads are cached to minimize file-io operations. * The reads are cached to minimize file-io operations.
*/ */
public class JsonTaskList implements TaskList { public class JsonTaskList implements TaskList {
@@ -45,9 +45,17 @@ public class JsonTaskList implements TaskList {
timeModule.addSerializer(LocalDate.class, dateSerializer); timeModule.addSerializer(LocalDate.class, dateSerializer);
} }
/**
* Default constructor. Uses a file from the app resources.
*/
public JsonTaskList() { public JsonTaskList() {
this.dataSource = getClass().getResource("taskdb.json"); this.dataSource = getClass().getResource("taskdb.json");
} }
/**
* Constructor to use a specified {@link URL} as a {@link #dataSource}
* @param dataSource A {@link URL} to the file to be used as a data source
*/
public JsonTaskList(URL dataSource) { public JsonTaskList(URL dataSource) {
this.dataSource = dataSource; this.dataSource = dataSource;
} }
@@ -8,7 +8,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
* A database of {@link Plant}s. * A List of {@link Plant}s.
* The interface specifies the minimal required operations. * The interface specifies the minimal required operations.
*/ */
public interface PlantList { public interface PlantList {
@@ -1,5 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
public enum SevereWeather {
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
}
@@ -7,8 +7,8 @@ import java.time.LocalDate;
import java.util.List; import java.util.List;
/** /**
* A database of {@link Task}s. * Represents a List of {@link Task}s.
* The interface specifies the minimal required operations. * The interface specifies the operations to add/update and remove entries.
*/ */
public interface TaskList { public interface TaskList {
/** /**
@@ -1,93 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.types.*;
import java.io.IOException;
import java.time.LocalDate;
import java.util.List;
public class WeatherGradenTaskPlanner {
private final TaskList taskList;
private final PlantList plantList;
private final CropList cropList;
WeatherService weatherService;
private final LocalDate dateSevereWeather = LocalDate.of(22,12,15);
public WeatherGradenTaskPlanner(TaskList taskList, PlantList plantList, CropList cropList) {
this.taskList = taskList;
this.plantList = plantList;
this.cropList = cropList;
weatherService = new WeatherService();
}
public void refreshTasks() throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
getSevereWeatherEvents();
getRainAmount();
}
private void getSevereWeatherEvents() throws IOException {
SevereWeather actualWeather = weatherService.causeSevereWeather(0);
if (SevereWeather.HAIL.equals(actualWeather)) {
createPreHail();
} else if (SevereWeather.FROST.equals(actualWeather)) {
createPreFrost();
} else if (SevereWeather.SNOW.equals(actualWeather)) {
createPreSnow();
}
}
private void getRainAmount() throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
int rainAmount = weatherService.causeRainAmount(3);
adjustWateringTask(rainAmount);
}
public void createPreHail() throws IOException {
Task preHailTask = new Task("Hail",
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
dateSevereWeather.minusDays(1L));
preHailTask.withId(Long.MAX_VALUE);
taskList.saveTask(preHailTask);
}
public void createPreFrost() throws IOException {
Task preFrostTask = new Task("Frost",
"The temperatur falls below zero degrees, cover especially the root with wool",
dateSevereWeather.minusDays(1L));
preFrostTask.withId(Long.MAX_VALUE);
taskList.saveTask(preFrostTask);
}
public void createPreSnow() throws IOException {
Task preSnowTask = new Task("Snow",
"The weather brings little snowfall. Cover your crops",
dateSevereWeather.minusDays(1L));
preSnowTask.withId(Long.MAX_VALUE);
taskList.saveTask(preSnowTask);
}
public void adjustWateringTask(int rainAmount) throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
for (Crop crop : cropList.getCrops()) {
Plant plant = plantList.getPlantById(HardinessZone.ZONE_8A,crop.getPlantId()).orElseThrow(PlantNotFoundException::new);
for (GrowthPhase growthphase : plant.lifecycle()) {
if(growthphase.wateringCycle().litersPerSqM() < rainAmount){
adjustNextExecutionOfWateringTask(taskList.getTaskList(LocalDate.now(), LocalDate.now().plusDays(7)));
}
}
}
}
private void adjustNextExecutionOfWateringTask(List<Task> cropTaskList){
for(Task task : cropTaskList){
if(task.getName().equals("watering task")){
task.setNextExecution(task.getNextExecution().plusDays(task.getInterval().orElse(1)));
}
}
}
}
@@ -1,29 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
public class WeatherService {
private static final int NO_RAIN = 0;
private static final int LITTLE_RAIN = 15;
private static final int RAIN = 25;
private static final int HEAVY_RAIN = 50;
public SevereWeather causeSevereWeather(int randomWeather) {
return switch (randomWeather) {
case 1 -> SevereWeather.HAIL;
case 2 -> SevereWeather.SNOW;
case 3 -> SevereWeather.FROST;
default -> null;
};
}
public int causeRainAmount(int randomRainAmount) {
return switch (randomRainAmount) {
case 1 -> NO_RAIN;
case 2 -> LITTLE_RAIN;
case 3 -> RAIN;
case 4 -> HEAVY_RAIN;
default -> -1;
};
}
}
@@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException; import java.io.IOException;
/**
* Used by the Jackson Library to deserialize a String to a {@link GrowthPhaseType}
*/
public class GrowthPhaseTypeDeserializer extends StdDeserializer<GrowthPhaseType> { public class GrowthPhaseTypeDeserializer extends StdDeserializer<GrowthPhaseType> {
public GrowthPhaseTypeDeserializer(Class<?> vc) { public GrowthPhaseTypeDeserializer(Class<?> vc) {
super(vc); super(vc);
@@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException; import java.io.IOException;
/**
* Used by the Jackson Library to deserialize a String to a {@link HardinessZone}
*/
public class HardinessZoneDeserializer extends StdDeserializer<HardinessZone> { public class HardinessZoneDeserializer extends StdDeserializer<HardinessZone> {
public HardinessZoneDeserializer(Class<?> vc) { public HardinessZoneDeserializer(Class<?> vc) {
super(vc); super(vc);
@@ -13,6 +13,9 @@ import java.io.InputStream;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
/**
* Used by the Jackson Library to deserialize a String to a {@link Image}
*/
public class PlantImageDeserializer extends JsonDeserializer<Image> { public class PlantImageDeserializer extends JsonDeserializer<Image> {
@Override @Override
@@ -52,13 +52,6 @@ public class GardenSchedule {
for (GrowthPhase growthPhase : plant.lifecycleForGroup(growPhaseGroup)) { for (GrowthPhase growthPhase : plant.lifecycleForGroup(growPhaseGroup)) {
for (TaskTemplate taskTemplate : growthPhase.taskTemplates()) { for (TaskTemplate taskTemplate : growthPhase.taskTemplates()) {
addTask(taskTemplate.generateTask(crop.getStartDate(), crop.getCropId().orElse(0L))); addTask(taskTemplate.generateTask(crop.getStartDate(), crop.getCropId().orElse(0L)));
}
//TODO add wateringtask
if(growthPhase.wateringCycle() != null){
addTask(new Task("watering Task", "pour water over the plant circa : "+ growthPhase.wateringCycle().litersPerSqM() +" per square meter",
growthPhase.startDate().atYear(LocalDate.now().getYear()), growthPhase.endDate().atYear(LocalDate.now().getYear()),
growthPhase.wateringCycle().interval(), crop.getCropId().orElse(0L)));
} }
} }
} }
@@ -40,15 +40,6 @@ public class Task {
this.cropId = cropId; this.cropId = cropId;
} }
/**
* Constructor for weather events
*/
public Task(String name, String description, LocalDate startDate) {
this.name = name;
this.description = description;
this.startDate = startDate;
}
public Task(String name, String description, LocalDate startDate, LocalDate endDate, int interval, long cropId) { public Task(String name, String description, LocalDate startDate, LocalDate endDate, int interval, long cropId) {
this.name = name; this.name = name;
this.description = description; this.description = description;