aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTharre <tharre3@gmail.com>2018-05-11 15:49:43 +0200
committerTharre <tharre3@gmail.com>2018-05-11 15:49:43 +0200
commitf7d14a76123911f0bced08356a0c69e61147cb1b (patch)
treea75b0baa891453a14046c78503603d21986126c5 /src
parentacd6b64e494192f7c73032240029bfa53dccb362 (diff)
parent5298356db60cd971fed686d379130102843db819 (diff)
downloadsepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.tar.gz
sepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.tar.xz
sepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.zip
Merge branch 'develop'
Diffstat (limited to 'src')
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/application/MainApplication.java52
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateCarController.java116
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateNewEmployeeController.java117
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowController.java204
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/DBOperationDAO.java161
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/EmployeeDatabaseDao.java124
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/OperationDAO.java2
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDAO.java7
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAO.java106
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/VehicleDatabaseDao.java147
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Employee.java12
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/EmployeeValidator.java23
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Operation.java16
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Registration.java8
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/RegistrationValidator.java194
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Vehicle.java14
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/EmployeeServiceImpl.java49
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/OperationServiceImpl.java131
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationService.java7
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImpl.java62
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/VehicleServiceImpl.java99
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/ui/vehiclepane/VehiclePaneController.java84
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/userInterface/CreateOperationController.java227
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java13
-rw-r--r--src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/SpringFXMLLoader.java212
-rw-r--r--src/main/resources/fxml/CreateOperationController.fxml95
-rw-r--r--src/main/resources/fxml/RegistrationWindow.fxml76
-rw-r--r--src/main/resources/fxml/createCar.fxml17
-rw-r--r--src/main/resources/fxml/createNewEmployee.fxml24
-rw-r--r--src/main/resources/fxml/vehiclePane.fxml70
-rw-r--r--src/main/resources/images/NEF.pngbin0 -> 327 bytes
-rw-r--r--src/main/resources/images/Not.pngbin0 -> 872 bytes
-rw-r--r--src/main/resources/images/NotNEF.pngbin0 -> 1042 bytes
-rw-r--r--src/main/resources/images/Qualification.pngbin0 -> 1029 bytes
-rw-r--r--src/main/resources/images/Vehicle.pngbin0 -> 964 bytes
-rw-r--r--src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql5
-rw-r--r--src/main/resources/sql/H2RegistrationDAOTest_populate.sql15
-rw-r--r--src/main/resources/sql/database.sql20
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java53
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java168
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java148
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeApplication.java53
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeControllerTest.java85
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java155
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTest.java68
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTestConfiguration.java19
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationPersistenceTest.java109
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceComponentTest.java130
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceUnitTest.java155
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/Helper.java28
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/HighDpiAwareApplicationTest.java24
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/ScaledBounds.java34
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CarAddTestService.java283
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleApplication.java51
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleControllerTest.java79
-rw-r--r--src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/VehicleServiceTestConfiguration.java19
-rw-r--r--src/test/resources/employeeServiceTestData.xml12
57 files changed, 4141 insertions, 41 deletions
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/application/MainApplication.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/application/MainApplication.java
new file mode 100644
index 0000000..01c04d3
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/application/MainApplication.java
@@ -0,0 +1,52 @@
+package at.ac.tuwien.sepm.assignment.groupphase.application;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.userInterface.CreateOperationController;
+import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+@Component
+@ComponentScan("at.ac.tuwien.sepm.assignment.groupphase")
+public class MainApplication extends Application {
+
+ private static AnnotationConfigApplicationContext configApplicationContext;
+
+ public static void main(String[] args) {
+ Application.launch(MainApplication.class, args);
+ }
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ primaryStage.setTitle("Einsatz erstellen");
+ primaryStage.centerOnScreen();
+ primaryStage.setOnCloseRequest(event -> Platform.exit());
+
+ configApplicationContext = new AnnotationConfigApplicationContext(MainApplication.class);
+ final var fxmlLoader = configApplicationContext.getBean(SpringFXMLLoader.class);
+ primaryStage.setScene(
+ new Scene(
+ (Parent)
+ fxmlLoader.load(
+ getClass()
+ .getResourceAsStream(
+ "/fxml/CreateOperationController.fxml"))));
+
+ CreateOperationController controller =
+ configApplicationContext.getBean(CreateOperationController.class);
+ controller.updateList();
+ primaryStage.show();
+ primaryStage.toFront();
+ }
+
+ @Override
+ public void stop() throws Exception {
+ super.stop();
+ configApplicationContext.close();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateCarController.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateCarController.java
new file mode 100644
index 0000000..b6693d0
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateCarController.java
@@ -0,0 +1,116 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.lang.invoke.MethodHandles;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javafx.collections.FXCollections;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Button;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ChoiceBox;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class CreateCarController {
+
+ @FXML private ChoiceBox<String> cmb_Ctyp;
+ @FXML private ChoiceBox<String> cmb_typ;
+ @FXML private Button btn_cancel;
+ @FXML private CheckBox cbx_NEF;
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private final VehicleService vehicleService;
+
+ public CreateCarController(VehicleService vehicleService) {
+ this.vehicleService = vehicleService;
+ }
+
+ @FXML
+ public void initialize() {
+ cmb_Ctyp.setItems(
+ FXCollections.observableArrayList(
+ Stream.of(
+ ConstructionType.NORMAL,
+ ConstructionType.MITTELHOCHDACH,
+ ConstructionType.HOCHDACH)
+ .map(Enum::toString)
+ .collect(Collectors.toList())));
+ cmb_Ctyp.setValue(ConstructionType.NORMAL.toString());
+ cmb_typ.setItems(
+ FXCollections.observableArrayList(
+ Stream.of(
+ VehicleType.BKTW,
+ VehicleType.KTW_B,
+ VehicleType.KTW,
+ VehicleType.RTW,
+ VehicleType.NEF,
+ VehicleType.NAH)
+ .map(Enum::toString)
+ .collect(Collectors.toList())));
+ cmb_typ.setValue(VehicleType.BKTW.toString());
+ }
+
+ @FXML
+ public void onCancelClicked() {
+ ((Stage) btn_cancel.getScene().getWindow()).close();
+ }
+
+ @FXML
+ public void createCar(ActionEvent actionEvent) {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(parseConstructionType())
+ .type(parseType())
+ .name("")
+ .status(Status.ABGEMELDET)
+ .hasNef(cbx_NEF.isSelected())
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException e) {
+ LOG.error("Invalid Vehicle: {}", e);
+ createComplete(AlertType.ERROR, "Ungültige Eingabe", e.getMessage());
+ return;
+ } catch (ServiceException e) {
+ LOG.error("Exception: {}", e);
+ createComplete(AlertType.ERROR, "Fehler", e.getMessage());
+ return;
+ }
+ createComplete(
+ AlertType.CONFIRMATION, "Speichern Erfolgreich", "Auto wurde erfolgreich angelegt");
+ }
+
+ private ConstructionType parseConstructionType() {
+ if (cmb_Ctyp.getSelectionModel().getSelectedItem() == null) {
+ return ConstructionType.NORMAL;
+ }
+ return ConstructionType.valueOf(cmb_Ctyp.getSelectionModel().getSelectedItem().toString());
+ }
+
+ private VehicleType parseType() {
+ if (cmb_typ.getSelectionModel().getSelectedItem() == null) {
+ return VehicleType.BKTW;
+ }
+ return VehicleType.valueOf(cmb_typ.getSelectionModel().getSelectedItem().toString());
+ }
+
+ private void createComplete(AlertType alertType, String headerText, String contentText) {
+ Alert alert = new Alert(alertType, contentText, ButtonType.OK);
+ alert.setHeaderText(headerText);
+ alert.showAndWait();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateNewEmployeeController.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateNewEmployeeController.java
new file mode 100644
index 0000000..d81f6d7
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/CreateNewEmployeeController.java
@@ -0,0 +1,117 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidEmployeeException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.lang.invoke.MethodHandles;
+import java.time.LocalDate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javafx.collections.FXCollections;
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Button;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.CheckBox;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.Hyperlink;
+import javafx.scene.control.TextField;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class CreateNewEmployeeController {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private final EmployeeService employeeService;
+
+ @FXML private CheckBox inputIsDriver;
+ @FXML private CheckBox inputIsPilot;
+ @FXML private Hyperlink btnCancel;
+ @FXML private Button btnCreate;
+ @FXML private TextField inputName;
+ @FXML private ChoiceBox<String> inputQualification;
+
+ public CreateNewEmployeeController(EmployeeService employeeService) {
+ this.employeeService = employeeService;
+ }
+
+ @FXML
+ public void initialize() {
+ inputQualification.setItems(
+ FXCollections.observableArrayList(
+ Stream.of(
+ EducationLevel.RS,
+ EducationLevel.NFS,
+ EducationLevel.NKV,
+ EducationLevel.NKA,
+ EducationLevel.NKI,
+ EducationLevel.NA)
+ .map(Enum::toString)
+ .collect(Collectors.toList())));
+
+ inputQualification.setValue(EducationLevel.RS.toString());
+ }
+
+ @FXML
+ public void onCancelClicked() {
+ ((Stage) inputQualification.getScene().getWindow()).close();
+ }
+
+ @FXML
+ public void onCreateClicked() {
+
+ Employee employee =
+ Employee.builder()
+ .name(inputName.getText())
+ .educationLevel(parseEducationLevel())
+ .birthday(LocalDate.MIN) // TODO: change UI to include birthday field
+ .isDriver(inputIsDriver.isSelected())
+ .isPilot(inputIsPilot.isSelected())
+ .build();
+
+ try {
+ employeeService.add(employee);
+ } catch (InvalidEmployeeException e) {
+ LOG.error("Invalid Employee: {}", e);
+
+ showModalDialogWithOkButton(
+ AlertType.ERROR,
+ "Ungültige Eingabe",
+ "Mindestens eines der Eingabefelder haben einen ungültigen Wert!");
+ return;
+ } catch (ServiceException e) {
+ LOG.error("Employee could not be saved: {}", e);
+
+ showModalDialogWithOkButton(
+ AlertType.ERROR,
+ "Speicherfehler",
+ "Der Eintrag konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.");
+ return;
+ }
+
+ showModalDialogWithOkButton(
+ AlertType.INFORMATION,
+ "Erfolgreich angelegt",
+ "Mitarbeiter wurde erfolgreich angelegt und gespeichert!");
+ }
+
+ private void showModalDialogWithOkButton(
+ AlertType alertType, String headerText, String contentText) {
+ Alert alert = new Alert(alertType, contentText, ButtonType.OK);
+ alert.setHeaderText(headerText);
+ alert.showAndWait();
+ }
+
+ private EducationLevel parseEducationLevel() {
+ if (inputQualification.getSelectionModel().getSelectedItem() == null) {
+ return EducationLevel.RS;
+ }
+ return EducationLevel.valueOf(inputQualification.getSelectionModel().getSelectedItem());
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowController.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowController.java
new file mode 100644
index 0000000..bf413bb
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowController.java
@@ -0,0 +1,204 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.RegistrationService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class RegistrationWindowController {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegistrationWindowController.class);
+
+ private EmployeeService employeeService;
+
+ private VehicleService vehicleService;
+
+ private RegistrationService registrationService;
+
+ @Autowired
+ public void setEmployeeService(EmployeeService employeeService) {
+ this.employeeService = employeeService;
+ }
+
+ @Autowired
+ public void setVehicleService(VehicleService vehicleService) {
+ this.vehicleService = vehicleService;
+ }
+
+ @Autowired
+ public void setRegistrationService(RegistrationService registrationService) {
+ this.registrationService = registrationService;
+ }
+
+ @FXML public ChoiceBox<Integer> cbStart;
+ @FXML public ChoiceBox<Integer> cbEnd;
+ @FXML public Label lVehicles;
+ @FXML public Label lEmployees;
+ @FXML public TextField tfVehicleSearch;
+ @FXML public TextField tfEmployeeSearch;
+ @FXML public TableView<Vehicle> tvVehicles;
+ @FXML public TableView<Employee> tvEmployees;
+ @FXML public TableColumn<Vehicle, String> tcVehicles;
+ @FXML public TableColumn<Employee, String> tcEmployees;
+
+ private Vehicle chosenVehicle;
+ private List<Employee> chosenEmployees = new LinkedList<>();
+
+ @FXML
+ public void initialize() {
+ // will have to be replaced for FlowPane
+ try {
+ List<Vehicle> vehicles = vehicleService.list(EnumSet.of(Status.ABGEMELDET));
+ tcVehicles.setCellValueFactory(x -> new SimpleStringProperty(x.getValue().name()));
+ tvVehicles.setItems(FXCollections.observableArrayList(vehicles));
+ } catch (ServiceException e) {
+ LOG.warn(
+ "Caught ServiceException while getting vehicles. Showing it to user. Error message: {}",
+ e.getMessage());
+ Alert alert = new Alert(AlertType.ERROR);
+ alert.setTitle("Fahrzeuge - Fehler!");
+ alert.setHeaderText("Beim Auflisten der Fahrzeug ist ein Fehler aufgetreten.");
+ alert.setContentText(e.getMessage());
+ alert.show();
+ }
+ try {
+ List<Employee> employees = employeeService.list();
+ tcEmployees.setCellValueFactory(x -> new SimpleStringProperty(x.getValue().name()));
+ tvEmployees.setItems(FXCollections.observableArrayList(employees));
+ } catch (ServiceException e) {
+ LOG.warn(
+ "Caught ServiceException while getting employees. Showing it to user. Error message: {}",
+ e.getMessage());
+ Alert alert = new Alert(AlertType.ERROR);
+ alert.setTitle("Personal - Fehler!");
+ alert.setHeaderText("Beim Auflisten des Personals ist ein Fehler aufgetreten.");
+ alert.setContentText(e.getMessage());
+ alert.show();
+ }
+ tvVehicles.setOnMousePressed(
+ mouseEvent -> {
+ if (mouseEvent.isPrimaryButtonDown() && mouseEvent.getClickCount() == 2) {
+ chosenVehicle = tvVehicles.getSelectionModel().getSelectedItem();
+ if (chosenVehicle == null) {
+ return;
+ }
+ lVehicles.setText(chosenVehicle.name());
+ }
+ });
+ tvEmployees.setOnMousePressed(
+ mouseEvent -> {
+ if (mouseEvent.isPrimaryButtonDown() && mouseEvent.getClickCount() == 2) {
+ chosenEmployees.add(tvEmployees.getSelectionModel().getSelectedItem());
+ if (chosenEmployees == null) {
+ return;
+ }
+ StringBuilder text = new StringBuilder();
+ for (Employee employee : chosenEmployees) {
+ text.append(employee.name()).append("\n");
+ }
+ lEmployees.setText(text.toString());
+ }
+ });
+ ObservableList<Integer> hours =
+ FXCollections.observableArrayList(
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23);
+ cbStart.setItems(hours);
+ cbStart.setValue(0);
+ cbEnd.setItems(hours);
+ cbEnd.setValue(12);
+ }
+
+ public void cancel() {
+ LOG.debug("Cancel Button clicked");
+ ((Stage) lVehicles.getScene().getWindow()).close();
+ }
+
+ public void create() {
+ LOG.debug("Create Button clicked");
+
+ List<Registration> registrations = new LinkedList<>();
+
+ for (Employee employee : chosenEmployees) {
+ registrations.add(
+ Registration.builder()
+ .id(chosenVehicle.id())
+ .employee(employee)
+ .start(
+ LocalDateTime.of(
+ LocalDate.now(),
+ LocalTime.of(cbStart.getValue(), 0))
+ .toInstant(OffsetDateTime.now().getOffset()))
+ .end(
+ LocalDateTime.of(
+ LocalDate.now(),
+ LocalTime.of(cbEnd.getValue(), 0))
+ .toInstant(OffsetDateTime.now().getOffset()))
+ .build());
+ }
+ try {
+ registrationService.add(chosenVehicle.id(), registrations);
+ ((Stage) lVehicles.getScene().getWindow()).close();
+ } catch (InvalidVehicleException e) {
+ // NOT THROWN ANYWHERE RIGHT NOW
+ LOG.info(
+ "Caught InvalidVehicleException. Showing it to user. Error message: {}",
+ e.getClass().toString(),
+ e.getMessage());
+ Alert alert = new Alert(AlertType.WARNING);
+ alert.setTitle("Ungültiges Fahrzeug");
+ alert.setHeaderText("Das spezifizierte Fahrzeug ist nicht gültig.");
+ alert.setContentText(e.getMessage());
+ alert.show();
+ } catch (ServiceException e) {
+ LOG.warn(
+ "Caught ServiceException while getting vehicles. Showing it to user. Error message: {}",
+ e.getMessage());
+ Alert alert = new Alert(AlertType.ERROR);
+ alert.setTitle("Anmeldung - Fehler!");
+ alert.setHeaderText("Beim Erstellen der Anmeldung ist ein Fehler aufgetreten.");
+ alert.setContentText(e.getMessage());
+ alert.show();
+ } catch (InvalidRegistrationException e) {
+ LOG.info(
+ "Caught InvalidRegistrationException. Showing it to user. Error message: {}",
+ e.getMessage());
+ Alert alert = new Alert(AlertType.WARNING);
+ alert.setTitle("Ungültige Eingabe");
+ alert.setHeaderText(
+ "Die gewählte Kombination von Fahrzeug und Personal ist nicht gültig!");
+ alert.setContentText(e.getMessage());
+ alert.show();
+ }
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/DBOperationDAO.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/DBOperationDAO.java
new file mode 100644
index 0000000..672424a
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/DBOperationDAO.java
@@ -0,0 +1,161 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ElementNotFoundException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.EnumSet;
+import java.util.List;
+
+public class DBOperationDAO implements OperationDAO {
+
+ private JDBCConnectionManager jdbcConnectionManager;
+
+ public DBOperationDAO(JDBCConnectionManager j) {
+ jdbcConnectionManager = j;
+ }
+
+ @Override
+ public long add(Operation operation) throws PersistenceException {
+ if (operation == null) {
+ throw new PersistenceException("Das der Datenbank übergebene Objekt ist fehlerhaft!");
+ }
+ PreparedStatement pstmt = null;
+ try {
+ pstmt =
+ jdbcConnectionManager
+ .getConnection()
+ .prepareStatement(
+ "INSERT INTO operation(opCode, severity, "
+ + "created, destination, additionalInfo, status) values (?,?,?,?,?,?)",
+ java.sql.Statement.RETURN_GENERATED_KEYS);
+
+ if (operation.opCode() == null) {
+ throw new PersistenceException("Code darf nicht null sein!");
+ } else if (operation.opCode().length() > 20)
+ throw new PersistenceException(
+ "Länge des OP-Codes überschreitet erlaubte Länge von 100 Zeichen!");
+ else pstmt.setString(1, operation.opCode());
+ /*switch (operation.severity()) {
+ case A:
+ pstmt.setInt(2, 0);
+ break;
+ case B:
+ pstmt.setInt(2, 1);
+ break;
+ case C:
+ pstmt.setInt(2, 2);
+ break;
+ case D:
+ pstmt.setInt(2, 3);
+ break;
+ case E:
+ pstmt.setInt(2, 4);
+ break;
+ case O:
+ pstmt.setInt(2, 5);
+ break;
+ default:
+ throw new PersistenceException(
+ "Schwere des Einsatzes konnte nicht validiert werden!");
+ }*/
+ pstmt.setString(2, operation.severity().name());
+ if (operation.created() != null) {
+ pstmt.setTimestamp(3, Timestamp.from(operation.created()));
+ } else {
+ throw new PersistenceException("Zeitpunkt der Erstellung darf nicht null sein!");
+ }
+
+ if (operation.destination() == null) {
+ throw new PersistenceException("Einsatzort darf nicht null sein!");
+ } else if (operation.destination().length() > 100) {
+ throw new PersistenceException(
+ "Länge der Adresse überschreitet erlaubte Länge von 100 Zeichen!");
+ } else {
+ pstmt.setString(4, operation.destination());
+ }
+ if (operation.additionalInfo().length() > 100)
+ throw new PersistenceException(
+ "Länge der zusätzlichen Information überschreitet erlaubte Länge von 100 Zeichen!");
+ else pstmt.setString(5, operation.additionalInfo());
+ if (operation.status() == null) {
+ throw new PersistenceException("Status darf nicht null sein!");
+ } else if (operation.status().toString().length() > 100) {
+ throw new PersistenceException(
+ "Länge des Status überschreitet erlaubte Länge von 100 Zeichen!");
+ } else {
+ pstmt.setString(6, operation.status().toString());
+ }
+ pstmt.executeUpdate();
+ ResultSet rs = pstmt.getGeneratedKeys();
+ if (rs.next()) return rs.getInt(1);
+ else throw new PersistenceException("Einsatz konnte nicht gespeichert werden");
+ } catch (SQLException e) {
+ throw new PersistenceException(e);
+ } finally {
+ if (pstmt != null) {
+ try {
+ pstmt.close();
+ } catch (SQLException e) {
+ throw new PersistenceException(
+ "Verbindung zur Datenbank konnte nicht geschlossen werden!", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void update(Operation operation) throws ElementNotFoundException, PersistenceException {}
+
+ @Override
+ public Operation get(long operationId) throws ElementNotFoundException, PersistenceException {
+ return null;
+ }
+
+ @Override
+ public List<Operation> list(EnumSet<Status> statuses) throws PersistenceException {
+ return null;
+ }
+
+ @Override
+ public int connectVehicleToOperation(long vehicleID, long operationID)
+ throws PersistenceException {
+ PreparedStatement pstmt = null;
+ try {
+ pstmt =
+ jdbcConnectionManager
+ .getConnection()
+ .prepareStatement(
+ "insert into VehicleOperation(vehicleId, operationId)"
+ + "values (?,?)");
+ pstmt.setLong(1, vehicleID);
+ pstmt.setLong(2, operationID);
+ pstmt.executeUpdate();
+
+ /*
+ ResultSet rs = pstmt.getGeneratedKeys();
+ if (rs.next()) return rs.getInt(1);
+ else
+ throw new PersistenceException(
+ "Fahrzeug für die Operation konnte nicht abgespeichert werden!");*/
+ } catch (SQLException e) {
+ throw new PersistenceException("Die Werte konnten nicht gespeichert werden!");
+ } finally {
+ if (pstmt != null) {
+ try {
+ pstmt.close();
+ } catch (SQLException e) {
+ throw new PersistenceException(
+ "Verbindung zur Datenbank konnte nicht geschlossen werden!", e);
+ }
+ }
+ }
+
+ return 1;
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/EmployeeDatabaseDao.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/EmployeeDatabaseDao.java
new file mode 100644
index 0000000..3e4ba12
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/EmployeeDatabaseDao.java
@@ -0,0 +1,124 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ElementNotFoundException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.lang.invoke.MethodHandles;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class EmployeeDatabaseDao implements EmployeeDAO {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private static final String INSERT_EMPLOYEE_VERSION =
+ "INSERT INTO EmployeeVersion(name, birthday, educationLevel, isDriver, isPilot) "
+ + "VALUES(?, ?, ?, ?, ?)";
+ private static final String INSERT_EMPLOYEE = "INSERT INTO Employee(version) VALUES(?)";
+ private static final String LIST_EMPLOYEE =
+ "SELECT emp.id, v.name, v.birthday, v.educationLevel, v.isDriver, v.isPilot "
+ + "FROM employee emp "
+ + "JOIN EmployeeVersion v ON v.id = emp.version";
+
+ private final PreparedStatement insertEmployeeVersion, insertEmployee, listEmployee;
+
+ public EmployeeDatabaseDao(JDBCConnectionManager connectionManager)
+ throws PersistenceException {
+
+ try {
+
+ final var connection = connectionManager.getConnection();
+ insertEmployeeVersion =
+ connection.prepareStatement(
+ INSERT_EMPLOYEE_VERSION, Statement.RETURN_GENERATED_KEYS);
+ insertEmployee =
+ connection.prepareStatement(INSERT_EMPLOYEE, Statement.RETURN_GENERATED_KEYS);
+
+ listEmployee = connection.prepareStatement(LIST_EMPLOYEE);
+
+ } catch (SQLException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ @Override
+ public long add(Employee employee) throws PersistenceException {
+
+ // Assumption: the given employee is already validated (from service)
+ try {
+ insertEmployeeVersion.setString(1, employee.name());
+ insertEmployeeVersion.setTimestamp(
+ 2, Timestamp.valueOf(employee.birthday().atStartOfDay()));
+ insertEmployeeVersion.setString(3, employee.educationLevel().toString());
+ insertEmployeeVersion.setBoolean(4, employee.isDriver());
+ insertEmployeeVersion.setBoolean(5, employee.isPilot());
+ insertEmployeeVersion.executeUpdate();
+ ResultSet resultSetEmployeeVersion = insertEmployeeVersion.getGeneratedKeys();
+ if (resultSetEmployeeVersion.next()) {
+ long versionId = resultSetEmployeeVersion.getLong(1);
+
+ insertEmployee.setLong(1, versionId);
+ insertEmployee.executeUpdate();
+
+ ResultSet resultSetEmployee = insertEmployee.getGeneratedKeys();
+ if (resultSetEmployee.next()) {
+ return resultSetEmployee.getLong(1);
+ }
+ }
+
+ throw new PersistenceException("Employee was not created");
+
+ } catch (SQLException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ @Override
+ public void update(Employee employee) throws ElementNotFoundException, PersistenceException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Employee> list() throws PersistenceException {
+
+ try {
+ ResultSet rs = listEmployee.executeQuery();
+
+ List<Employee> employees = new ArrayList<>();
+ while (rs.next()) {
+
+ Employee employee =
+ Employee.builder()
+ .id(rs.getLong(1))
+ .name(rs.getString(2))
+ .birthday(rs.getTimestamp(3).toLocalDateTime().toLocalDate())
+ .educationLevel(EducationLevel.valueOf(rs.getString(4)))
+ .isDriver(rs.getBoolean(5))
+ .isPilot(rs.getBoolean(6))
+ .build();
+
+ employees.add(employee);
+ }
+
+ return employees;
+
+ } catch (SQLException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ @Override
+ public void remove(long id) throws ElementNotFoundException, PersistenceException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/OperationDAO.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/OperationDAO.java
index 7f28005..dd1a189 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/OperationDAO.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/OperationDAO.java
@@ -45,4 +45,6 @@ public interface OperationDAO {
* @throws PersistenceException if loading the stored operations failed
*/
List<Operation> list(EnumSet<Status> statuses) throws PersistenceException;
+
+ int connectVehicleToOperation(long vehicleID, long operationID) throws PersistenceException;
}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDAO.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDAO.java
index f2c461a..ba8f909 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDAO.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDAO.java
@@ -3,6 +3,7 @@ package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
import at.ac.tuwien.sepm.assignment.groupphase.exception.ElementNotFoundException;
import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import java.util.List;
public interface RegistrationDAO {
@@ -10,11 +11,11 @@ public interface RegistrationDAO {
* Persist the given registration.
*
* @param vehicleId the id of the target vehicle
- * @param registration that should be stored
- * @return the id that was assigned
+ * @param registrations that should be stored
+ * @return a list of the ids that were assigned
* @throws PersistenceException if the registration could not be persisted
*/
- long add(long vehicleId, Registration registration) throws PersistenceException;
+ List<Long> add(long vehicleId, List<Registration> registrations) throws PersistenceException;
/**
* Make registration with the given id inactive.
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAO.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAO.java
new file mode 100644
index 0000000..8fbcd18
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAO.java
@@ -0,0 +1,106 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ElementNotFoundException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.util.LinkedList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class RegistrationDatabaseDAO implements RegistrationDAO {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegistrationDatabaseDAO.class);
+
+ private static final String ADD_REGISTRATION =
+ "INSERT INTO Registration (vehicleId, employeeId, start, end, active) VALUES (?,?,?,?,?);";
+ private static final String UPDATE_VEHICLE =
+ "UPDATE Vehicle SET status = 'FREI_WACHE' WHERE id = ?;";
+
+ private PreparedStatement addRegistration;
+ private PreparedStatement updateVehicle;
+
+ private Connection connection;
+
+ @Autowired
+ public RegistrationDatabaseDAO(JDBCConnectionManager connectionManager)
+ throws PersistenceException {
+ try {
+ connection = connectionManager.getConnection();
+ addRegistration =
+ connection.prepareStatement(ADD_REGISTRATION, Statement.RETURN_GENERATED_KEYS);
+ updateVehicle = connection.prepareStatement(UPDATE_VEHICLE);
+ } catch (SQLException e) {
+ LOG.error("Could not get connection or preparation of statement failed");
+ throw new PersistenceException(e);
+ }
+ }
+
+ @Override
+ public List<Long> add(long vehicleId, List<Registration> registrations)
+ throws PersistenceException {
+ List<Long> returnValues = new LinkedList<>();
+ try {
+ connection.setAutoCommit(false);
+ for (Registration registration : registrations) {
+ addRegistration.setLong(1, vehicleId);
+ addRegistration.setLong(2, registration.employee().id());
+ addRegistration.setTimestamp(3, Timestamp.from(registration.start()));
+ addRegistration.setObject(4, registration.end());
+ addRegistration.setBoolean(
+ 5, true); // ASSUMPTION: Registration gets created as active
+ addRegistration.executeUpdate();
+ try (ResultSet rs = addRegistration.getGeneratedKeys()) {
+ if (rs.next()) {
+ returnValues.add(rs.getLong(1));
+ } else {
+ LOG.error("No ResultSet was created while adding registration");
+ throw new PersistenceException(
+ "Anmeldung konnte nicht gespeichert werden.");
+ }
+ }
+ }
+
+ updateVehicle.setLong(1, vehicleId);
+ updateVehicle.executeUpdate();
+
+ connection.commit();
+ return returnValues;
+ } catch (SQLException e) {
+ LOG.error(
+ "An SQLException occurred while trying to save registrations to database. "
+ + "Attempting a rollback. Error message: {}",
+ e.getMessage());
+ try {
+ connection.rollback();
+ } catch (SQLException e1) {
+ LOG.error("Rollback failed :(");
+ }
+ throw new PersistenceException(e);
+ } finally {
+ try {
+ connection.setAutoCommit(true);
+ } catch (SQLException e) {
+ LOG.error(
+ "Setting back AutoCommit to false failed! Error message: {}",
+ e.getMessage());
+ // SonarLint insists on me not throwing anything here...
+ }
+ }
+ }
+
+ @Override
+ public void remove(long id) throws ElementNotFoundException, PersistenceException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/VehicleDatabaseDao.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/VehicleDatabaseDao.java
new file mode 100644
index 0000000..ca1d45c
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/VehicleDatabaseDao.java
@@ -0,0 +1,147 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ElementNotFoundException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class VehicleDatabaseDao implements VehicleDAO {
+
+ private final JDBCConnectionManager jdbcConnectionManager;
+
+ public VehicleDatabaseDao(JDBCConnectionManager j) {
+ jdbcConnectionManager = j;
+ }
+
+ public long add(Vehicle vehicle) throws PersistenceException {
+ String query1 =
+ "INSERT INTO VehicleVersion (name,hasNef,constructionType,type) VALUES (?,?,?,?)";
+ String query2 = "INSERT INTO Vehicle (version,status) VALUES (?,?)";
+ PreparedStatement p1 = null;
+ PreparedStatement p2 = null;
+ PreparedStatement p3 = null;
+ String status = "ABGEMELDET";
+ String name = "";
+ int id = -1;
+ try {
+ p1 =
+ jdbcConnectionManager
+ .getConnection()
+ .prepareStatement(query1, PreparedStatement.RETURN_GENERATED_KEYS);
+ p1.setString(1, name);
+ p1.setBoolean(2, vehicle.hasNef());
+ p1.setString(3, vehicle.constructionType().name());
+ if (vehicle.type() == VehicleType.KTW_B) {
+ p1.setString(4, "KTW-B");
+ } else {
+ p1.setString(4, vehicle.type().name());
+ }
+ p1.executeUpdate();
+
+ ResultSet keyResultSet = p1.getGeneratedKeys();
+
+ if (keyResultSet.next()) {
+ id = keyResultSet.getInt(1);
+ }
+
+ name = vehicle.type().name() + "-" + id;
+
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ } finally {
+ try {
+ p1.close();
+
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ }
+ }
+ try {
+ query1 = "UPDATE VehicleVersion SET name=? WHERE id=?";
+ p3 = jdbcConnectionManager.getConnection().prepareStatement(query1);
+ p3.setString(1, name);
+ p3.setInt(2, id);
+ p3.executeUpdate();
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ } finally {
+ try {
+ p3.close();
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ }
+ }
+ try {
+ p2 = jdbcConnectionManager.getConnection().prepareStatement(query2);
+ p2.setInt(1, id);
+ p2.setString(2, status);
+ p2.executeUpdate();
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ } finally {
+ try {
+ p2.close();
+ } catch (SQLException e) {
+ throw new PersistenceException("SQL Excpetion : " + e.toString());
+ }
+ }
+ return id;
+ }
+
+ @Override
+ public void update(Vehicle vehicle) throws ElementNotFoundException, PersistenceException {}
+
+ @Override
+ public List<Vehicle> list() throws PersistenceException {
+ PreparedStatement pstmt = null;
+ List<Vehicle> result = new LinkedList<>();
+ try {
+ pstmt =
+ jdbcConnectionManager
+ .getConnection()
+ .prepareStatement(
+ "Select * from VehicleVersion, "
+ + "Vehicle where VehicleVersion.id=Vehicle.version");
+ pstmt.executeQuery();
+ ResultSet rs = pstmt.getResultSet();
+ while (rs.next()) {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .name(rs.getString("name"))
+ .constructionType(
+ ConstructionType.valueOf(rs.getString("constructionType")))
+ .status(Status.valueOf(rs.getString("status")))
+ .id(rs.getInt("id"))
+ .hasNef(rs.getBoolean("hasNef"))
+ .type(VehicleType.valueOf(rs.getString("type").replace("-", "_")))
+ .build();
+ result.add(vehicle);
+ }
+ } catch (SQLException e) {
+ throw new PersistenceException("Die Werte konnten nicht geladen werden.", e);
+ } finally {
+ if (pstmt != null) {
+ try {
+ pstmt.close();
+ } catch (SQLException e) {
+ throw new PersistenceException(
+ "Verbindung zur Datenbank konnte nicht geschlossen werden!", e);
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void remove(long id) throws ElementNotFoundException, PersistenceException {}
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Employee.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Employee.java
index bbb5117..583bf5b 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Employee.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Employee.java
@@ -14,17 +14,17 @@ public abstract class Employee {
NA
}
- abstract long id();
+ public abstract long id();
- abstract String name();
+ public abstract String name();
- abstract LocalDate birthday();
+ public abstract LocalDate birthday();
- abstract EducationLevel educationLevel();
+ public abstract EducationLevel educationLevel();
- abstract boolean isDriver();
+ public abstract boolean isDriver();
- abstract boolean isPilot();
+ public abstract boolean isPilot();
public static Builder builder() {
return new AutoValue_Employee.Builder().id(0);
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/EmployeeValidator.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/EmployeeValidator.java
new file mode 100644
index 0000000..d7fa9aa
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/EmployeeValidator.java
@@ -0,0 +1,23 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto;
+
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidEmployeeException;
+
+public class EmployeeValidator {
+
+ public static boolean validate(Employee employee) throws InvalidEmployeeException {
+
+ if (employee.name() == null || employee.name().trim().length() == 0) {
+ throw new InvalidEmployeeException("name not set");
+ }
+
+ if (employee.birthday() == null) {
+ throw new InvalidEmployeeException("birthday not set");
+ }
+
+ if (employee.educationLevel() == null) {
+ throw new InvalidEmployeeException("educationLevel not set");
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Operation.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Operation.java
index bfb03c7..6641437 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Operation.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Operation.java
@@ -22,22 +22,22 @@ public abstract class Operation {
CANCELLED,
}
- abstract long id();
+ public abstract long id();
- abstract String opCode();
+ public abstract String opCode();
- abstract Severity severity();
+ public abstract Severity severity();
- abstract Status status();
+ public abstract Status status();
- abstract List<Vehicle> vehicles();
+ public abstract List<Vehicle> vehicles();
@Nullable
- abstract Instant created();
+ public abstract Instant created();
- abstract String destination();
+ public abstract String destination();
- abstract String additionalInfo();
+ public abstract String additionalInfo();
public static Builder builder() {
return new AutoValue_Operation.Builder().id(0);
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Registration.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Registration.java
index f917406..8551266 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Registration.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Registration.java
@@ -5,13 +5,13 @@ import java.time.Instant;
@AutoValue
public abstract class Registration {
- abstract long id();
+ public abstract long id();
- abstract Instant start();
+ public abstract Instant start();
- abstract Instant end();
+ public abstract Instant end();
- abstract Employee employee();
+ public abstract Employee employee();
public static Builder builder() {
return new AutoValue_Registration.Builder().id(0);
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/RegistrationValidator.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/RegistrationValidator.java
new file mode 100644
index 0000000..295b615
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/RegistrationValidator.java
@@ -0,0 +1,194 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RegistrationValidator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegistrationValidator.class);
+
+ private RegistrationValidator() {}
+
+ public static void validate(Vehicle vehicle, List<Registration> registrations)
+ throws InvalidVehicleException, InvalidRegistrationException {
+ /*
+ Vehicles and Employees are assumed to be valid.
+ They have been checked at creation, and for them to be checked again, access to
+ VehicleValidator and EmployeeValidator are needed, which are not available at this time.
+ */
+ /*
+ The method used here goes as follows: All given employees are inspected in regards to their
+ qualifications, and added to the appropriate lists of the roles they could fill.
+ For example, an NFS, who is also a driver, would be added to the lists driverIds, nfsIds
+ and rsIds (because an NFS can always substitute an RS).
+ Afterwards, the number of people is checked according to the chosen vehicle type, and if
+ the number is okay, the program tries to find a valid combination of roles for the vehicle.
+ For example, for an RTW, first a driver is chosen, their ID marked as found in the aptly
+ titled HashMap, and then for the second RS, the list of RS is checked, excluding the chosen
+ driver. If no other valid RS is found, the next possible driver is chosen, and so on. If no
+ valid combination is found, an InvalidRegistrationException is thrown.
+ */
+ List<Long> pilotIds = new LinkedList<>();
+ List<Long> driverIds = new LinkedList<>();
+ List<Long> naIds = new LinkedList<>();
+ List<Long> nfsIds = new LinkedList<>();
+ List<Long> rsIds = new LinkedList<>();
+ HashMap<Long, Boolean> found =
+ new HashMap<>(); // needed later in DFS, checks that no person is chosen twice
+ int total = 0;
+ for (Registration registration : registrations) {
+ total++;
+ if (found.put(registration.employee().id(), false) != null) {
+ LOG.info("Employee with ID {} was added twice", registration.employee().id());
+ throw new InvalidRegistrationException(
+ "Person with the ID: "
+ + registration.employee().id()
+ + " was added more than once!");
+ }
+ if (registration.employee().isPilot()) {
+ pilotIds.add(registration.employee().id());
+ }
+ if (registration.employee().isDriver()) {
+ driverIds.add(registration.employee().id());
+ }
+ if (registration.employee().educationLevel() == EducationLevel.NA) {
+ naIds.add(registration.employee().id());
+ nfsIds.add(registration.employee().id());
+ rsIds.add(registration.employee().id());
+ } else if (isNFS(registration.employee())) {
+ nfsIds.add(registration.employee().id());
+ rsIds.add(registration.employee().id());
+ } else { // only RS left
+ rsIds.add(registration.employee().id());
+ }
+ }
+ if (total <= 0) {
+ LOG.info("No employees were added");
+ throw new InvalidRegistrationException("Kein Personal ausgewählt!");
+ }
+ if (vehicle.type() == VehicleType.NAH) {
+ /*
+ NAH
+ 1 Pilot
+ 1 NFS
+ 1 NA
+ 3-4 Personen
+ */
+ if (total < 3) {
+ LOG.info("Too few employees for NAH");
+ throw new InvalidRegistrationException("Zu wenig Personal für NAH!");
+ } else if (total > 4) {
+ LOG.info("Too many employees for NAH");
+ throw new InvalidRegistrationException("Zu viel Personal für NAH!");
+ }
+ for (long pilot_id : pilotIds) {
+ found.put(pilot_id, true);
+ for (long na_id : naIds) {
+ if (found.get(na_id)) continue;
+ found.put(na_id, true);
+ for (long nfs_id : nfsIds) {
+ if (found.get(nfs_id)) continue;
+ LOG.info("Valid combination found for NAH");
+ return;
+ }
+ found.put(na_id, false);
+ }
+ found.put(pilot_id, false);
+ }
+ LOG.info("No valid combination of employees found for NAH");
+ throw new InvalidRegistrationException(
+ "Keine gültige Kombination von Personen für NAH!");
+ } else if (vehicle.type() == VehicleType.NEF) {
+ /*
+ NEF
+ 1 Driver (has to be NFS)
+ 1 NA
+ */
+ if (total < 2) {
+ LOG.info("Too few employees for NEF");
+ throw new InvalidRegistrationException("Zu wenig Personal für NEF!");
+ } else if (total > 3) {
+ LOG.info("Too many employees for NEF");
+ throw new InvalidRegistrationException("Zu viel Personal für NEF!");
+ }
+ for (long driver_id : driverIds) {
+ if (!nfsIds.contains(driver_id))
+ continue; // if possible driver is not NFS, skip him
+ found.put(driver_id, true);
+ for (long na_id : naIds) {
+ if (found.get(na_id)) continue;
+ LOG.info("Valid combinaion found for NEF");
+ return;
+ }
+ found.put(driver_id, false);
+ }
+ LOG.info("No valid combination of employees found for NEF");
+ throw new InvalidRegistrationException(
+ "Keine gültige Kombination von Personen für NEF!");
+ } else if (vehicle.type() == VehicleType.BKTW) {
+ /*
+ BKTW
+ 1 Driver
+ */
+ if (total > 3) {
+ LOG.info("Too many employees for BKTW");
+ throw new InvalidRegistrationException("Zu viel Personal für BKTW!");
+ }
+ if (!driverIds.isEmpty()) {
+ LOG.info("Valid combination found for BKTW");
+ return;
+ }
+ LOG.info("No driver was found for BKTW");
+ throw new InvalidRegistrationException("Kein Fahrer gefunden für BKTW!");
+ } else { // KTW or RTW, both have the same requirements
+ /*
+ RTW/KTW
+ 1 Driver
+ 1 RS
+ */
+ if (total < 2) {
+ LOG.info("Too few employees for {}", vehicle.type().name());
+ throw new InvalidRegistrationException(
+ "Zu wenig Personal für " + vehicle.type().name() + "!");
+ } else if (total > 4) {
+ LOG.info("Too many employees for {}", vehicle.type().name());
+ throw new InvalidRegistrationException(
+ "Zu viel Persoanl für " + vehicle.type().name() + "!");
+ }
+ for (long driver_id : driverIds) { // driver includes rs
+ found.put(driver_id, true);
+ for (long rs_id : rsIds) {
+ if (found.get(rs_id)) continue;
+ LOG.info("Valid combination found for {}", vehicle.type().name());
+ return;
+ }
+ }
+ LOG.info("No valid combination of employees found for {}", vehicle.type().name());
+ throw new InvalidRegistrationException(
+ "Keine gültige Kombination von Personen für " + vehicle.type().name() + "!");
+ }
+ }
+
+ private static boolean isNFS(Employee employee) {
+ EducationLevel educationLevel = employee.educationLevel();
+ switch (educationLevel) {
+ case NFS:
+ return true;
+ case NKA:
+ return true;
+ case NKI:
+ return true;
+ case NKV:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Vehicle.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Vehicle.java
index 29698da..84d9c92 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Vehicle.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dto/Vehicle.java
@@ -31,20 +31,20 @@ public abstract class Vehicle {
FREI_FUNK,
}
- abstract long id();
+ public abstract long id();
- abstract String name();
+ public abstract String name();
- abstract ConstructionType constructionType();
+ public abstract ConstructionType constructionType();
- abstract VehicleType type();
+ public abstract VehicleType type();
- abstract Status status();
+ public abstract Status status();
- abstract boolean hasNef();
+ public abstract boolean hasNef();
@Nullable
- abstract List<Registration> registrations();
+ public abstract List<Registration> registrations();
public static Builder builder() {
return new AutoValue_Vehicle.Builder().id(0);
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/EmployeeServiceImpl.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/EmployeeServiceImpl.java
new file mode 100644
index 0000000..ed0fb1c
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/EmployeeServiceImpl.java
@@ -0,0 +1,49 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.EmployeeValidator;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidEmployeeException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.util.List;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmployeeServiceImpl implements EmployeeService {
+
+ private final EmployeeDAO employeePersistence;
+
+ public EmployeeServiceImpl(EmployeeDAO employeePersistence) {
+ this.employeePersistence = employeePersistence;
+ }
+
+ @Override
+ public long add(Employee employee) throws InvalidEmployeeException, ServiceException {
+
+ EmployeeValidator.validate(employee);
+ try {
+ return employeePersistence.add(employee);
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ @Override
+ public Employee update(Employee employee) throws InvalidEmployeeException, ServiceException {
+ return null;
+ }
+
+ @Override
+ public List<Employee> list() throws ServiceException {
+
+ try {
+ return employeePersistence.list();
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ @Override
+ public void remove(long id) throws InvalidEmployeeException, ServiceException {}
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/OperationServiceImpl.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/OperationServiceImpl.java
new file mode 100644
index 0000000..05a548c
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/OperationServiceImpl.java
@@ -0,0 +1,131 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.OperationDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Severity;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidOperationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.util.EnumSet;
+import java.util.List;
+import javafx.collections.transformation.SortedList;
+
+public class OperationServiceImpl implements OperationService {
+
+ // TODO: anders?
+ private OperationDAO operationDAO;
+
+ public OperationServiceImpl(OperationDAO dao) {
+ this.operationDAO = dao;
+ }
+
+ @Override
+ public long add(Operation operation) throws InvalidOperationException, ServiceException {
+ List<Vehicle> vehicles = operation.vehicles();
+ boolean rtw = false;
+ if (faultyInput(operation.opCode())) {
+ throw new InvalidOperationException("Code ist ungültig!");
+ }
+ if (faultyInput(operation.destination())) {
+ throw new InvalidOperationException("Adresse ist ungültig!");
+ }
+ if (operation.vehicles().size() == 0) {
+ throw new InvalidOperationException(
+ "Es muss mindestens ein Fahrzeug ausgewählt werden!");
+ }
+ for (Vehicle vehicle : vehicles) {
+ if (vehicle.status() == Vehicle.Status.ABGEMELDET
+ || (vehicle.status() != Vehicle.Status.FREI_FUNK
+ && vehicle.status() != Vehicle.Status.FREI_WACHE))
+ throw new InvalidOperationException(
+ "Abgemeldete Fahrzeuge dürfen nicht zu einem Einsatz geschickt werden!");
+ /*if (vehicle.type() == VehicleType.NEF && !rtw) {
+ for (Vehicle vehicleA : vehicles) {
+ if (vehicleA.type() == VehicleType.RTW && vehicleA.hasNef()) {
+ rtw = true;
+ break;
+ }
+ }
+ if (!rtw)
+ throw new InvalidOperationException(
+ "Zu einem Fahrzeug des Typs NEF muss auch ein Fahrzeug des Typs RTW mit NEF-Halterung geschickt werden!");
+ }*/
+ /* if (vehicle.type() == VehicleType.NAH && !rtw) {
+ for (Vehicle vehicleA : vehicles) {
+ if (vehicleA.type() == VehicleType.RTW) {
+ rtw = true;
+ break;
+ }
+ }
+ if (!rtw)
+ throw new InvalidOperationException(
+ "Zu einem Fahrzeug des Typs NAH muss auch ein Fahrzeug des Typs RTW geschickt werden!");
+ }*/
+ }
+ String[] codeParts = operation.opCode().split("-");
+ String severity = "";
+ for (int i = 0; i < codeParts[1].length(); i++) {
+ if (((int) (codeParts[1].charAt(i)) >= 65 && (int) (codeParts[1].charAt(i)) <= 79)
+ || ((int) (codeParts[1].charAt(i)) >= 97
+ && (int) (codeParts[1].charAt(i)) <= 111)) {
+ severity = "" + codeParts[1].charAt(i);
+ break;
+ }
+ }
+ try {
+ operation = operation.toBuilder().severity(Severity.valueOf(severity)).build();
+ } catch (IllegalArgumentException e) {
+ throw new InvalidOperationException(
+ "Der Schweregrad des Einsatzes konnte nicht ausgelesen werden!");
+ }
+ operation = operation.toBuilder().status(Status.ACTIVE).build();
+
+ long operationId = -1;
+ try {
+ operationId = operationDAO.add(operation);
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+
+ for (Vehicle vehicle : vehicles) {
+ try {
+ operationDAO.connectVehicleToOperation(vehicle.id(), operationId);
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ return operationId;
+ }
+
+ private boolean faultyInput(String name) {
+ if (name == null) return true;
+ else if (name.isEmpty()) return true;
+ for (int i = 0; i < name.length(); i++) {
+ if (name.charAt(i) != ' ') return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void requestVehicles(long operationId, List<Long> vehicleIds)
+ throws InvalidOperationException, InvalidVehicleException, ServiceException {}
+
+ @Override
+ public void complete(long operationId, Status status)
+ throws InvalidOperationException, ServiceException {}
+
+ @Override
+ public SortedList<Vehicle> rankVehicles(long operationId)
+ throws InvalidOperationException, ServiceException {
+ return null;
+ }
+
+ @Override
+ public List<Operation> list(EnumSet<Status> statuses) throws ServiceException {
+ return null;
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationService.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationService.java
index 6723f32..c345a2b 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationService.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationService.java
@@ -4,6 +4,7 @@ import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registratio
import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException;
import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.util.List;
public interface RegistrationService {
@@ -11,13 +12,13 @@ public interface RegistrationService {
* Register employee to a vehicle.
*
* @param vehicleId the id of the target vehicle
- * @param registration that should be added to the vehicle
- * @return the id that was assigned
+ * @param registrations that should be added to the vehicle
+ * @return the list of ids that were assigned
* @throws InvalidVehicleException if the vehicleId is invalid or does not exist
* @throws InvalidRegistrationException if the registration is invalid
* @throws ServiceException if the registration could not be persisted
*/
- long add(long vehicleId, Registration registration)
+ List<Long> add(long vehicleId, List<Registration> registrations)
throws InvalidVehicleException, InvalidRegistrationException, ServiceException;
/**
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImpl.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImpl.java
new file mode 100644
index 0000000..a267b6f
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImpl.java
@@ -0,0 +1,62 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.RegistrationDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.RegistrationValidator;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.util.EnumSet;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RegistrationServiceImpl implements RegistrationService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RegistrationServiceImpl.class);
+
+ private final RegistrationDAO registrationDAO;
+ private final VehicleService vehicleService;
+
+ @Autowired
+ public RegistrationServiceImpl(RegistrationDAO registrationDAO, VehicleService vehicleService) {
+ this.registrationDAO = registrationDAO;
+ this.vehicleService = vehicleService;
+ }
+
+ @Override
+ public List<Long> add(long vehicleId, List<Registration> registrations)
+ throws InvalidVehicleException, InvalidRegistrationException, ServiceException {
+
+ Vehicle vehicle =
+ vehicleService
+ .list(EnumSet.of(Status.ABGEMELDET))
+ .stream()
+ .filter(v -> v.id() == vehicleId)
+ .findFirst()
+ .orElse(null);
+
+ if (vehicle == null) {
+ throw new ServiceException("no vehicle with this id");
+ }
+
+ RegistrationValidator.validate(vehicle, registrations);
+ try {
+ return registrationDAO.add(vehicle.id(), registrations);
+ } catch (PersistenceException e) {
+ LOG.warn("PersistenceException caught, throwing matching ServiceException");
+ throw new ServiceException(e);
+ }
+ }
+
+ @Override
+ public void remove(long registrationId) throws InvalidRegistrationException, ServiceException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/VehicleServiceImpl.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/VehicleServiceImpl.java
new file mode 100644
index 0000000..bbe668b
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/VehicleServiceImpl.java
@@ -0,0 +1,99 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.VehicleDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.springframework.stereotype.Service;
+
+@Service
+public class VehicleServiceImpl implements VehicleService {
+
+ private VehicleDAO vehiclePersistence;
+
+ public VehicleServiceImpl(VehicleDAO vehiclePersistence) {
+ this.vehiclePersistence = vehiclePersistence;
+ }
+
+ public long add(Vehicle vehicle) throws InvalidVehicleException, ServiceException {
+
+ switch (vehicle.type()) {
+ case RTW:
+ if (vehicle.constructionType() == ConstructionType.NORMAL) {
+ throw new InvalidVehicleException("RTW darf kein Normales Dach haben");
+ } else if (vehicle.constructionType() == ConstructionType.MITTELHOCHDACH) {
+ throw new InvalidVehicleException("RTW darf kein Mittelhochdach haben");
+ }
+ break;
+ case KTW:
+ if (vehicle.constructionType() == ConstructionType.NORMAL) {
+ throw new InvalidVehicleException("KTW darf kein Normales Dach haben");
+ }
+ break;
+ case KTW_B:
+ if (vehicle.constructionType() == ConstructionType.NORMAL) {
+ throw new InvalidVehicleException("KTW-B darf kein Normales Dach haben");
+ }
+ break;
+ case NEF:
+ if (vehicle.constructionType() == ConstructionType.MITTELHOCHDACH) {
+ throw new InvalidVehicleException("NEF darf kein Mittelhochdach haben");
+ } else if (vehicle.constructionType() == ConstructionType.HOCHDACH) {
+ throw new InvalidVehicleException("NEF darf kein Hochdach haben");
+ }
+ break;
+ case NAH:
+ if (vehicle.constructionType() == ConstructionType.MITTELHOCHDACH) {
+ throw new InvalidVehicleException("NEF darf kein Mittelhochdach haben");
+ } else if (vehicle.constructionType() == ConstructionType.HOCHDACH) {
+ throw new InvalidVehicleException("NEF darf kein Hochdach haben");
+ }
+ break;
+ case BKTW:
+ break;
+ default:
+ throw new ServiceException("not a Valid type");
+ }
+ try {
+ vehiclePersistence.add(vehicle);
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+ return 0;
+ }
+
+ public Vehicle update(Vehicle vehicle) throws InvalidVehicleException, ServiceException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Vehicle> list(EnumSet<Status> statuses) throws ServiceException {
+
+ if (statuses == null) {
+ throw new ServiceException("statuses may not be null");
+ }
+
+ List<Vehicle> vehicles;
+
+ try {
+ vehicles = vehiclePersistence.list();
+ } catch (PersistenceException e) {
+ throw new ServiceException(e);
+ }
+
+ return vehicles.stream()
+ .filter(vehicle -> statuses.contains(vehicle.status()))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void remove(long id) throws InvalidVehicleException, ServiceException {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/ui/vehiclepane/VehiclePaneController.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/ui/vehiclepane/VehiclePaneController.java
new file mode 100644
index 0000000..2db6f37
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/ui/vehiclepane/VehiclePaneController.java
@@ -0,0 +1,84 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.ui.vehiclepane;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Node;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.text.Text;
+
+public class VehiclePaneController {
+ @FXML private Text txtType;
+ @FXML private Text txtNumber;
+ @FXML private ImageView ivNEF;
+ @FXML private Text txtNEF;
+ @FXML private ImageView ivQualification;
+ @FXML private Text txtQualification;
+ @FXML private Text txtRooftype;
+
+ public static VehiclePaneController createVehiclePane() throws IOException {
+ FXMLLoader fxmlLoader =
+ new FXMLLoader(VehiclePaneController.class.getResource("/fxml/vehiclePane.fxml"));
+ Node root = fxmlLoader.load();
+ VehiclePaneController result = fxmlLoader.getController();
+ result.rootElement = root;
+
+ return result;
+ }
+
+ private Node rootElement;
+
+ public Node getRootElement() {
+ return rootElement;
+ }
+
+ /**
+ * * Set the displayed data of this VehiclePane.
+ *
+ * @param vehicle The data to display.
+ * @param showQualification If true, the most recent registration of vehicle will be searched
+ * for the highest qualification.
+ */
+ public void setData(Vehicle vehicle, boolean showQualification) {
+ txtType.setText(vehicle.type().name());
+ String constrType = vehicle.constructionType().name();
+ txtRooftype.setText(
+ constrType.substring(0, 1).toUpperCase() + constrType.substring(1).toLowerCase());
+ txtNumber.setText("" + vehicle.id());
+ if (vehicle.hasNef()) {
+ ivNEF.setImage(new Image("../images/NEF.png"));
+ txtNEF.setText("hat NEF-Halterung");
+ } else {
+ ivNEF.setImage(new Image("../images/NotNEF.png"));
+ txtNEF.setText("keine NEF-Halterung");
+ }
+ if (showQualification) {
+
+ Instant now = (new Date()).toInstant();
+ List<Registration> regs = vehicle.registrations();
+
+ assert regs != null;
+ Optional<EducationLevel> edu =
+ regs.stream()
+ .filter(reg -> reg.start().isBefore(now) && reg.end().isAfter(now))
+ .map(reg -> reg.employee().educationLevel())
+ .max(EducationLevel::compareTo);
+
+ assert edu.isPresent();
+ txtQualification.setText(edu.get().name());
+ } else {
+ txtQualification.setVisible(false);
+ txtQualification.setManaged(false);
+ ivQualification.setVisible(false);
+ ivQualification.setManaged(false);
+ }
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/userInterface/CreateOperationController.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/userInterface/CreateOperationController.java
new file mode 100644
index 0000000..5b645f3
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/userInterface/CreateOperationController.java
@@ -0,0 +1,227 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.userInterface;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.DBOperationDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Severity;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationServiceImpl;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidOperationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.time.Instant;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+import javafx.collections.FXCollections;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Controller;
+
+@Controller
+public class CreateOperationController {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public AnchorPane apCreateOperation;
+ public TextField txtCode;
+ public TextField txtAddress;
+ public TextField txtNote;
+ public Button btnCreateOperation;
+ public ListView<Vehicle> lvVehicles;
+ public ListView lvActiveOperations;
+ public Label lblChosenVehicles;
+ public LinkedList<Vehicle> chosenVehicles = new LinkedList<>();
+
+ // TODO: Anders?
+ OperationService operationService =
+ new OperationServiceImpl(new DBOperationDAO(new JDBCConnectionManager()));
+ private final VehicleService vehicleService;
+ private final SpringFXMLLoader fxmlLoader;
+
+ public CreateOperationController(VehicleService vehicleService, SpringFXMLLoader fxmlLoader) {
+ this.vehicleService = vehicleService;
+ this.fxmlLoader = fxmlLoader;
+ }
+
+ @FXML
+ public void initialize() {
+ lblChosenVehicles.setText("keine ausgewählt");
+ lvVehicles.setCellFactory(
+ param ->
+ new ListCell<Vehicle>() {
+ @Override
+ protected void updateItem(Vehicle item, boolean empty) {
+ super.updateItem(item, empty);
+
+ if (empty || item == null || item.name() == null) {
+ setText(null);
+ } else {
+ setText(item.name());
+ }
+ }
+ });
+
+ lvVehicles.setOnMouseClicked(
+ event -> {
+ if (event.getClickCount() == 2) {
+ boolean remove = false;
+ if (lvVehicles.getSelectionModel().getSelectedItem() == null) {
+ return;
+ }
+ for (Vehicle vehicle : chosenVehicles) {
+ if (lvVehicles.getSelectionModel().getSelectedItem().equals(vehicle)) {
+ remove = true;
+ break;
+ }
+ }
+ if (!remove) {
+ chosenVehicles.add(lvVehicles.getSelectionModel().getSelectedItem());
+
+ } else {
+ chosenVehicles.remove(lvVehicles.getSelectionModel().getSelectedItem());
+ }
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < chosenVehicles.size(); i++) {
+ if (i == chosenVehicles.size() - 1) {
+ result.append(chosenVehicles.get(i).name());
+ } else {
+ result.append(chosenVehicles.get(i).name()).append(", ");
+ }
+ }
+ if (result.toString().equals("")) {
+ lblChosenVehicles.setText("keine ausgewählt");
+ } else {
+ lblChosenVehicles.setText(result.toString());
+ }
+ }
+ });
+ }
+
+ public void updateList() {
+ try {
+ this.lvVehicles.setItems(
+ FXCollections.observableArrayList(
+ vehicleService.list(
+ EnumSet.of(
+ Vehicle.Status.FREI_FUNK, Vehicle.Status.FREI_WACHE))));
+ } catch (ServiceException e) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Fehler");
+ alert.setHeaderText("Fehler!");
+ alert.setContentText(e.getMessage());
+ alert.showAndWait();
+ }
+ }
+
+ /*private LinkedList<Vehicle> mylist() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .name("Test-KTW")
+ .constructionType(ConstructionType.HOCHDACH)
+ .type(VehicleType.KTW)
+ .status(Vehicle.Status.FREI_WACHE)
+ .hasNef(true)
+ .build();
+
+ Vehicle vehicle1 =
+ Vehicle.builder()
+ .name("Test-NEF")
+ .constructionType(ConstructionType.NORMAL)
+ .type(VehicleType.NEF)
+ .status(Vehicle.Status.FREI_FUNK)
+ .hasNef(true)
+ .build();
+ LinkedList<Vehicle> list = new LinkedList<>();
+ list.add(vehicle);
+ list.add(vehicle1);
+ // this.lvVehicles.setItems(FXCollections.observableArrayList(list));
+ return list;
+ }*/
+
+ @FXML
+ protected void createOperationClicked() {
+ Vehicle[] vehicles = new Vehicle[chosenVehicles.size()];
+ for (int i = 0; i < chosenVehicles.size(); i++) {
+ vehicles[i] = chosenVehicles.get(i);
+ }
+ Operation operation =
+ Operation.builder()
+ .additionalInfo(txtNote.getText())
+ .destination(txtAddress.getText())
+ .created(Instant.now())
+ .opCode(txtCode.getText())
+ .status(Status.ACTIVE)
+ .vehicles(List.of(vehicles))
+ .severity(Severity.A)
+ .build();
+ try {
+ operationService.add(operation);
+ } catch (ServiceException | InvalidOperationException e) {
+ Alert alert = new Alert(Alert.AlertType.ERROR);
+ alert.setTitle("Fehler");
+ alert.setHeaderText("Fehler!");
+ alert.setContentText(e.getMessage());
+ alert.showAndWait();
+ return;
+ }
+ Alert alert = new Alert(AlertType.CONFIRMATION);
+ alert.setTitle("Erfolg");
+ alert.setHeaderText("Erfolgreich gespeichert");
+ alert.setContentText("Der Einsatz wurde erfolgreich gespeichert.");
+ alert.showAndWait();
+ updateList();
+ }
+
+ public void onRegistrationLinkClicked(ActionEvent actionEvent) {
+ openNewWindow("RegistrationWindow.fxml");
+ }
+
+ public void onEmployeeLinkClicked(ActionEvent actionEvent) {
+ openNewWindow("createNewEmployee.fxml");
+ }
+
+ public void onVehicleLinkClicked(ActionEvent actionEvent) {
+ openNewWindow("createCar.fxml");
+ }
+
+ private void openNewWindow(String fxmlFileName) {
+
+ Stage stage = new Stage();
+ try {
+ stage.setScene(
+ new Scene(
+ (Parent)
+ fxmlLoader.load(
+ getClass()
+ .getResourceAsStream(
+ "/fxml/" + fxmlFileName))));
+ } catch (IOException e) {
+ LOG.error("Could not open new window: {}", e);
+ }
+
+ stage.setTitle("Einsatz erstellen");
+ stage.centerOnScreen();
+ stage.showAndWait(); // important to call wait so that updateList is executed afterwards
+
+ updateList();
+ }
+}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java
index 5494471..0ee3319 100644
--- a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java
@@ -12,12 +12,17 @@ import org.springframework.stereotype.Component;
public class JDBCConnectionManager {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final String CONNECTION_URL =
- "jdbc:h2:~/sepm;INIT=RUNSCRIPT FROM 'classpath:sql/database.sql'";
-
+ private static final String DEFAULT_CONNECTION_URL =
+ "jdbc:h2:./sepm;INIT=RUNSCRIPT FROM 'classpath:sql/database.sql'";
+ private String connectionUrl;
private Connection connection;
public JDBCConnectionManager() {
+ this(DEFAULT_CONNECTION_URL);
+ }
+
+ public JDBCConnectionManager(String connectionUrl) {
+ this.connectionUrl = connectionUrl;
try {
Class.forName("org.h2.Driver");
} catch (ClassNotFoundException e) {
@@ -27,7 +32,7 @@ public class JDBCConnectionManager {
}
public Connection getConnection() throws SQLException {
- if (connection == null) connection = DriverManager.getConnection(CONNECTION_URL);
+ if (connection == null) connection = DriverManager.getConnection(connectionUrl);
return connection;
}
diff --git a/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/SpringFXMLLoader.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/SpringFXMLLoader.java
new file mode 100644
index 0000000..cb1f510
--- /dev/null
+++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/SpringFXMLLoader.java
@@ -0,0 +1,212 @@
+package at.ac.tuwien.sepm.assignment.groupphase.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import javafx.fxml.FXMLLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * A Spring Based FXMLLoader.
+ *
+ * <p>Provides the possibility to load FXML-Files and wrap them for convenient access to the loaded
+ * class as well as the spring loaded controller.
+ */
+@Component
+public class SpringFXMLLoader {
+
+ private Logger LOG = LoggerFactory.getLogger(SpringFXMLLoader.class);
+
+ private ApplicationContext applicationContext;
+
+ @Autowired
+ public SpringFXMLLoader(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ private FXMLLoader getFXMLLoader() {
+ final var fxmlLoader = new FXMLLoader();
+ fxmlLoader.setControllerFactory(applicationContext::getBean);
+ return fxmlLoader;
+ }
+
+ /**
+ * Load and return an object from an FXML-File.
+ *
+ * @param inputStream the input stream of the FXML-File
+ * @param loadType the class of the object to load
+ * @param <TLoad> the loaded object
+ * @return the loaded object
+ * @throws IOException if the resource could not be loaded
+ */
+ public synchronized <TLoad> TLoad load(InputStream inputStream, Class<TLoad> loadType)
+ throws IOException {
+ LOG.trace(
+ "Loading object of type {} from fxml resource {}",
+ loadType.getCanonicalName(),
+ inputStream);
+ return this.getFXMLLoader().load(inputStream);
+ }
+
+ /**
+ * Load and return an object from an FXML-File.
+ *
+ * @param pathToFXMLFile path to the FXML-File
+ * @param loadType the class of the object to load
+ * @param <TLoad> the loaded object
+ * @return the loaded object
+ * @throws IOException if the resource could not be loaded
+ */
+ public <TLoad> TLoad load(String pathToFXMLFile, Class<TLoad> loadType) throws IOException {
+ return this.load(SpringFXMLLoader.class.getResourceAsStream(pathToFXMLFile), loadType);
+ }
+
+ /**
+ * Load and return an object from an FXML-File.
+ *
+ * @param inputStream the input stream of the FXML-File
+ * @return the loaded object
+ * @throws IOException if the resource could not be loaded
+ */
+ public Object load(InputStream inputStream) throws IOException {
+ return this.load(inputStream, Object.class);
+ }
+
+ /**
+ * Load and return an object from an FXML-File.
+ *
+ * @param pathToFXMLFile path to the FXML-File
+ * @return the loaded object
+ * @throws IOException if the resource could not be loaded
+ */
+ public Object load(String pathToFXMLFile) throws IOException {
+ return this.load(SpringFXMLLoader.class.getResourceAsStream(pathToFXMLFile));
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param inputStream the input stream of the FXML-File
+ * @param loadType the class of the object to load
+ * @param controllerType the class of the declared controller of the loaded object
+ * @param <TLoad> the loaded object
+ * @param <TController> the controller of the loaded object
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public synchronized <TLoad, TController> FXMLWrapper<TLoad, TController> loadAndWrap(
+ InputStream inputStream, Class<TLoad> loadType, Class<TController> controllerType)
+ throws IOException {
+ final var fxmlLoader = this.getFXMLLoader();
+ LOG.trace(
+ "Loading and wrapping object of type {} with controller of type {} from fxml resource {}",
+ loadType.getCanonicalName(),
+ controllerType.getCanonicalName(),
+ inputStream);
+ return new FXMLWrapper<>(fxmlLoader.load(inputStream), fxmlLoader.getController());
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param pathToFXMLFile path to the FXML-File
+ * @param loadType the class of the object to load
+ * @param controllerType the class of the declared controller of the loaded object
+ * @param <TLoad> the loaded object
+ * @param <TController> the controller of the loaded object
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public synchronized <TLoad, TController> FXMLWrapper<TLoad, TController> loadAndWrap(
+ String pathToFXMLFile, Class<TLoad> loadType, Class<TController> controllerType)
+ throws IOException {
+ return this.loadAndWrap(
+ SpringFXMLLoader.class.getResourceAsStream(pathToFXMLFile),
+ loadType,
+ controllerType);
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param inputStream the input stream of the FXML-File
+ * @param controllerType the class of the declared controller of the loaded object
+ * @param <TController> the controller of the loaded object
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public <TController> FXMLWrapper<Object, TController> loadAndWrap(
+ InputStream inputStream, Class<TController> controllerType) throws IOException {
+ return this.loadAndWrap(inputStream, Object.class, controllerType);
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param pathToFXMLFile path to the FXML-File
+ * @param controllerType the class of the declared controller of the loaded object
+ * @param <TController> the controller of the loaded object
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public <TController> FXMLWrapper<Object, TController> loadAndWrap(
+ String pathToFXMLFile, Class<TController> controllerType) throws IOException {
+ return this.loadAndWrap(pathToFXMLFile, Object.class, controllerType);
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param inputStream the input stream of the FXML-File
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public FXMLWrapper<Object, Object> loadAndWrap(InputStream inputStream) throws IOException {
+ return this.loadAndWrap(inputStream, Object.class, Object.class);
+ }
+
+ /**
+ * Load and wrap an object and the declared controller from an FXML-File.
+ *
+ * @param pathToFXMLFile path to the FXML-File
+ * @return a wrapper object containing the loaded object and its declared controller
+ * @throws IOException if the resource could not be loaded
+ * @see FXMLWrapper
+ */
+ public FXMLWrapper<Object, Object> loadAndWrap(String pathToFXMLFile) throws IOException {
+ return this.loadAndWrap(pathToFXMLFile, Object.class, Object.class);
+ }
+
+ /**
+ * A wrapper for loading FXML-files and wrapping the loaded object as well as the controller.
+ *
+ * @param <TLoad> the loaded object
+ * @param <TController> the controller of the loaded object
+ */
+ public class FXMLWrapper<TLoad, TController> {
+
+ public TLoad getLoadedObject() {
+ return loadedObject;
+ }
+
+ public TController getController() {
+ return controller;
+ }
+
+ private final TLoad loadedObject;
+ private final TController controller;
+
+ private FXMLWrapper(TLoad loadedObject, TController controller) {
+ this.loadedObject = loadedObject;
+ this.controller = controller;
+ }
+ }
+}
diff --git a/src/main/resources/fxml/CreateOperationController.fxml b/src/main/resources/fxml/CreateOperationController.fxml
new file mode 100644
index 0000000..086a5d1
--- /dev/null
+++ b/src/main/resources/fxml/CreateOperationController.fxml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.Hyperlink?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.ListView?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.text.Font?>
+
+<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="650.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.userInterface.CreateOperationController">
+ <children>
+ <AnchorPane layoutX="964.0" layoutY="-66.0" prefHeight="182.0" prefWidth="1200.0" style="-fx-background-color: #2D75B6;" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0" />
+ <AnchorPane fx:id="apCreateOperation" layoutX="40.0" layoutY="71.0" prefHeight="151.0" prefWidth="920.0" style="-fx-background-color: white; -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 5, 0, 0, 5);">
+ <children>
+ <Label layoutX="14.0" layoutY="14.0" prefHeight="30.0" prefWidth="62.0" text="Code">
+ <font>
+ <Font size="19.0" />
+ </font>
+ </Label>
+ <Label layoutX="185.0" layoutY="14.0" prefHeight="30.0" prefWidth="94.0" text="Adresse">
+ <font>
+ <Font size="19.0" />
+ </font>
+ </Label>
+ <Label layoutX="587.0" layoutY="14.0" prefHeight="30.0" prefWidth="121.0" text="Anmerkung">
+ <font>
+ <Font size="19.0" />
+ </font>
+ </Label>
+ <TextField fx:id="txtCode" layoutX="14.0" layoutY="48.0" prefHeight="39.0" prefWidth="163.0">
+ <font>
+ <Font name="System Bold" size="20.0" />
+ </font>
+ </TextField>
+ <TextField fx:id="txtAddress" layoutX="185.0" layoutY="48.0" prefHeight="39.0" prefWidth="396.0">
+ <font>
+ <Font name="System Bold" size="20.0" />
+ </font>
+ </TextField>
+ <TextField fx:id="txtNote" layoutX="587.0" layoutY="48.0" prefHeight="39.0" prefWidth="319.0">
+ <font>
+ <Font name="System Bold" size="20.0" />
+ </font>
+ </TextField>
+ <Label layoutX="14.0" layoutY="101.0" prefHeight="30.0" prefWidth="102.0" text="Fahrzeuge:">
+ <font>
+ <Font size="19.0" />
+ </font>
+ </Label>
+ <Label fx:id="lblChosenVehicles" layoutX="116.0" layoutY="102.0" prefHeight="30.0" prefWidth="610.0" text="keine ausgewählt">
+ <font>
+ <Font size="19.0" />
+ </font>
+ </Label>
+ <Button fx:id="btnCreateOperation" layoutX="747.0" layoutY="95.0" mnemonicParsing="false" onAction="#createOperationClicked" prefHeight="0.0" prefWidth="158.0" text="Erstellen">
+ <font>
+ <Font name="System Bold" size="21.0" />
+ </font>
+ </Button>
+ </children>
+ </AnchorPane>
+ <Hyperlink layoutX="44.0" layoutY="38.0" onAction="#onRegistrationLinkClicked" text="Anmeldungen" textFill="WHITE">
+ <font>
+ <Font size="15.0" />
+ </font>
+ </Hyperlink>
+ <Hyperlink layoutX="802.0" layoutY="38.0" onAction="#onEmployeeLinkClicked" text="Personen" textFill="WHITE">
+ <font>
+ <Font size="15.0" />
+ </font>
+ </Hyperlink>
+ <Hyperlink layoutX="877.0" layoutY="38.0" onAction="#onVehicleLinkClicked" text="Fahrzeuge" textFill="WHITE">
+ <font>
+ <Font size="15.0" />
+ </font>
+ </Hyperlink>
+ <AnchorPane fx:id="apActiveOperations" layoutX="968.0" layoutY="71.0" prefHeight="315.0" prefWidth="207.0" style="-fx-background-color: white; -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 5);">
+ <children>
+ <ListView fx:id="lvActiveOperations" layoutX="4.0" layoutY="74.0" prefHeight="242.0" prefWidth="200.0" style="-fx-background-color: white;" />
+ <Label layoutX="10.0" layoutY="14.0" prefHeight="46.0" prefWidth="103.0" text="Aktive Einsätze">
+ <font>
+ <Font name="System Bold" size="14.0" />
+ </font>
+ </Label>
+ <Label layoutX="148.0" layoutY="28.0" text="Archiv">
+ <font>
+ <Font size="13.0" />
+ </font>
+ </Label>
+ </children>
+ </AnchorPane>
+ <ListView fx:id="lvVehicles" layoutX="40.0" layoutY="228.0" prefHeight="388.0" prefWidth="920.0" style="-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 5);" />
+ </children>
+</AnchorPane>
diff --git a/src/main/resources/fxml/RegistrationWindow.fxml b/src/main/resources/fxml/RegistrationWindow.fxml
new file mode 100644
index 0000000..0394ca7
--- /dev/null
+++ b/src/main/resources/fxml/RegistrationWindow.fxml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ChoiceBox?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.SplitPane?>
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.VBox?>
+
+<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller.RegistrationWindowController">
+ <children>
+ <AnchorPane prefHeight="135.0" prefWidth="600.0">
+ <children>
+ <Label layoutX="14.0" layoutY="14.0" text="Neue Anmeldung" />
+ <Label layoutX="14.0" layoutY="44.0" text="von" />
+ <Label layoutX="133.0" layoutY="44.0" text="bis" />
+ <ChoiceBox fx:id="cbStart" layoutX="42.0" layoutY="40.0" prefWidth="80.0" />
+ <ChoiceBox fx:id="cbEnd" layoutX="159.0" layoutY="40.0" prefWidth="80.0" />
+ <Label layoutX="10.0" layoutY="82.0" text="Fahrzeug" />
+ <Label fx:id="lVehicles" layoutX="10.0" layoutY="108.0" text="Fahrzeugname" />
+ <Label layoutX="216.0" layoutY="82.0" text="Personen" />
+ <Label fx:id="lEmployees" layoutX="216.0" layoutY="108.0" text="Namen" />
+ </children>
+ </AnchorPane>
+ <SplitPane dividerPositions="0.35" prefWidth="200.0">
+ <items>
+ <VBox prefHeight="200.0" prefWidth="100.0">
+ <children>
+ <Label text="Fahrzeugsuche" />
+ <TextField fx:id="tfVehicleSearch" />
+ <TableView fx:id="tvVehicles" prefHeight="200.0" prefWidth="200.0">
+ <columns>
+ <TableColumn fx:id="tcVehicles" prefWidth="75.0" text="Fahrzeuge" />
+ </columns>
+ <columnResizePolicy>
+ <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
+ </columnResizePolicy>
+ </TableView>
+ </children>
+ </VBox>
+ <VBox prefHeight="200.0" prefWidth="100.0">
+ <children>
+ <Label text="Personensuche" />
+ <TextField fx:id="tfEmployeeSearch" />
+ <TableView fx:id="tvEmployees" prefHeight="200.0" prefWidth="200.0">
+ <columns>
+ <TableColumn fx:id="tcEmployees" prefWidth="75.0" text="Personen" />
+ </columns>
+ <columnResizePolicy>
+ <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
+ </columnResizePolicy>
+ </TableView>
+ </children>
+ </VBox>
+ </items>
+ </SplitPane>
+ <HBox alignment="CENTER" prefWidth="200.0">
+ <children>
+ <Button mnemonicParsing="false" onAction="#cancel" text="Abbrechen">
+ <HBox.margin>
+ <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
+ </HBox.margin>
+ </Button>
+ <Button mnemonicParsing="false" onAction="#create" text="Erstellen">
+ <HBox.margin>
+ <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
+ </HBox.margin>
+ </Button>
+ </children></HBox>
+ </children>
+</VBox>
diff --git a/src/main/resources/fxml/createCar.fxml b/src/main/resources/fxml/createCar.fxml
new file mode 100644
index 0000000..b0898da
--- /dev/null
+++ b/src/main/resources/fxml/createCar.fxml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.CheckBox?>
+<?import javafx.scene.control.ChoiceBox?>
+<?import javafx.scene.layout.AnchorPane?>
+
+
+<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller.CreateCarController">
+ <children>
+ <ChoiceBox fx:id="cmb_Ctyp" layoutX="14.0" layoutY="14.0" prefWidth="150.0" />
+ <ChoiceBox fx:id="cmb_typ" layoutX="191.0" layoutY="14.0" prefWidth="150.0" />
+ <Button fx:id="btn_cancel" layoutX="500.0" layoutY="14.0" mnemonicParsing="false" text="abbrechen" />
+ <Button fx:id="btn_create" layoutX="500.0" layoutY="53.0" mnemonicParsing="false" onAction="#createCar" text="Erstellen" />
+ <CheckBox fx:id="cbx_NEF" layoutX="14.0" layoutY="57.0" mnemonicParsing="false" text="NEF - Halterung" />
+ </children>
+</AnchorPane>
diff --git a/src/main/resources/fxml/createNewEmployee.fxml b/src/main/resources/fxml/createNewEmployee.fxml
new file mode 100644
index 0000000..5fa1ca9
--- /dev/null
+++ b/src/main/resources/fxml/createNewEmployee.fxml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.CheckBox?>
+<?import javafx.scene.control.ChoiceBox?>
+<?import javafx.scene.control.Hyperlink?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.layout.AnchorPane?>
+
+
+<AnchorPane prefHeight="114.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller.CreateNewEmployeeController">
+ <children>
+ <Label layoutX="14.0" layoutY="14.0" text="Neue Person erstellen" />
+ <Label layoutX="14.0" layoutY="38.0" text="Name" />
+ <Label layoutX="206.0" layoutY="38.0" text="Qualifikation" />
+ <CheckBox fx:id="inputIsDriver" layoutX="343.0" layoutY="37.0" mnemonicParsing="false" text="Fahrer" />
+ <CheckBox fx:id="inputIsPilot" layoutX="343.0" layoutY="62.0" mnemonicParsing="false" text="Pilot" />
+ <Hyperlink fx:id="btnCancel" layoutX="441.0" layoutY="31.0" onAction="#onCancelClicked" text="abbrechen" />
+ <Button fx:id="btnCreate" layoutX="441.0" layoutY="55.0" mnemonicParsing="false" onAction="#onCreateClicked" text="Erstellen" />
+ <TextField fx:id="inputName" layoutX="14.0" layoutY="57.0" prefHeight="25.0" prefWidth="179.0" />
+ <ChoiceBox fx:id="inputQualification" layoutX="199.0" layoutY="57.0" prefHeight="25.0" prefWidth="128.0" />
+ </children>
+</AnchorPane>
diff --git a/src/main/resources/fxml/vehiclePane.fxml b/src/main/resources/fxml/vehiclePane.fxml
new file mode 100644
index 0000000..8b1d194
--- /dev/null
+++ b/src/main/resources/fxml/vehiclePane.fxml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.image.Image?>
+<?import javafx.scene.image.ImageView?>
+<?import javafx.scene.layout.ColumnConstraints?>
+<?import javafx.scene.layout.GridPane?>
+<?import javafx.scene.layout.RowConstraints?>
+<?import javafx.scene.text.Font?>
+<?import javafx.scene.text.Text?>
+<?import javafx.scene.text.TextFlow?>
+
+<GridPane hgap="6.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1"
+ fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.ui.vehiclepane.VehiclePaneController">
+ <columnConstraints>
+ <ColumnConstraints/>
+ <ColumnConstraints/>
+ <ColumnConstraints/>
+ <ColumnConstraints/>
+ </columnConstraints>
+ <rowConstraints>
+ <RowConstraints/>
+ <RowConstraints/>
+ <RowConstraints/>
+ <RowConstraints/>
+ </rowConstraints>
+ <padding>
+ <Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/>
+ </padding>
+ <TextFlow GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="0">
+ <Text text="RTW" fx:id="txtType">
+ <font>
+ <Font name="System Bold" size="18.0"/>
+ </font>
+ </Text>
+ <Text text="-10003" fx:id="txtNumber">
+ <font>
+ <Font size="16.0"/>
+ </font>
+ </Text>
+ </TextFlow>
+ <ImageView fx:id="ivNEF" fitHeight="25.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true"
+ GridPane.columnIndex="0" GridPane.rowIndex="1">
+ <Image url="@../images/NotNEF.png"/>
+ </ImageView>
+ <Text fx:id="txtNEF" text="keine NEF-Halterung" GridPane.columnIndex="1" GridPane.rowIndex="1">
+ <font>
+ <Font size="14.0"/>
+ </font>
+ </Text>
+ <ImageView fx:id="ivQualification" fitHeight="25.0" fitWidth="25.0" pickOnBounds="true"
+ preserveRatio="true"
+ GridPane.columnIndex="0" GridPane.rowIndex="2">
+ <Image url="@../images/Qualification.png"/>
+ </ImageView>
+ <Text fx:id="txtQualification" text="Notarzt" GridPane.columnIndex="1" GridPane.rowIndex="2">
+ <font>
+ <Font size="14.0"/>
+ </font>
+ </Text>
+ <ImageView fitHeight="25.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true"
+ GridPane.columnIndex="0" GridPane.rowIndex="3">
+ <Image url="@../images/Vehicle.png"/>
+ </ImageView>
+ <Text fx:id="txtRooftype" text="Hochdach" GridPane.columnIndex="1" GridPane.rowIndex="3">
+ <font>
+ <Font size="14.0"/>
+ </font>
+ </Text>
+</GridPane>
diff --git a/src/main/resources/images/NEF.png b/src/main/resources/images/NEF.png
new file mode 100644
index 0000000..687f914
--- /dev/null
+++ b/src/main/resources/images/NEF.png
Binary files differ
diff --git a/src/main/resources/images/Not.png b/src/main/resources/images/Not.png
new file mode 100644
index 0000000..03063af
--- /dev/null
+++ b/src/main/resources/images/Not.png
Binary files differ
diff --git a/src/main/resources/images/NotNEF.png b/src/main/resources/images/NotNEF.png
new file mode 100644
index 0000000..0c17d53
--- /dev/null
+++ b/src/main/resources/images/NotNEF.png
Binary files differ
diff --git a/src/main/resources/images/Qualification.png b/src/main/resources/images/Qualification.png
new file mode 100644
index 0000000..c58a640
--- /dev/null
+++ b/src/main/resources/images/Qualification.png
Binary files differ
diff --git a/src/main/resources/images/Vehicle.png b/src/main/resources/images/Vehicle.png
new file mode 100644
index 0000000..2fe992d
--- /dev/null
+++ b/src/main/resources/images/Vehicle.png
Binary files differ
diff --git a/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql b/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql
new file mode 100644
index 0000000..f43b641
--- /dev/null
+++ b/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql
@@ -0,0 +1,5 @@
+DELETE FROM Registration;
+DELETE FROM Vehicle;
+DELETE FROM VehicleVersion;
+DELETE FROM Employee;
+DELETE FROM EmployeeVersion; \ No newline at end of file
diff --git a/src/main/resources/sql/H2RegistrationDAOTest_populate.sql b/src/main/resources/sql/H2RegistrationDAOTest_populate.sql
new file mode 100644
index 0000000..7e7b428
--- /dev/null
+++ b/src/main/resources/sql/H2RegistrationDAOTest_populate.sql
@@ -0,0 +1,15 @@
+DELETE FROM Registration;
+DELETE FROM Vehicle;
+DELETE FROM VehicleVersion;
+DELETE FROM Employee;
+DELETE FROM EmployeeVersion;
+INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (1, 'John Doe', '2000-01-01', 'RS', TRUE, TRUE);
+INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (2, 'Nick "Kage" Verily', '1990-01-01', 'NKV', TRUE, FALSE);
+INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (3, 'Nicht Arzt', '1980-01-01', 'NA', FALSE, FALSE);
+INSERT INTO Employee (id, version) VALUES (1, 1);
+INSERT INTO Employee (id, version) VALUES (2, 2);
+INSERT INTO Employee (id, version) VALUES (3, 3);
+INSERT INTO VehicleVersion (id, name, hasNef, constructionType, type) VALUES (1, 'RTW-1', TRUE, 'HOCHDACH', 'RTW');
+INSERT INTO VehicleVersion (id, name, hasNef, constructionType, type) VALUES (2, 'NEF-1', FALSE, 'NORMAL', 'NEF');
+INSERT INTO Vehicle (id, version, status) VALUES (1, 1, 'ABGEMELDET');
+INSERT INTO Vehicle (id, version, status) VALUES (2, 2, 'ABGEMELDET'); \ No newline at end of file
diff --git a/src/main/resources/sql/database.sql b/src/main/resources/sql/database.sql
index 9d1b0e1..4f3adf7 100644
--- a/src/main/resources/sql/database.sql
+++ b/src/main/resources/sql/database.sql
@@ -1,25 +1,30 @@
CREATE TABLE IF NOT EXISTS VehicleVersion (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
- constructionType ENUM('Normal', 'Hochdach', 'Mittelhochdach') NOT NULL,
- type ENUM('BKTW', 'KTW-B', 'KTW', 'RTW', 'NEF', 'NAH') NOT NULL,
+ constructionType VARCHAR NOT NULL,
+ type VARCHAR NOT NULL,
+ hasNef BOOLEAN NOT NULL,
+ CHECK constructionType IN ('NORMAL', 'HOCHDACH', 'MITTELHOCHDACH'),
+ CHECK type IN ('BKTW', 'KTW-B', 'KTW', 'RTW', 'NEF', 'NAH')
);
CREATE TABLE IF NOT EXISTS Vehicle (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
version BIGINT NOT NULL,
- status ENUM('abgemeldet', 'frei_wache', 'zum_berufungsort', 'am_berufungsort', 'zum_zielort',
- 'am_zielort', 'frei_funk', 'deleted') NOT NULL,
+ status VARCHAR NOT NULL,
FOREIGN KEY (version) REFERENCES VehicleVersion(id),
+ CHECK status IN ('ABGEMELDET', 'FREI_WACHE', 'ZUM_BERUFUNGSORT', 'AM_BERUFUNGSORT', 'ZUM_ZIELORT',
+ 'AM_ZIELORT', 'FREI_FUNK', 'DELETED')
);
CREATE TABLE IF NOT EXISTS EmployeeVersion (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
birthday DATE NOT NULL,
- educationLevel ENUM('RS', 'NFS', 'NKV', 'NKA', 'NKI', 'NA') NOT NULL,
+ educationLevel VARCHAR NOT NULL,
isDriver BOOLEAN NOT NULL,
isPilot BOOLEAN NOT NULL,
+ CHECK educationLevel IN ('RS', 'NFS', 'NKV', 'NKA', 'NKI', 'NA')
);
CREATE TABLE IF NOT EXISTS Employee (
@@ -42,10 +47,13 @@ CREATE TABLE IF NOT EXISTS Registration (
CREATE TABLE IF NOT EXISTS Operation (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
opCode VARCHAR(20) NOT NULL,
- severity ENUM('A', 'B', 'C', 'D', 'E', 'O') NOT NULL,
+ severity VARCHAR NOT NULL,
created TIMESTAMP NOT NULL,
destination VARCHAR(100) NOT NULL,
additionalInfo VARCHAR(100),
+ status VARCHAR NOT NULL,
+ CHECK severity IN ('A', 'B', 'C', 'D', 'E', 'O'),
+ CHECK status IN ('ACTIVE', 'COMPLETED', 'CANCELLED')
);
CREATE TABLE IF NOT EXISTS VehicleOperation (
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java
new file mode 100644
index 0000000..3293ae9
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java
@@ -0,0 +1,53 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller;
+
+import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader;
+import java.lang.invoke.MethodHandles;
+import javafx.application.Application;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+@Component
+@ComponentScan("at.ac.tuwien.sepm.assignment.groupphase")
+public class RegistrationWindowApplication extends Application {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static AnnotationConfigApplicationContext context;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ // setup application
+ primaryStage.setTitle("Person anlegen");
+ // primaryStage.setWidth(1366);
+ // primaryStage.setHeight(768);
+ primaryStage.centerOnScreen();
+ primaryStage.setOnCloseRequest(event -> LOG.debug("Application shutdown initiated"));
+
+ context = new AnnotationConfigApplicationContext(RegistrationWindowApplication.class);
+ final var fxmlLoader = context.getBean(SpringFXMLLoader.class);
+ primaryStage.setScene(
+ new Scene(
+ (Parent)
+ fxmlLoader.load(
+ getClass()
+ .getResourceAsStream(
+ "/fxml/RegistrationWindow.fxml"))));
+
+ // show application
+ primaryStage.show();
+ primaryStage.toFront();
+ LOG.debug("Application startup complete");
+ }
+
+ @Override
+ public void stop() {
+ LOG.debug("Stopping application");
+ context.close();
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java
new file mode 100644
index 0000000..03059ff
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java
@@ -0,0 +1,168 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao;
+
+import static org.junit.Assert.*;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.nio.charset.Charset;
+import java.sql.SQLException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.LinkedList;
+import java.util.List;
+import org.h2.tools.RunScript;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class RegistrationDatabaseDAOTest {
+
+ // Base taken from EmployeePersistenceTest
+
+ private static final String JDBC_DRIVER = org.h2.Driver.class.getName();
+ private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
+ private static final String USER = "";
+ private static final String PASSWORD = "";
+
+ private RegistrationDAO registrationDAO;
+
+ public RegistrationDatabaseDAOTest() throws PersistenceException {
+ this.registrationDAO = new RegistrationDatabaseDAO(new JDBCConnectionManager(JDBC_URL));
+ }
+
+ @BeforeClass
+ public static void setupDatabase() throws SQLException {
+ RunScript.execute(
+ JDBC_URL,
+ USER,
+ PASSWORD,
+ "classpath:sql/database.sql",
+ Charset.forName("UTF8"),
+ false);
+ RunScript.execute(
+ JDBC_URL,
+ USER,
+ PASSWORD,
+ "classpath:sql/H2RegistrationDAOTest_populate.sql",
+ Charset.forName("UTF8"),
+ false);
+ }
+ /*
+ @Before
+ public void setUp() throws SQLException {
+ RunScript.execute(
+ JDBC_URL,
+ USER,
+ PASSWORD,
+ "classpath:sql/H2RegistrationDAOTest_populate.sql",
+ Charset.forName("UTF8"),
+ false);
+ }
+ */
+ @AfterClass
+ public static void tearDown() throws SQLException {
+ RunScript.execute(
+ JDBC_URL,
+ USER,
+ PASSWORD,
+ "classpath:sql/H2RegistrationDAOTest_depopulate.sql",
+ Charset.forName("UTF8"),
+ false);
+ }
+
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void addRegistrationsShouldSucceed() throws PersistenceException {
+ List<Registration> registrations = new LinkedList<>();
+ /*
+ Vehicle vehicle = Vehicle.builder()
+ .id(1)
+ .name("RTW-1")
+ .constructionType(ConstructionType.HOCHDACH)
+ .type(VehicleType.RTW)
+ .status(Status.ABGEMELDET)
+ .hasNef(true)
+ .build();
+ */
+ Employee employee1 =
+ Employee.builder()
+ .id(1)
+ .name("John Doe")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(true)
+ .build();
+ Employee employee2 =
+ Employee.builder()
+ .id(2)
+ .name("Nick \"Kage\" Verily")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.NKV)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+ Employee employee3 =
+ Employee.builder()
+ .id(3)
+ .name("Nicht Arzt")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.NA)
+ .isDriver(false)
+ .isPilot(false)
+ .build();
+ Registration registration1 =
+ Registration.builder()
+ .start(Instant.now()) // incorrect, but should be irrelevant to outcome
+ .end(Instant.now()) // same
+ .employee(employee1)
+ .build();
+ Registration registration2 =
+ Registration.builder()
+ .start(Instant.now()) // incorrect, but should be irrelevant to outcome
+ .end(Instant.now()) // same
+ .employee(employee2)
+ .build();
+ Registration registration3 =
+ Registration.builder()
+ .start(Instant.now()) // incorrect, but should be irrelevant to outcome
+ .end(Instant.now()) // same
+ .employee(employee3)
+ .build();
+ registrations.add(registration1);
+ registrations.add(registration2);
+ registrations.add(registration3);
+
+ List<Long> returnvalues = registrationDAO.add(1, registrations);
+ assertFalse(returnvalues.isEmpty()); // can be improved...
+ }
+
+ @Test
+ public void addRegistrationToInexistentVehicleShouldFail() throws PersistenceException {
+ thrown.expect(PersistenceException.class);
+ List<Registration> registrations = new LinkedList<>();
+ Employee employee =
+ Employee.builder()
+ .id(1)
+ .name("John Doe")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(true)
+ .build();
+ Registration registration =
+ Registration.builder()
+ .start(Instant.MIN)
+ .end(Instant.MAX)
+ .employee(employee)
+ .build();
+ registrations.add(registration);
+ registrationDAO.add(200, registrations);
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java
new file mode 100644
index 0000000..f3efbef
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java
@@ -0,0 +1,148 @@
+package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.RegistrationDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class RegistrationServiceImplTest {
+
+ @Mock RegistrationDAO daoMock;
+
+ @Mock VehicleService vehicleService;
+
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Rule public ExpectedException thrown = ExpectedException.none();
+
+ @Before
+ public void setUp() throws ServiceException {
+ MockitoAnnotations.initMocks(this);
+ when(vehicleService.list(any()))
+ .thenReturn(
+ Arrays.asList(
+ Vehicle.builder()
+ .id(1)
+ .name("RTW-1")
+ .constructionType(ConstructionType.HOCHDACH)
+ .status(Status.ABGEMELDET)
+ .type(VehicleType.RTW)
+ .hasNef(true)
+ .build()));
+ }
+
+ @Test
+ public void addValidRegistrationsShouldSucceed()
+ throws InvalidRegistrationException, ServiceException, InvalidVehicleException {
+ RegistrationService registrationService =
+ new RegistrationServiceImpl(daoMock, vehicleService);
+ List<Registration> registrations = new LinkedList<>();
+ Vehicle vehicle =
+ Vehicle.builder()
+ .id(1)
+ .name("RTW-1")
+ .constructionType(ConstructionType.HOCHDACH)
+ .type(VehicleType.RTW)
+ .status(Status.ABGEMELDET)
+ .hasNef(true)
+ .build();
+ Employee employee1 =
+ Employee.builder()
+ .id(1)
+ .name("John Doe")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(true)
+ .build();
+ Employee employee2 =
+ Employee.builder()
+ .id(2)
+ .name("Nick \"Kage\" Verily")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.NKV)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+ Employee employee3 =
+ Employee.builder()
+ .id(3)
+ .name("Nicht Arzt")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.NA)
+ .isDriver(false)
+ .isPilot(false)
+ .build();
+ Instant start = Instant.now();
+ Instant end = start.plus(8, ChronoUnit.HOURS);
+ Registration registration1 =
+ Registration.builder().start(start).end(end).employee(employee1).build();
+ Registration registration2 =
+ Registration.builder().start(start).end(end).employee(employee2).build();
+ Registration registration3 =
+ Registration.builder().start(start).end(end).employee(employee3).build();
+ registrations.add(registration1);
+ registrations.add(registration2);
+ registrations.add(registration3);
+ registrationService.add(vehicle.id(), registrations);
+ }
+
+ @Test
+ public void addOnlyOnePersonToRTWShouldFail()
+ throws InvalidRegistrationException, ServiceException, InvalidVehicleException {
+ thrown.expect(InvalidRegistrationException.class);
+ RegistrationService registrationService =
+ new RegistrationServiceImpl(daoMock, vehicleService);
+ List<Registration> registrations = new LinkedList<>();
+ Vehicle vehicle =
+ Vehicle.builder()
+ .id(1)
+ .name("RTW-1")
+ .constructionType(ConstructionType.HOCHDACH)
+ .type(VehicleType.RTW)
+ .status(Status.ABGEMELDET)
+ .hasNef(true)
+ .build();
+ Employee employee =
+ Employee.builder()
+ .id(1)
+ .name("John Doe")
+ .birthday(LocalDate.now()) // incorrect, but should be irrelevant
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(true)
+ .build();
+ Registration registration =
+ Registration.builder()
+ .start(Instant.MIN)
+ .end(Instant.MAX)
+ .employee(employee)
+ .build();
+ registrations.add(registration);
+ registrationService.add(vehicle.id(), registrations);
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeApplication.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeApplication.java
new file mode 100644
index 0000000..e9f4801
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeApplication.java
@@ -0,0 +1,53 @@
+package at.ac.tuwien.sepm.assignment.groupphase.employee;
+
+import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader;
+import java.lang.invoke.MethodHandles;
+import javafx.application.Application;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+@Component
+@ComponentScan("at.ac.tuwien.sepm.assignment.groupphase")
+public final class CreateNewEmployeeApplication extends Application {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static AnnotationConfigApplicationContext context;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ // setup application
+ primaryStage.setTitle("Person anlegen");
+ primaryStage.setWidth(1366);
+ primaryStage.setHeight(768);
+ primaryStage.centerOnScreen();
+ primaryStage.setOnCloseRequest(event -> LOG.debug("Application shutdown initiated"));
+
+ context = new AnnotationConfigApplicationContext(CreateNewEmployeeApplication.class);
+ final var fxmlLoader = context.getBean(SpringFXMLLoader.class);
+ primaryStage.setScene(
+ new Scene(
+ (Parent)
+ fxmlLoader.load(
+ getClass()
+ .getResourceAsStream(
+ "/fxml/createNewEmployee.fxml"))));
+
+ // show application
+ primaryStage.show();
+ primaryStage.toFront();
+ LOG.debug("Application startup complete");
+ }
+
+ @Override
+ public void stop() {
+ LOG.debug("Stopping application");
+ context.close();
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeControllerTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeControllerTest.java
new file mode 100644
index 0000000..eb1a728
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/CreateNewEmployeeControllerTest.java
@@ -0,0 +1,85 @@
+package at.ac.tuwien.sepm.assignment.groupphase.employee;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidEmployeeException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.Helper;
+import at.ac.tuwien.sepm.assignment.groupphase.util.HighDpiAwareApplicationTest;
+import javafx.scene.control.DialogPane;
+import javafx.scene.input.MouseButton;
+import javafx.stage.Stage;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.testfx.api.FxToolkit;
+import org.testfx.robot.Motion;
+
+public class CreateNewEmployeeControllerTest extends HighDpiAwareApplicationTest {
+
+ private EmployeeService employeeService;
+
+ @Before
+ public void setup() throws Exception {
+ // TODO: check if testfx can be run in headless mode on Jenkins
+ FxToolkit.registerPrimaryStage();
+ FxToolkit.setupApplication(CreateNewEmployeeApplication.class);
+ employeeService = CreateNewEmployeeApplication.context.getBean(EmployeeService.class);
+ }
+
+ @After
+ public void cleanup() throws Exception {
+ FxToolkit.cleanupStages();
+ }
+
+ @Test
+ public void testClickAddValidEmployee() throws InvalidEmployeeException, ServiceException {
+
+ when(employeeService.add(any())).thenReturn(1L);
+
+ clickOn("#inputName", Motion.DIRECT, MouseButton.PRIMARY);
+ write("Name");
+ clickOn("#btnCreate", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Erfolgreich angelegt", dialogPane.getHeaderText());
+ }
+
+ @Test
+ public void testClickAddInvalidEmployee() throws InvalidEmployeeException, ServiceException {
+
+ when(employeeService.add(any())).thenThrow(InvalidEmployeeException.class);
+
+ moveTo("#inputName");
+ clickOn("#btnCreate", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Ungültige Eingabe", dialogPane.getHeaderText());
+ }
+
+ @Test
+ public void testClickAddEmployeeWithServiceException()
+ throws InvalidEmployeeException, ServiceException {
+
+ when(employeeService.add(any())).thenThrow(ServiceException.class);
+
+ clickOn("#inputName", Motion.DIRECT, MouseButton.PRIMARY);
+ write("Test");
+ clickOn("#btnCreate", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Speicherfehler", dialogPane.getHeaderText());
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java
new file mode 100644
index 0000000..f8fe0f3
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java
@@ -0,0 +1,155 @@
+package at.ac.tuwien.sepm.assignment.groupphase.employee;
+
+import static junit.framework.TestCase.fail;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDatabaseDao;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
+import java.nio.charset.Charset;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import org.dbunit.IDatabaseTester;
+import org.dbunit.JdbcDatabaseTester;
+import org.dbunit.dataset.DataSetException;
+import org.dbunit.dataset.IDataSet;
+import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
+import org.dbunit.operation.DatabaseOperation;
+import org.h2.tools.RunScript;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class EmployeePersistenceTest {
+
+ private static final String JDBC_DRIVER = org.h2.Driver.class.getName();
+ private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1";
+ private static final String USER = "";
+ private static final String PASSWORD = "";
+
+ private EmployeeDAO employeePersistence;
+
+ public EmployeePersistenceTest() throws PersistenceException {
+ employeePersistence = new EmployeeDatabaseDao(new JDBCConnectionManager(JDBC_URL));
+ }
+
+ @BeforeClass
+ public static void createSchema() throws SQLException {
+ RunScript.execute(
+ JDBC_URL,
+ USER,
+ PASSWORD,
+ "classpath:sql/database.sql",
+ Charset.forName("UTF8"),
+ false);
+ }
+
+ @Before
+ public void importDataSet() throws Exception {
+ IDataSet dataSet = readDataSet();
+ cleanlyInsert(dataSet);
+ }
+
+ private IDataSet readDataSet() throws DataSetException {
+ return new FlatXmlDataSetBuilder()
+ .build(
+ getClass()
+ .getClassLoader()
+ .getResourceAsStream("employeeServiceTestData.xml"));
+ }
+
+ private void cleanlyInsert(IDataSet dataSet) throws Exception {
+ IDatabaseTester databaseTester =
+ new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PASSWORD);
+
+ databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT);
+ databaseTester.setDataSet(dataSet);
+ databaseTester.onSetup();
+ }
+
+ @Test
+ public void testListEmployees() {
+
+ try {
+ List<Employee> employees = employeePersistence.list();
+
+ Employee empOne =
+ Employee.builder()
+ .id(1)
+ .name("Adam")
+ .birthday(
+ LocalDate.parse(
+ "10.10.2010",
+ DateTimeFormatter.ofPattern("dd.MM.yyyy")))
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+
+ Employee empTwo =
+ Employee.builder()
+ .id(2)
+ .name("Max")
+ .birthday(
+ LocalDate.parse(
+ "11.11.1990",
+ DateTimeFormatter.ofPattern("dd.MM.yyyy")))
+ .educationLevel(EducationLevel.NFS)
+ .isDriver(false)
+ .isPilot(false)
+ .build();
+
+ Employee empThree =
+ Employee.builder()
+ .id(3)
+ .name("Lisa")
+ .birthday(
+ LocalDate.parse(
+ "16.10.1999",
+ DateTimeFormatter.ofPattern("dd.MM.yyyy")))
+ .educationLevel(EducationLevel.NKI)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+
+ Assert.assertTrue(employees.contains(empOne));
+ Assert.assertTrue(employees.contains(empTwo));
+ Assert.assertTrue(employees.contains(empThree));
+ Assert.assertEquals(3, employees.size());
+
+ } catch (PersistenceException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void testEmployeeListNoElement() {
+
+ try {
+ List<Employee> employees = employeePersistence.list();
+
+ Employee empOne =
+ Employee.builder()
+ .id(10)
+ .name("Adam")
+ .birthday(
+ LocalDate.parse(
+ "10.10.2010",
+ DateTimeFormatter.ofPattern("dd.MM.yyyy")))
+ .educationLevel(EducationLevel.RS)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+
+ Assert.assertFalse(employees.contains(empOne));
+
+ } catch (PersistenceException e) {
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTest.java
new file mode 100644
index 0000000..47328b3
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTest.java
@@ -0,0 +1,68 @@
+package at.ac.tuwien.sepm.assignment.groupphase.employee;
+
+import static junit.framework.TestCase.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDatabaseDao;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeServiceImpl;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidEmployeeException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.time.LocalDate;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EmployeeServiceTest {
+
+ private final EmployeeDAO employeePersistence = mock(EmployeeDatabaseDao.class);
+ private final EmployeeService employeeService = new EmployeeServiceImpl(employeePersistence);
+
+ public EmployeeServiceTest() throws PersistenceException {
+ when(employeePersistence.add(any())).thenReturn(1L);
+ }
+
+ @Test
+ public void testAddValidEmployee() {
+
+ Employee employee =
+ Employee.builder()
+ .name("Testperson")
+ .birthday(LocalDate.MIN)
+ .educationLevel(EducationLevel.NA)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+
+ try {
+ Assert.assertThat(employeeService.add(employee), is(1L));
+ } catch (InvalidEmployeeException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidEmployeeException.class)
+ public void testAddInvalidEmployee() throws InvalidEmployeeException {
+
+ Employee employee =
+ Employee.builder()
+ .name("")
+ .birthday(LocalDate.MIN)
+ .educationLevel(EducationLevel.NA)
+ .isDriver(true)
+ .isPilot(false)
+ .build();
+
+ try {
+ employeeService.add(employee);
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTestConfiguration.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTestConfiguration.java
new file mode 100644
index 0000000..3668ef4
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeeServiceTestConfiguration.java
@@ -0,0 +1,19 @@
+package at.ac.tuwien.sepm.assignment.groupphase.employee;
+
+import static org.mockito.Mockito.mock;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.EmployeeServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+@Configuration
+public class EmployeeServiceTestConfiguration {
+
+ @Bean
+ @Primary
+ public EmployeeService employeeService() {
+ return mock(EmployeeServiceImpl.class);
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationPersistenceTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationPersistenceTest.java
new file mode 100644
index 0000000..be612d0
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationPersistenceTest.java
@@ -0,0 +1,109 @@
+package at.ac.tuwien.sepm.assignment.groupphase.operation;
+
+public class OperationPersistenceTest {
+
+ /*private final OperationDAO operationDAO =
+ new DBOperationDAO(new JDBCConnectionManager("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"));
+
+ @BeforeClass
+ public static void createSchema() throws SQLException {
+ RunScript.execute(
+ "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
+ "",
+ "",
+ "classpath:sql/database.sql",
+ Charset.forName("UTF8"),
+ false);
+ }
+
+ @Test
+ public void addOperationTest() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle))
+ .build();
+ try {
+ operationDAO.add(operation);
+ } catch (PersistenceException e) {
+ fail();
+ }
+ }
+
+ /*@Test(expected = PersistenceException.class)
+ public void addFaultyOperationTest() throws PersistenceException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle))
+ .build();
+ operationDAO.add(operation);
+ }*/
+ /*
+
+ @Test(expected = PersistenceException.class)
+ public void addFaultyOperation1Test() throws PersistenceException {
+ operationDAO.add(null);
+ }
+
+ @Test(expected = PersistenceException.class)
+ public void addFaultyOperation2Test() throws PersistenceException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination(
+ "Wiednerstraße 888, 1010 Wien Wiednerstraße 888, 1010 Wien Wiednerstraße 888, 1010 Wien Wiednerstraße 888, 1010 Wien Wiednerstraße 888, 1010 Wien ")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle))
+ .build();
+ operationDAO.add(operation);
+ }
+
+ @Test(expected = PersistenceException.class)
+ public void addConnectionTest() throws PersistenceException {
+ operationDAO.connectVehicleToOperation(-1, 0);
+ }
+
+ // TODO: ADD CONNECTION TESTS
+ // KOMMT ID ZURÜCK?*/
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceComponentTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceComponentTest.java
new file mode 100644
index 0000000..286ee07
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceComponentTest.java
@@ -0,0 +1,130 @@
+package at.ac.tuwien.sepm.assignment.groupphase.operation;
+
+public class OperationServiceComponentTest {
+
+ /*private final OperationDAO operationDAO =
+ new DBOperationDAO(new JDBCConnectionManager("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"));
+ private final OperationService operationService = new OperationServiceImpl(operationDAO);
+
+ @Test
+ public void addOperationTest() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle))
+ .build();
+ try {
+ // TODO: OPERATION DOES NOT WORK
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (InvalidOperationException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperationTest() throws InvalidOperationException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+ Vehicle vehicle1 =
+ Vehicle.builder()
+ .status(Vehicle.Status.ABGEMELDET)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle, vehicle1))
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation2Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation3Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation4Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("")
+ .created(Instant.now())
+ .destination("Römergasse 7, 2500 Baden")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }*/
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceUnitTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceUnitTest.java
new file mode 100644
index 0000000..fc10553
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/operation/OperationServiceUnitTest.java
@@ -0,0 +1,155 @@
+package at.ac.tuwien.sepm.assignment.groupphase.operation;
+
+import static junit.framework.TestCase.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.OperationDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Severity;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Status;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationServiceImpl;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidOperationException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import java.time.Instant;
+import java.util.List;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class OperationServiceUnitTest {
+ private final OperationDAO operationDAO = mock(OperationDAO.class);
+ private final OperationService operationService = new OperationServiceImpl(operationDAO);
+
+ @Test
+ public void addOperationTest() {
+ try {
+ when(operationDAO.add(any())).thenReturn(1L);
+ } catch (PersistenceException e) {
+ fail();
+ }
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle))
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (InvalidOperationException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperationTest() throws InvalidOperationException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .status(Vehicle.Status.FREI_FUNK)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+ Vehicle vehicle1 =
+ Vehicle.builder()
+ .status(Vehicle.Status.ABGEMELDET)
+ .constructionType(ConstructionType.HOCHDACH)
+ .name("BKTW_123")
+ .hasNef(true)
+ .type(VehicleType.BKTW)
+ .build();
+
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of(vehicle, vehicle1))
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation2Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("Wiedner Hauptstraße 35, Wien")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation3Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("ALP-95E7")
+ .created(Instant.now())
+ .destination("")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test(expected = InvalidOperationException.class)
+ public void addFaultyOperation4Test() throws InvalidOperationException {
+ Operation operation =
+ Operation.builder()
+ .status(Status.ACTIVE)
+ .opCode("")
+ .created(Instant.now())
+ .destination("Römergasse 7, 2500 Baden")
+ .additionalInfo("HTU Wien")
+ .severity(Severity.B)
+ .vehicles(List.of())
+ .build();
+ try {
+ Assert.assertThat(operationService.add(operation), is(1L));
+ } catch (ServiceException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/Helper.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/Helper.java
new file mode 100644
index 0000000..b808206
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/Helper.java
@@ -0,0 +1,28 @@
+package at.ac.tuwien.sepm.assignment.groupphase.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
+import javafx.stage.Window;
+import org.testfx.api.FxRobotContext;
+
+public class Helper {
+
+ public static Stage getTopModalStage(FxRobotContext robotContext) {
+
+ List<Window> allWindows = new ArrayList<>(robotContext.getWindowFinder().listWindows());
+ Collections.reverse(allWindows);
+ return (Stage)
+ allWindows
+ .stream()
+ .filter(window -> window instanceof Stage)
+ .filter(
+ window ->
+ ((Stage) window).getModality()
+ == Modality.APPLICATION_MODAL)
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/HighDpiAwareApplicationTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/HighDpiAwareApplicationTest.java
new file mode 100644
index 0000000..c9816a1
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/HighDpiAwareApplicationTest.java
@@ -0,0 +1,24 @@
+package at.ac.tuwien.sepm.assignment.groupphase.util;
+
+import javafx.geometry.Bounds;
+import javafx.scene.Node;
+import org.testfx.api.FxRobotContext;
+import org.testfx.framework.junit.ApplicationTest;
+import org.testfx.service.locator.impl.BoundsLocatorImpl;
+import org.testfx.service.locator.impl.PointLocatorImpl;
+
+public class HighDpiAwareApplicationTest extends ApplicationTest {
+
+ public HighDpiAwareApplicationTest() {
+ FxRobotContext context = robotContext();
+ context.setBoundsLocator(
+ new BoundsLocatorImpl() {
+ @Override
+ public Bounds boundsOnScreenFor(Node node) {
+ Bounds bounds = super.boundsOnScreenFor(node);
+ return ScaledBounds.wrap(bounds);
+ }
+ });
+ robotContext().setPointLocator(new PointLocatorImpl(context.getBoundsLocator()));
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/ScaledBounds.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/ScaledBounds.java
new file mode 100644
index 0000000..02c15c4
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/util/ScaledBounds.java
@@ -0,0 +1,34 @@
+package at.ac.tuwien.sepm.assignment.groupphase.util;
+
+import java.awt.GraphicsEnvironment;
+import javafx.geometry.BoundingBox;
+import javafx.geometry.Bounds;
+
+public class ScaledBounds extends BoundingBox {
+
+ private static final double scale;
+
+ static {
+ scale =
+ 1
+ / GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getDefaultScreenDevice()
+ .getDefaultConfiguration()
+ .getDefaultTransform()
+ .getScaleX();
+ }
+
+ public static ScaledBounds wrap(Bounds bounds) {
+ return new ScaledBounds(bounds);
+ }
+
+ private ScaledBounds(Bounds wrapped) {
+ super(
+ wrapped.getMinX() * scale,
+ wrapped.getMinY() * scale,
+ wrapped.getMinZ() * scale,
+ wrapped.getWidth() * scale,
+ wrapped.getHeight() * scale,
+ wrapped.getDepth());
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CarAddTestService.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CarAddTestService.java
new file mode 100644
index 0000000..de7a26a
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CarAddTestService.java
@@ -0,0 +1,283 @@
+package at.ac.tuwien.sepm.assignment.groupphase.vehicle;
+
+import static junit.framework.TestCase.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.VehicleDAO;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.VehicleDatabaseDao;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleServiceImpl;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import org.junit.Test;
+
+public class CarAddTestService {
+ private final VehicleDAO vehicleP = mock(VehicleDatabaseDao.class);
+ private final VehicleService vehicleService = new VehicleServiceImpl(vehicleP);
+
+ public CarAddTestService() throws PersistenceException {
+ when(vehicleP.add(any())).thenReturn(1L);
+ }
+
+ @Test
+ public void testValidVehicleH() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.RTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.KTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.KTW_B)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.BKTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void testValidVehicleM() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.KTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.KTW_B)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.BKTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test
+ public void testValidVehicleN() {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.BKTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.NEF)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.NAH)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (InvalidVehicleException | ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidVehicleException.class)
+ public void testInvalidVehicleH() throws InvalidVehicleException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.NEF)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.HOCHDACH)
+ .type(Vehicle.VehicleType.NAH)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidVehicleException.class)
+ public void testInvalidVehicleM() throws InvalidVehicleException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.NEF)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.NAH)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.MITTELHOCHDACH)
+ .type(Vehicle.VehicleType.RTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+
+ @Test(expected = InvalidVehicleException.class)
+ public void testInvalidVehicleN() throws InvalidVehicleException {
+ Vehicle vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.RTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.KTW_B)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ vehicle =
+ Vehicle.builder()
+ .constructionType(Vehicle.ConstructionType.NORMAL)
+ .type(Vehicle.VehicleType.KTW)
+ .hasNef(true)
+ .status(Vehicle.Status.ABGEMELDET)
+ .name("")
+ .build();
+ try {
+ vehicleService.add(vehicle);
+ } catch (ServiceException e) {
+ fail();
+ }
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleApplication.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleApplication.java
new file mode 100644
index 0000000..dcd88ec
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleApplication.java
@@ -0,0 +1,51 @@
+package at.ac.tuwien.sepm.assignment.groupphase.vehicle;
+
+import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader;
+import java.lang.invoke.MethodHandles;
+import javafx.application.Application;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+
+@Component
+@ComponentScan("at.ac.tuwien.sepm.assignment.groupphase")
+public class CreateNewVehicleApplication extends Application {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ public static AnnotationConfigApplicationContext context;
+
+ @Override
+ public void start(Stage primaryStage) throws Exception {
+ // setup application
+ primaryStage.setTitle("Fahrzeug anlegen");
+ primaryStage.setWidth(1366);
+ primaryStage.setHeight(768);
+ primaryStage.centerOnScreen();
+ primaryStage.setOnCloseRequest(event -> LOG.debug("Application shutdown initiated"));
+
+ context = new AnnotationConfigApplicationContext(CreateNewVehicleApplication.class);
+ final var fxmlLoader = context.getBean(SpringFXMLLoader.class);
+ primaryStage.setScene(
+ new Scene(
+ (Parent)
+ fxmlLoader.load(
+ getClass().getResourceAsStream("/fxml/createCar.fxml"))));
+
+ // show application
+ primaryStage.show();
+ primaryStage.toFront();
+ LOG.debug("Application startup complete");
+ }
+
+ @Override
+ public void stop() {
+ LOG.debug("Stopping application");
+ context.close();
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleControllerTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleControllerTest.java
new file mode 100644
index 0000000..866ed74
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/CreateNewVehicleControllerTest.java
@@ -0,0 +1,79 @@
+package at.ac.tuwien.sepm.assignment.groupphase.vehicle;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;
+import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
+import at.ac.tuwien.sepm.assignment.groupphase.util.Helper;
+import at.ac.tuwien.sepm.assignment.groupphase.util.HighDpiAwareApplicationTest;
+import javafx.scene.control.DialogPane;
+import javafx.scene.input.MouseButton;
+import javafx.stage.Stage;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.testfx.api.FxToolkit;
+import org.testfx.robot.Motion;
+
+public class CreateNewVehicleControllerTest extends HighDpiAwareApplicationTest {
+
+ private VehicleService vehicleService;
+
+ @Before
+ public void setup() throws Exception {
+ // TODO: check if testfx can be run in headless mode on Jenkins
+ FxToolkit.registerPrimaryStage();
+ FxToolkit.setupApplication(CreateNewVehicleApplication.class);
+ vehicleService = CreateNewVehicleApplication.context.getBean(VehicleService.class);
+ }
+
+ @After
+ public void cleanup() throws Exception {
+ FxToolkit.cleanupStages();
+ }
+
+ @Test
+ public void testClickAddValidVehicle() throws ServiceException, InvalidVehicleException {
+
+ when(vehicleService.add(any())).thenReturn(1L);
+
+ clickOn("#btn_create", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Speichern Erfolgreich", dialogPane.getHeaderText());
+ }
+
+ @Test
+ public void testClickInvalidVehicleEx() throws ServiceException, InvalidVehicleException {
+
+ when(vehicleService.add(any())).thenThrow(InvalidVehicleException.class);
+
+ clickOn("#btn_create", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Ungültige Eingabe", dialogPane.getHeaderText());
+ }
+
+ @Test
+ public void testClickInvalidServiceEx() throws ServiceException, InvalidVehicleException {
+
+ when(vehicleService.add(any())).thenThrow(ServiceException.class);
+
+ clickOn("#btn_create", Motion.DIRECT, MouseButton.PRIMARY);
+
+ Stage alertDialog = Helper.getTopModalStage(robotContext());
+ Assert.assertNotNull(alertDialog);
+
+ DialogPane dialogPane = (DialogPane) alertDialog.getScene().getRoot();
+ Assert.assertEquals("Fehler", dialogPane.getHeaderText());
+ }
+}
diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/VehicleServiceTestConfiguration.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/VehicleServiceTestConfiguration.java
new file mode 100644
index 0000000..ccd1e5d
--- /dev/null
+++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/vehicle/VehicleServiceTestConfiguration.java
@@ -0,0 +1,19 @@
+package at.ac.tuwien.sepm.assignment.groupphase.vehicle;
+
+import static org.mockito.Mockito.mock;
+
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleService;
+import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.VehicleServiceImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+@Configuration
+public class VehicleServiceTestConfiguration {
+
+ @Bean
+ @Primary
+ public VehicleService vehicleService() {
+ return mock(VehicleServiceImpl.class);
+ }
+}
diff --git a/src/test/resources/employeeServiceTestData.xml b/src/test/resources/employeeServiceTestData.xml
new file mode 100644
index 0000000..c21fde6
--- /dev/null
+++ b/src/test/resources/employeeServiceTestData.xml
@@ -0,0 +1,12 @@
+<dataset>
+ <EmployeeVersion id="10" name="Adam" birthday="2010-10-10" educationlevel="RS" isDriver="true"
+ isPilot="false"/>
+ <EmployeeVersion id="20" name="Max" birthday="1990-11-11" educationlevel="NFS" isDriver="false"
+ isPilot="false"/>
+ <EmployeeVersion id="30" name="Lisa" birthday="1999-10-16" educationlevel="NKI" isDriver="true"
+ isPilot="false"/>
+
+ <Employee id="1" version="10" />
+ <Employee id="2" version="20" />
+ <Employee id="3" version="30" />
+</dataset> \ No newline at end of file