/** * {@inheritDoc} This method will delete the distance data from a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public boolean delete(Distance distance) throws DataUpdateException, DataAccessException { if (distance == null || distance.id < 0) { return false; } try { if (delete == null || delete.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.DELETE).addWhereClause("id=?"); delete = connection.prepareStatement(builder.build()); } delete.setInt(1, distance.id); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing DataAccessException!"); throw new DataAccessException(e); } try { delete.executeUpdate(); return true; } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataUpdateException!"); throw new DataUpdateException(e); } }
/** * {@inheritDoc} This method will get the distance data from a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public Optional<Distance> getDistanceBetween(Classroom classroom1, Classroom classroom2) throws DataAccessException { Distance distance = null; try { if (selectTwoRooms == null || selectTwoRooms.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.SELECT) .addColumns("id,distance") .addWhereClause( "(startRoomId=? AND endRoomId=?) OR (startRoomId=? AND endRoomId=?"); selectTwoRooms = connection.prepareStatement(builder.build()); } selectTwoRooms.setInt(1, classroom1.id); selectTwoRooms.setInt(4, classroom1.id); selectTwoRooms.setInt(2, classroom2.id); selectTwoRooms.setInt(3, classroom2.id); ResultSet set = selectTwoRooms.executeQuery(); if (set.next()) { distance = new Distance(set.getInt(1), classroom1, classroom2, set.getInt(2)); } set.close(); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); throw new DataAccessException(e); } return Optional.ofNullable(distance); }
/** * {@inheritDoc} This method will insert the distance data into a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public int insert(Distance distance) throws DataUpdateException, DataAccessException { int id = -1; if (distance == null || distance.endRoom == null || distance.startRoom == null || distance.distance < 0) { return id; } try { if (insert == null || insert.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.INSERT) .addColumns("startRoomId", "endRoomId", "distance") .addValue("?,?,?"); insert = connection.prepareStatement(builder.build(), Statement.RETURN_GENERATED_KEYS); } insert.setInt(1, distance.startRoom.id); insert.setInt(2, distance.endRoom.id); insert.setInt(3, distance.distance); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); throw new DataUpdateException(e); } try { insert.executeUpdate(); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataUpdateException!"); throw new DataUpdateException(e); } try { ResultSet set = insert.getGeneratedKeys(); if (set.next()) { id = set.getInt(1); } set.close(); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); } return id; }
/** {@inheritDoc} */ @Override public void close() { try { if (selectAll != null) selectAll.close(); if (selectAllRoomEnd != null) selectAllRoomEnd.close(); if (selectAllRoomStart != null) selectAllRoomStart.close(); if (selectId != null) selectId.close(); if (selectTwoRooms != null) selectTwoRooms.close(); } catch (SQLException e) { Log.error(e); } }
/** {@inheritDoc} */ @Override public boolean deleteAll() throws DataAccessException, DataUpdateException { boolean success = false; try { if (delete == null || delete.isClosed()) { delete = connection.prepareStatement("DELETE FROM distance;"); } } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); throw new DataAccessException(e); } try { delete.execute(); success = true; } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataUpdateException!"); throw new DataUpdateException(e); } return success; }
/** * {@inheritDoc} This method will update the distance data in a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public boolean update(Distance distance) throws DataUpdateException, DataAccessException { if (distance == null || distance.endRoom == null || distance.startRoom == null || distance.id < 0 || distance.distance < 0) { return false; } try { if (update == null || update.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.UPDATE) .addSetClauses("startRoomId=?", "endRoomId=?", "distance=?") .addWhereClause("id=?"); update = connection.prepareStatement(builder.build()); } update.setInt(1, distance.startRoom.id); update.setInt(2, distance.endRoom.id); update.setInt(3, distance.distance); update.setInt(4, distance.id); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing DataAccessException!"); throw new DataAccessException(e); } try { update.executeUpdate(); return true; } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataUpdateException!"); throw new DataUpdateException(e); } }
/** * {@inheritDoc} This method will get the distance data from a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public List<Distance> getAll() throws DataAccessException { ArrayList<Distance> distances = new ArrayList<>(); try { if (selectAll == null || selectAll.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.SELECT) .addColumns( "distance.id", "distance.startRoomId", "distance.endRoomId", "classroom1.roomName", "classroom1.buildingId", "building1.buildingName", "classroom1.subjectId", "subject1.subjectName", "classroom2.roomName", "classroom2.buildingId", "building2.buildingName", "classroom2.subjectId", "subject2.subjectName", "distance.distance") .addJoinClause( new JoinClause( JoinType.INNER, "classroom classroom1", "classroom1.id=distance.startRoomId")) .addJoinClause( new JoinClause( JoinType.INNER, "building building1", "building1.id=classroom1.buildingId")) .addJoinClause( new JoinClause( JoinType.INNER, "subject subject1", "subject1.id=classroom1.subjectId")) .addJoinClause( new JoinClause( JoinType.INNER, "classroom classroom2", "classroom2.id=distance.endRoomId")) .addJoinClause( new JoinClause( JoinType.INNER, "building building2", "building2.id=classroom2.buildingId")) .addJoinClause( new JoinClause( JoinType.INNER, "subject subject2", "subject2.id=classroom2.subjectId")); selectAll = connection.prepareStatement(builder.build()); } ResultSet set = selectAll.executeQuery(); while (set.next()) { Subject subject1 = new Subject(set.getInt(7), set.getString(8)); Subject subject2 = new Subject(set.getInt(12), set.getString(13)); Building building1 = new Building(set.getInt(5), set.getString(6)); Building building2 = new Building(set.getInt(10), set.getString(11)); Classroom classroom1 = new Classroom(set.getInt(2), set.getString(4), building1, subject1); Classroom classroom2 = new Classroom(set.getInt(3), set.getString(9), building2, subject2); distances.add(new Distance(set.getInt(1), classroom1, classroom2, set.getInt(14))); } set.close(); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); throw new DataAccessException(e); } return distances; }
/** * {@inheritDoc} This method will get the distance data from a MariaDB database. This method * assumes the connection member is not null and open. Therefore, should be called through * MariaDaoManager. */ @Override public List<Distance> getAllDistancesFrom(Classroom classroom) throws DataAccessException { ArrayList<Distance> distances = new ArrayList<>(); if (classroom == null || classroom.id < 0) { return distances; } try { if (selectAllRoomStart == null || selectAllRoomStart.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.SELECT) .addColumns( "distance.id", "classroom.id", "classroom.roomName", "building.id", "buildingName", "subject.id", "subject.subjectName", "distance.distance") .addJoinClause( new JoinClause(JoinType.INNER, "classroom", "distance.endRoomId=classroom.id")) .addJoinClause( new JoinClause(JoinType.INNER, "building", "classroom.buildingId=building.id")) .addJoinClause( new JoinClause(JoinType.INNER, "subject", "classroom.subjectId=subject.id")) .addWhereClause("distance.startRoomId=?"); selectAllRoomStart = connection.prepareStatement(builder.build()); } selectAllRoomStart.setInt(1, classroom.id); ResultSet startSet = selectAllRoomStart.executeQuery(); while (startSet.next()) { Distance distance = new Distance( startSet.getInt(1), classroom, new Classroom( startSet.getInt(2), startSet.getString(3), new Building(startSet.getInt(4), startSet.getString(5)), new Subject(startSet.getInt(6), startSet.getString(7))), startSet.getInt(8)); distances.add(distance); } startSet.close(); if (selectAllRoomEnd == null || selectAllRoomEnd.isClosed()) { SqlBuilder builder = new SqlBuilder("distance", StatementType.SELECT) .addColumns( "distance.id", "classroom.id", "classroom.roomName", "building.id", "buildingName", "subject.id", "subject.subjectName", "distance.distance") .addJoinClause( new JoinClause( JoinType.INNER, "classroom", "distance.startRoomId=classroom.id")) .addJoinClause( new JoinClause(JoinType.INNER, "building", "classroom.buildingId=building.id")) .addJoinClause( new JoinClause(JoinType.INNER, "subject", "classroom.subjectId=subject.id")) .addWhereClause("distance.endRoomId=?"); selectAllRoomEnd = connection.prepareStatement(builder.build()); } selectAllRoomEnd.setInt(1, classroom.id); ResultSet endSet = selectAllRoomEnd.executeQuery(); while (endSet.next()) { Distance distance = new Distance( endSet.getInt(1), classroom, new Classroom( endSet.getInt(2), endSet.getString(3), new Building(endSet.getInt(4), endSet.getString(5)), new Subject(endSet.getInt(6), endSet.getString(7))), endSet.getInt(8)); distances.add(distance); } endSet.close(); } catch (SQLException e) { Log.debug("Caught [" + e + "] so throwing a DataAccessException!"); throw new DataAccessException(e); } return distances; }
/** * Gives each lesson a staff member and classroom on a per subject basis, taking into account the * distances between each lesson for each member of staff. * * @return Nothing. */ @Override public Void call() { // get all subjects List<Subject> subjects; List<Distance> distances; StringBuilder failedLog = new StringBuilder(); try { subjects = daoManager.getSubjectDao().getAll(); } catch (DataAccessException e) { updateMessage( "Failed to access subject data due to the error [" + e + "]\n" + "Please restart the timetabler and send the logs to your system administrator if this occurs again."); return null; } catch (DataConnectionException e) { DataExceptionHandler.handleJavaFx(e, null, true); return null; } try { distances = daoManager.getDistanceDao().getAll(); } catch (DataAccessException e) { updateMessage( "Failed to access distance data due to the error [" + e + "]\n" + "Please restart the timetabler and send the logs to your system administrator if this occurs again."); return null; } catch (DataConnectionException e) { DataExceptionHandler.handleJavaFx(e, null, true); return null; } try { subjects.forEach( subject -> { updateMessage("Timetabling [" + subject.name + ']'); // for current subject find periods where multiple classes are taught during the same // period for this subject // The id of the top list is the id of the period as it is static data List<Set<LessonPlan>> overloadedPeriod; overloadedPeriod = findOverloadedPeriods(subject, 31); Log.verbose("Found [" + overloadedPeriod.size() + "] overloaded periods"); List<LessonPlan> lessonPlans = null; List<Staff> staff = null; List<Classroom> classrooms = null; try { // get all lessonPlans for this subject lessonPlans = daoManager.getLessonPlanDao().getAllBySubject(subject); } catch (DataAccessException e) { failedLog .append("Could not access the lesson data!\nThe error was [") .append(e) .append( "]\nPlease restart the timetabler and send the logs to your system administrator") .append(" if this occurs again."); Log.error(e); throw new LambdaBreakException(); } catch (DataConnectionException e) { DataExceptionHandler.handleJavaFx(e, null, true); throw new LambdaBreakException(); } try { // get all staff who teach the subject staff = daoManager.getStaffDao().getAllBySubject(subject); } catch (DataAccessException e) { failedLog .append("Could not access the staff data!\nThe error was [") .append(e) .append( "]\nPlease restart the timetabler and send the logs to your system administrator") .append(" if this occurs again."); Log.error(e); throw new LambdaBreakException(); } catch (DataConnectionException e) { DataExceptionHandler.handleJavaFx(e, null, true); throw new LambdaBreakException(); } try { classrooms = daoManager.getClassroomDao().getAll(); } catch (DataConnectionException e) { failedLog .append("Could not access the classroom data!\nThe error was [") .append(e) .append( "]\nPlease restart the timetabler and send the logs to your system administrator") .append(" if this occurs again."); Log.error(e); throw new LambdaBreakException(); } catch (DataAccessException e) { DataExceptionHandler.handleJavaFx(e, null, true); throw new LambdaBreakException(); } Log.verbose( "Found [" + classrooms.size() + "] classrooms and [" + lessonPlans.size() + "] lessons and [" + staff.size() + "] staff"); // put staff into lessonPlans for this subject, avoiding teacher being scheduled twice // for same period. putStaffIntoLessonPlan(lessonPlans, staff, overloadedPeriod); // Get the data needed for the final part of timetabling List<Distance> subjectDistance = distances .parallelStream() .filter(distance -> distance.startRoom.subject.equals(subject)) .collect(Collectors.toList()); List<Classroom> subjectRooms = classrooms .parallelStream() .filter(classroom -> classroom.subject.equals(subject)) .collect(Collectors.toList()); // Put classrooms into lessonPlans for this subject. // putLessonPlansIntoClassrooms(lessonPlans, subjectRooms, subjectDistance); lessonPlans.forEach( lessonPlan -> { try { daoManager.getLessonPlanDao().update(lessonPlan); } catch (DataAccessException | DataUpdateException e) { failedLog .append("Could not update the lesson data!\nThe error was [") .append(e) .append( "]\nPlease restart the timetabler and send the logs to your system administrator") .append(" if this occurs again."); Log.error(e); throw new LambdaBreakException(); } catch (DataConnectionException e) { DataExceptionHandler.handleJavaFx(e, null, true); throw new LambdaBreakException(); } }); }); } catch (LambdaBreakException e) { if (failedLog.length() > 0) { updateMessage(failedLog.toString()); } return null; } updateMessage("Done"); return null; }