diff options
Diffstat (limited to 'src/main/java')
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; +        } +    } +}  | 
