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/java/at/ac/tuwien/sepm/assignment | |
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/java/at/ac/tuwien/sepm/assignment')
25 files changed, 2152 insertions, 35 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; + } + } +} |