diff options
author | Tharre <tharre3@gmail.com> | 2018-05-11 15:49:43 +0200 |
---|---|---|
committer | Tharre <tharre3@gmail.com> | 2018-05-11 15:49:43 +0200 |
commit | f7d14a76123911f0bced08356a0c69e61147cb1b (patch) | |
tree | a75b0baa891453a14046c78503603d21986126c5 /src/main | |
parent | acd6b64e494192f7c73032240029bfa53dccb362 (diff) | |
parent | 5298356db60cd971fed686d379130102843db819 (diff) | |
download | sepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.tar.gz sepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.tar.xz sepm-groupproject-f7d14a76123911f0bced08356a0c69e61147cb1b.zip |
Merge branch 'develop'
Diffstat (limited to 'src/main')
38 files changed, 2468 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 Binary files differnew file mode 100644 index 0000000..687f914 --- /dev/null +++ b/src/main/resources/images/NEF.png diff --git a/src/main/resources/images/Not.png b/src/main/resources/images/Not.png Binary files differnew file mode 100644 index 0000000..03063af --- /dev/null +++ b/src/main/resources/images/Not.png diff --git a/src/main/resources/images/NotNEF.png b/src/main/resources/images/NotNEF.png Binary files differnew file mode 100644 index 0000000..0c17d53 --- /dev/null +++ b/src/main/resources/images/NotNEF.png diff --git a/src/main/resources/images/Qualification.png b/src/main/resources/images/Qualification.png Binary files differnew file mode 100644 index 0000000..c58a640 --- /dev/null +++ b/src/main/resources/images/Qualification.png diff --git a/src/main/resources/images/Vehicle.png b/src/main/resources/images/Vehicle.png Binary files differnew file mode 100644 index 0000000..2fe992d --- /dev/null +++ b/src/main/resources/images/Vehicle.png 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 ( |