diff options
19 files changed, 1237 insertions, 22 deletions
@@ -26,6 +26,7 @@          <mockito.version>2.18.0</mockito.version>          <google-java-format.version>1.5</google-java-format.version>          <testfx.version>4.0.13-alpha</testfx.version> +        <dbunit.version>2.5.1</dbunit.version>          <!-- plugins -->          <maven-surefire-plugin.version>2.21.0</maven-surefire-plugin.version>          <maven-shade-plugin.version>3.1.1</maven-shade-plugin.version> @@ -66,13 +67,13 @@            <version>${auto-value.version}</version>            <scope>provided</scope>          </dependency> -        <!-- runtime dependencies -->          <dependency>              <groupId>com.h2database</groupId>              <artifactId>h2</artifactId>              <version>${h2.version}</version> -            <scope>runtime</scope> +            <scope>compile</scope>          </dependency> +        <!-- runtime dependencies -->          <dependency>              <groupId>ch.qos.logback</groupId>              <artifactId>logback-classic</artifactId> @@ -115,6 +116,11 @@              <version>${testfx.version}</version>              <scope>test</scope>          </dependency> +        <dependency> +            <groupId>org.dbunit</groupId> +            <artifactId>dbunit</artifactId> +            <version>${dbunit.version}</version> +        </dependency>      </dependencies>      <build> 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..0683c77 --- /dev/null +++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowController.java @@ -0,0 +1,202 @@ +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); +        cbEnd.setItems(hours); +    } + +    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, 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/EmployeeDatabaseDao.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/EmployeeDatabaseDao.java index 900fd0e..3e4ba12 100644 --- 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 @@ -1,6 +1,7 @@  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; @@ -10,6 +11,7 @@ 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; @@ -23,8 +25,12 @@ public class EmployeeDatabaseDao implements EmployeeDAO {              "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; +    private final PreparedStatement insertEmployeeVersion, insertEmployee, listEmployee;      public EmployeeDatabaseDao(JDBCConnectionManager connectionManager)              throws PersistenceException { @@ -38,6 +44,8 @@ public class EmployeeDatabaseDao implements EmployeeDAO {              insertEmployee =                      connection.prepareStatement(INSERT_EMPLOYEE, Statement.RETURN_GENERATED_KEYS); +            listEmployee = connection.prepareStatement(LIST_EMPLOYEE); +          } catch (SQLException e) {              throw new PersistenceException(e);          } @@ -82,7 +90,31 @@ public class EmployeeDatabaseDao implements EmployeeDAO {      @Override      public List<Employee> list() throws PersistenceException { -        throw new UnsupportedOperationException(); + +        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 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..e4bc0ab --- /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/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/service/EmployeeServiceImpl.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/EmployeeServiceImpl.java index 144ccc6..ed0fb1c 100644 --- 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 @@ -36,7 +36,12 @@ public class EmployeeServiceImpl implements EmployeeService {      @Override      public List<Employee> list() throws ServiceException { -        return null; + +        try { +            return employeePersistence.list(); +        } catch (PersistenceException e) { +            throw new ServiceException(e); +        }      }      @Override 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 801148c..c20ed3c 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 @@ -1,6 +1,7 @@  package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service;  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.exception.InvalidRegistrationException;  import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException;  import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException; @@ -11,14 +12,14 @@ public interface RegistrationService {      /**       * Register employee to a vehicle.       * -     * @param vehicleId the id of the target vehicle +     * @param vehicle the target vehicle       * @param registrations that should be added to the vehicle -     * @return a list of the ids that were assigned +     * @return the id that was 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       */ -    List<Long> add(long vehicleId, List<Registration> registrations) +    List<Long> add(Vehicle vehicle, 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..b0605f0 --- /dev/null +++ b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImpl.java @@ -0,0 +1,45 @@ +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.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.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; + +    @Autowired +    public RegistrationServiceImpl(RegistrationDAO registrationDAO) { +        this.registrationDAO = registrationDAO; +    } + +    @Override +    public List<Long> add(Vehicle vehicle, List<Registration> registrations) +            throws InvalidVehicleException, InvalidRegistrationException, ServiceException { +        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 index 4a11298..bbe668b 100644 --- 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 @@ -9,14 +9,16 @@ 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 vehicleDAO; -    public VehicleServiceImpl(VehicleDAO vehicleDAO) { -        this.vehicleDAO = vehicleDAO; +    private VehicleDAO vehiclePersistence; + +    public VehicleServiceImpl(VehicleDAO vehiclePersistence) { +        this.vehiclePersistence = vehiclePersistence;      }      public long add(Vehicle vehicle) throws InvalidVehicleException, ServiceException { @@ -59,7 +61,7 @@ public class VehicleServiceImpl implements VehicleService {                  throw new ServiceException("not a Valid type");          }          try { -            vehicleDAO.add(vehicle); +            vehiclePersistence.add(vehicle);          } catch (PersistenceException e) {              throw new ServiceException(e);          } @@ -70,10 +72,27 @@ public class VehicleServiceImpl implements VehicleService {          throw new UnsupportedOperationException();      } +    @Override      public List<Vehicle> list(EnumSet<Status> statuses) throws ServiceException { -        throw new UnsupportedOperationException(); + +        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/util/JDBCConnectionManager.java b/src/main/java/at/ac/tuwien/sepm/assignment/groupphase/util/JDBCConnectionManager.java index 5494471..6eb15ec 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 = +    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/resources/fxml/RegistrationWindow.fxml b/src/main/resources/fxml/RegistrationWindow.fxml new file mode 100644 index 0000000..0394ca7 --- /dev/null +++ b/src/main/resources/fxml/RegistrationWindow.fxml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.SplitPane?> +<?import javafx.scene.control.TableColumn?> +<?import javafx.scene.control.TableView?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> + +<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="600.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller.RegistrationWindowController"> +   <children> +      <AnchorPane prefHeight="135.0" prefWidth="600.0"> +         <children> +            <Label layoutX="14.0" layoutY="14.0" text="Neue Anmeldung" /> +            <Label layoutX="14.0" layoutY="44.0" text="von" /> +            <Label layoutX="133.0" layoutY="44.0" text="bis" /> +            <ChoiceBox fx:id="cbStart" layoutX="42.0" layoutY="40.0" prefWidth="80.0" /> +            <ChoiceBox fx:id="cbEnd" layoutX="159.0" layoutY="40.0" prefWidth="80.0" /> +            <Label layoutX="10.0" layoutY="82.0" text="Fahrzeug" /> +            <Label fx:id="lVehicles" layoutX="10.0" layoutY="108.0" text="Fahrzeugname" /> +            <Label layoutX="216.0" layoutY="82.0" text="Personen" /> +            <Label fx:id="lEmployees" layoutX="216.0" layoutY="108.0" text="Namen" /> +         </children> +      </AnchorPane> +      <SplitPane dividerPositions="0.35" prefWidth="200.0"> +        <items> +            <VBox prefHeight="200.0" prefWidth="100.0"> +               <children> +                  <Label text="Fahrzeugsuche" /> +                  <TextField fx:id="tfVehicleSearch" /> +                  <TableView fx:id="tvVehicles" prefHeight="200.0" prefWidth="200.0"> +                    <columns> +                      <TableColumn fx:id="tcVehicles" prefWidth="75.0" text="Fahrzeuge" /> +                    </columns> +                     <columnResizePolicy> +                        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> +                     </columnResizePolicy> +                  </TableView> +               </children> +            </VBox> +            <VBox prefHeight="200.0" prefWidth="100.0"> +               <children> +                  <Label text="Personensuche" /> +                  <TextField fx:id="tfEmployeeSearch" /> +                  <TableView fx:id="tvEmployees" prefHeight="200.0" prefWidth="200.0"> +                    <columns> +                      <TableColumn fx:id="tcEmployees" prefWidth="75.0" text="Personen" /> +                    </columns> +                     <columnResizePolicy> +                        <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> +                     </columnResizePolicy> +                  </TableView> +               </children> +            </VBox> +        </items> +      </SplitPane> +      <HBox alignment="CENTER" prefWidth="200.0"> +         <children> +            <Button mnemonicParsing="false" onAction="#cancel" text="Abbrechen"> +               <HBox.margin> +                  <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" /> +               </HBox.margin> +            </Button> +            <Button mnemonicParsing="false" onAction="#create" text="Erstellen"> +               <HBox.margin> +                  <Insets bottom="8.0" left="8.0" right="8.0" top="8.0" /> +               </HBox.margin> +            </Button> +         </children></HBox> +   </children> +</VBox> diff --git a/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql b/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql new file mode 100644 index 0000000..f43b641 --- /dev/null +++ b/src/main/resources/sql/H2RegistrationDAOTest_depopulate.sql @@ -0,0 +1,5 @@ +DELETE FROM Registration; +DELETE FROM Vehicle; +DELETE FROM VehicleVersion; +DELETE FROM Employee; +DELETE FROM EmployeeVersion;
\ No newline at end of file diff --git a/src/main/resources/sql/H2RegistrationDAOTest_populate.sql b/src/main/resources/sql/H2RegistrationDAOTest_populate.sql new file mode 100644 index 0000000..b81eb78 --- /dev/null +++ b/src/main/resources/sql/H2RegistrationDAOTest_populate.sql @@ -0,0 +1,10 @@ +INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (1, 'John Doe', '2000-01-01', 'RS', TRUE, TRUE); +INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (2, 'Nick "Kage" Verily', '1990-01-01', 'NKV', TRUE, FALSE); +INSERT INTO EmployeeVersion (id, name, birthday, educationLevel, isDriver, isPilot) VALUES (3, 'Nicht Arzt', '1980-01-01', 'NA', FALSE, FALSE); +INSERT INTO Employee (id, version) VALUES (1, 1); +INSERT INTO Employee (id, version) VALUES (2, 2); +INSERT INTO Employee (id, version) VALUES (3, 3); +INSERT INTO VehicleVersion (id, name, hasNef, constructionType, type) VALUES (1, 'RTW-1', TRUE, 'Hochdach', 'RTW'); +INSERT INTO VehicleVersion (id, name, hasNef, constructionType, type) VALUES (2, 'NEF-1', FALSE, 'Normal', 'NEF'); +INSERT INTO Vehicle (id, version, status) VALUES (1, 1, 'abgemeldet'); +INSERT INTO Vehicle (id, version, status) VALUES (2, 2, 'abgemeldet');
\ No newline at end of file diff --git a/src/main/resources/sql/database.sql b/src/main/resources/sql/database.sql index bb23c91..e775550 100644 --- a/src/main/resources/sql/database.sql +++ b/src/main/resources/sql/database.sql @@ -1,26 +1,30 @@  CREATE TABLE IF NOT EXISTS VehicleVersion (    id BIGINT AUTO_INCREMENT PRIMARY KEY,    name VARCHAR(100) NOT NULL, -  constructionType ENUM('Normal', 'Hochdach', 'Mittelhochdach') NOT NULL, -  type ENUM('BKTW', 'KTW-B', 'KTW', 'RTW', 'NEF', 'NAH') NOT NULL, +  constructionType VARCHAR NOT NULL, +  type VARCHAR NOT NULL,    hasNef BOOLEAN NOT NULL, +  CHECK constructionType IN ('Normal', 'Hochdach', 'Mittelhochdach'), +  CHECK type IN ('BKTW', 'KTW-B', 'KTW', 'RTW', 'NEF', 'NAH')  );  CREATE TABLE IF NOT EXISTS Vehicle (    id BIGINT AUTO_INCREMENT PRIMARY KEY,    version BIGINT NOT NULL, -  status ENUM('abgemeldet', 'frei_wache', 'zum_berufungsort', 'am_berufungsort', 'zum_zielort', -              'am_zielort', 'frei_funk', 'deleted') NOT NULL, +  status VARCHAR NOT NULL,    FOREIGN KEY (version) REFERENCES VehicleVersion(id), +  CHECK status IN ('abgemeldet', 'frei_wache', 'zum_berufungsort', 'am_berufungsort', 'zum_zielort', +              'am_zielort', 'frei_funk', 'deleted')  );  CREATE TABLE IF NOT EXISTS EmployeeVersion (    id BIGINT AUTO_INCREMENT PRIMARY KEY,    name VARCHAR(100) NOT NULL,    birthday DATE NOT NULL, -  educationLevel ENUM('RS', 'NFS', 'NKV', 'NKA', 'NKI', 'NA') NOT NULL, +  educationLevel VARCHAR NOT NULL,    isDriver BOOLEAN NOT NULL,    isPilot BOOLEAN NOT NULL, +  CHECK educationLevel IN ('RS', 'NFS', 'NKV', 'NKA', 'NKI', 'NA')  );  CREATE TABLE IF NOT EXISTS Employee ( @@ -43,10 +47,11 @@ CREATE TABLE IF NOT EXISTS Registration (  CREATE TABLE IF NOT EXISTS Operation (    id BIGINT AUTO_INCREMENT PRIMARY KEY,    opCode VARCHAR(20) NOT NULL, -  severity ENUM('A', 'B', 'C', 'D', 'E', 'O') NOT NULL, +  severity VARCHAR NOT NULL,    created TIMESTAMP NOT NULL,    destination VARCHAR(100) NOT NULL,    additionalInfo VARCHAR(100), +  CHECK severity IN ('A', 'B', 'C', 'D', 'E', 'O')  );  CREATE TABLE IF NOT EXISTS VehicleOperation ( diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java new file mode 100644 index 0000000..3293ae9 --- /dev/null +++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/controller/RegistrationWindowApplication.java @@ -0,0 +1,53 @@ +package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.controller; + +import at.ac.tuwien.sepm.assignment.groupphase.util.SpringFXMLLoader; +import java.lang.invoke.MethodHandles; +import javafx.application.Application; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.stage.Stage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; + +@Component +@ComponentScan("at.ac.tuwien.sepm.assignment.groupphase") +public class RegistrationWindowApplication extends Application { + +    private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + +    public static AnnotationConfigApplicationContext context; + +    @Override +    public void start(Stage primaryStage) throws Exception { +        // setup application +        primaryStage.setTitle("Person anlegen"); +        // primaryStage.setWidth(1366); +        // primaryStage.setHeight(768); +        primaryStage.centerOnScreen(); +        primaryStage.setOnCloseRequest(event -> LOG.debug("Application shutdown initiated")); + +        context = new AnnotationConfigApplicationContext(RegistrationWindowApplication.class); +        final var fxmlLoader = context.getBean(SpringFXMLLoader.class); +        primaryStage.setScene( +                new Scene( +                        (Parent) +                                fxmlLoader.load( +                                        getClass() +                                                .getResourceAsStream( +                                                        "/fxml/RegistrationWindow.fxml")))); + +        // show application +        primaryStage.show(); +        primaryStage.toFront(); +        LOG.debug("Application startup complete"); +    } + +    @Override +    public void stop() { +        LOG.debug("Stopping application"); +        context.close(); +    } +} diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java new file mode 100644 index 0000000..980c429 --- /dev/null +++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/dao/RegistrationDatabaseDAOTest.java @@ -0,0 +1,162 @@ +package at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao; + +import static org.junit.Assert.*; + +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration; +import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException; +import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager; +import java.nio.charset.Charset; +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDate; +import java.util.LinkedList; +import java.util.List; +import org.h2.tools.RunScript; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class RegistrationDatabaseDAOTest { + +    // Base taken from EmployeePersistenceTest + +    private static final String JDBC_DRIVER = org.h2.Driver.class.getName(); +    private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; +    private static final String USER = ""; +    private static final String PASSWORD = ""; + +    private RegistrationDAO registrationDAO; + +    public RegistrationDatabaseDAOTest() throws PersistenceException { +        this.registrationDAO = new RegistrationDatabaseDAO(new JDBCConnectionManager(JDBC_URL)); +    } + +    @BeforeClass +    public static void setupDatabase() throws SQLException { +        RunScript.execute( +                JDBC_URL, +                USER, +                PASSWORD, +                "classpath:sql/database.sql", +                Charset.forName("UTF8"), +                false); +    } + +    @Before +    public void setUp() throws SQLException { +        RunScript.execute( +                JDBC_URL, +                USER, +                PASSWORD, +                "classpath:sql/H2RegistrationDAOTest_populate.sql", +                Charset.forName("UTF8"), +                false); +    } + +    @After +    public void tearDown() throws SQLException { +        RunScript.execute( +                JDBC_URL, +                USER, +                PASSWORD, +                "classpath:sql/H2RegistrationDAOTest_depopulate.sql", +                Charset.forName("UTF8"), +                false); +    } + +    @Rule public ExpectedException thrown = ExpectedException.none(); + +    @Test +    public void addRegistrationsShouldSucceed() throws PersistenceException { +        List<Registration> registrations = new LinkedList<>(); +        /* +        Vehicle vehicle = Vehicle.builder() +                .id(1) +                .name("RTW-1") +                .constructionType(ConstructionType.HOCHDACH) +                .type(VehicleType.RTW) +                .status(Status.ABGEMELDET) +                .hasNef(true) +                .build(); +        */ +        Employee employee1 = +                Employee.builder() +                        .id(1) +                        .name("John Doe") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.RS) +                        .isDriver(true) +                        .isPilot(true) +                        .build(); +        Employee employee2 = +                Employee.builder() +                        .id(2) +                        .name("Nick \"Kage\" Verily") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.NKV) +                        .isDriver(true) +                        .isPilot(false) +                        .build(); +        Employee employee3 = +                Employee.builder() +                        .id(3) +                        .name("Nicht Arzt") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.NA) +                        .isDriver(false) +                        .isPilot(false) +                        .build(); +        Registration registration1 = +                Registration.builder() +                        .start(Instant.now()) // incorrect, but should be irrelevant to outcome +                        .end(Instant.now()) // same +                        .employee(employee1) +                        .build(); +        Registration registration2 = +                Registration.builder() +                        .start(Instant.now()) // incorrect, but should be irrelevant to outcome +                        .end(Instant.now()) // same +                        .employee(employee2) +                        .build(); +        Registration registration3 = +                Registration.builder() +                        .start(Instant.now()) // incorrect, but should be irrelevant to outcome +                        .end(Instant.now()) // same +                        .employee(employee3) +                        .build(); +        registrations.add(registration1); +        registrations.add(registration2); +        registrations.add(registration3); + +        List<Long> returnvalues = registrationDAO.add(1, registrations); +        assertFalse(returnvalues.isEmpty()); // can be improved... +    } + +    @Test +    public void addRegistrationToInexistentVehicleShouldFail() throws PersistenceException { +        thrown.expect(PersistenceException.class); +        List<Registration> registrations = new LinkedList<>(); +        Employee employee = +                Employee.builder() +                        .id(1) +                        .name("John Doe") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.RS) +                        .isDriver(true) +                        .isPilot(true) +                        .build(); +        Registration registration = +                Registration.builder() +                        .start(Instant.MIN) +                        .end(Instant.MAX) +                        .employee(employee) +                        .build(); +        registrations.add(registration); +        registrationDAO.add(200, registrations); +    } +} diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java new file mode 100644 index 0000000..7171f83 --- /dev/null +++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/einsatzverwaltung/service/RegistrationServiceImplTest.java @@ -0,0 +1,122 @@ +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.Employee; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Registration; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.Status; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType; +import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidRegistrationException; +import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidVehicleException; +import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.LinkedList; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +public class RegistrationServiceImplTest { + +    @Mock RegistrationDAO daoMock; + +    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); + +    @Rule public ExpectedException thrown = ExpectedException.none(); + +    @Test +    public void addValidRegistrationsShouldSucceed() +            throws InvalidRegistrationException, ServiceException, InvalidVehicleException { +        RegistrationService registrationService = new RegistrationServiceImpl(daoMock); +        List<Registration> registrations = new LinkedList<>(); +        Vehicle vehicle = +                Vehicle.builder() +                        .id(1) +                        .name("RTW-1") +                        .constructionType(ConstructionType.HOCHDACH) +                        .type(VehicleType.RTW) +                        .status(Status.ABGEMELDET) +                        .hasNef(true) +                        .build(); +        Employee employee1 = +                Employee.builder() +                        .id(1) +                        .name("John Doe") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.RS) +                        .isDriver(true) +                        .isPilot(true) +                        .build(); +        Employee employee2 = +                Employee.builder() +                        .id(2) +                        .name("Nick \"Kage\" Verily") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.NKV) +                        .isDriver(true) +                        .isPilot(false) +                        .build(); +        Employee employee3 = +                Employee.builder() +                        .id(3) +                        .name("Nicht Arzt") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.NA) +                        .isDriver(false) +                        .isPilot(false) +                        .build(); +        Instant start = Instant.now(); +        Instant end = start.plus(8, ChronoUnit.HOURS); +        Registration registration1 = +                Registration.builder().start(start).end(end).employee(employee1).build(); +        Registration registration2 = +                Registration.builder().start(start).end(end).employee(employee2).build(); +        Registration registration3 = +                Registration.builder().start(start).end(end).employee(employee3).build(); +        registrations.add(registration1); +        registrations.add(registration2); +        registrations.add(registration3); +        registrationService.add(vehicle, registrations); +    } + +    @Test +    public void addOnlyOnePersonToRTWShouldFail() +            throws InvalidRegistrationException, ServiceException, InvalidVehicleException { +        thrown.expect(InvalidRegistrationException.class); +        RegistrationService registrationService = new RegistrationServiceImpl(daoMock); +        List<Registration> registrations = new LinkedList<>(); +        Vehicle vehicle = +                Vehicle.builder() +                        .id(1) +                        .name("RTW-1") +                        .constructionType(ConstructionType.HOCHDACH) +                        .type(VehicleType.RTW) +                        .status(Status.ABGEMELDET) +                        .hasNef(true) +                        .build(); +        Employee employee = +                Employee.builder() +                        .id(1) +                        .name("John Doe") +                        .birthday(LocalDate.now()) // incorrect, but should be irrelevant +                        .educationLevel(EducationLevel.RS) +                        .isDriver(true) +                        .isPilot(true) +                        .build(); +        Registration registration = +                Registration.builder() +                        .start(Instant.MIN) +                        .end(Instant.MAX) +                        .employee(employee) +                        .build(); +        registrations.add(registration); +        registrationService.add(vehicle, registrations); +    } +} diff --git a/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java new file mode 100644 index 0000000..f8fe0f3 --- /dev/null +++ b/src/test/java/at/ac/tuwien/sepm/assignment/groupphase/employee/EmployeePersistenceTest.java @@ -0,0 +1,155 @@ +package at.ac.tuwien.sepm.assignment.groupphase.employee; + +import static junit.framework.TestCase.fail; + +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDAO; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.EmployeeDatabaseDao; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee; +import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Employee.EducationLevel; +import at.ac.tuwien.sepm.assignment.groupphase.exception.PersistenceException; +import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager; +import java.nio.charset.Charset; +import java.sql.SQLException; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import org.dbunit.IDatabaseTester; +import org.dbunit.JdbcDatabaseTester; +import org.dbunit.dataset.DataSetException; +import org.dbunit.dataset.IDataSet; +import org.dbunit.dataset.xml.FlatXmlDataSetBuilder; +import org.dbunit.operation.DatabaseOperation; +import org.h2.tools.RunScript; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class EmployeePersistenceTest { + +    private static final String JDBC_DRIVER = org.h2.Driver.class.getName(); +    private static final String JDBC_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; +    private static final String USER = ""; +    private static final String PASSWORD = ""; + +    private EmployeeDAO employeePersistence; + +    public EmployeePersistenceTest() throws PersistenceException { +        employeePersistence = new EmployeeDatabaseDao(new JDBCConnectionManager(JDBC_URL)); +    } + +    @BeforeClass +    public static void createSchema() throws SQLException { +        RunScript.execute( +                JDBC_URL, +                USER, +                PASSWORD, +                "classpath:sql/database.sql", +                Charset.forName("UTF8"), +                false); +    } + +    @Before +    public void importDataSet() throws Exception { +        IDataSet dataSet = readDataSet(); +        cleanlyInsert(dataSet); +    } + +    private IDataSet readDataSet() throws DataSetException { +        return new FlatXmlDataSetBuilder() +                .build( +                        getClass() +                                .getClassLoader() +                                .getResourceAsStream("employeeServiceTestData.xml")); +    } + +    private void cleanlyInsert(IDataSet dataSet) throws Exception { +        IDatabaseTester databaseTester = +                new JdbcDatabaseTester(JDBC_DRIVER, JDBC_URL, USER, PASSWORD); + +        databaseTester.setSetUpOperation(DatabaseOperation.CLEAN_INSERT); +        databaseTester.setDataSet(dataSet); +        databaseTester.onSetup(); +    } + +    @Test +    public void testListEmployees() { + +        try { +            List<Employee> employees = employeePersistence.list(); + +            Employee empOne = +                    Employee.builder() +                            .id(1) +                            .name("Adam") +                            .birthday( +                                    LocalDate.parse( +                                            "10.10.2010", +                                            DateTimeFormatter.ofPattern("dd.MM.yyyy"))) +                            .educationLevel(EducationLevel.RS) +                            .isDriver(true) +                            .isPilot(false) +                            .build(); + +            Employee empTwo = +                    Employee.builder() +                            .id(2) +                            .name("Max") +                            .birthday( +                                    LocalDate.parse( +                                            "11.11.1990", +                                            DateTimeFormatter.ofPattern("dd.MM.yyyy"))) +                            .educationLevel(EducationLevel.NFS) +                            .isDriver(false) +                            .isPilot(false) +                            .build(); + +            Employee empThree = +                    Employee.builder() +                            .id(3) +                            .name("Lisa") +                            .birthday( +                                    LocalDate.parse( +                                            "16.10.1999", +                                            DateTimeFormatter.ofPattern("dd.MM.yyyy"))) +                            .educationLevel(EducationLevel.NKI) +                            .isDriver(true) +                            .isPilot(false) +                            .build(); + +            Assert.assertTrue(employees.contains(empOne)); +            Assert.assertTrue(employees.contains(empTwo)); +            Assert.assertTrue(employees.contains(empThree)); +            Assert.assertEquals(3, employees.size()); + +        } catch (PersistenceException e) { +            fail(); +        } +    } + +    @Test +    public void testEmployeeListNoElement() { + +        try { +            List<Employee> employees = employeePersistence.list(); + +            Employee empOne = +                    Employee.builder() +                            .id(10) +                            .name("Adam") +                            .birthday( +                                    LocalDate.parse( +                                            "10.10.2010", +                                            DateTimeFormatter.ofPattern("dd.MM.yyyy"))) +                            .educationLevel(EducationLevel.RS) +                            .isDriver(true) +                            .isPilot(false) +                            .build(); + +            Assert.assertFalse(employees.contains(empOne)); + +        } catch (PersistenceException e) { +            fail(); +        } +    } +} diff --git a/src/test/resources/employeeServiceTestData.xml b/src/test/resources/employeeServiceTestData.xml new file mode 100644 index 0000000..c21fde6 --- /dev/null +++ b/src/test/resources/employeeServiceTestData.xml @@ -0,0 +1,12 @@ +<dataset> +  <EmployeeVersion id="10" name="Adam" birthday="2010-10-10" educationlevel="RS" isDriver="true" +    isPilot="false"/> +  <EmployeeVersion id="20" name="Max" birthday="1990-11-11" educationlevel="NFS" isDriver="false" +    isPilot="false"/> +  <EmployeeVersion id="30" name="Lisa" birthday="1999-10-16" educationlevel="NKI" isDriver="true" +    isPilot="false"/> + +  <Employee id="1" version="10" /> +  <Employee id="2" version="20" /> +  <Employee id="3" version="30" /> +</dataset>
\ No newline at end of file  | 
