diff --git a/src/main/java/nl/andrewlalis/Main.java b/src/main/java/nl/andrewlalis/Main.java index feb9ace..1c35e17 100644 --- a/src/main/java/nl/andrewlalis/Main.java +++ b/src/main/java/nl/andrewlalis/Main.java @@ -1,11 +1,10 @@ package nl.andrewlalis; -import nl.andrewlalis.database.Database; +import nl.andrewlalis.model.database.Database; import nl.andrewlalis.git_api.GithubManager; import nl.andrewlalis.model.Student; import nl.andrewlalis.model.StudentTeam; import nl.andrewlalis.util.CommandLine; -import nl.andrewlalis.util.FileUtils; import nl.andrewlalis.util.Logging; import nl.andrewlalis.util.TeamGenerator; diff --git a/src/main/java/nl/andrewlalis/git_api/GithubManager.java b/src/main/java/nl/andrewlalis/git_api/GithubManager.java index 101d1f1..d7265a2 100644 --- a/src/main/java/nl/andrewlalis/git_api/GithubManager.java +++ b/src/main/java/nl/andrewlalis/git_api/GithubManager.java @@ -2,6 +2,7 @@ package nl.andrewlalis.git_api; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import jdk.nashorn.internal.ir.annotations.Ignore; import nl.andrewlalis.model.Student; import nl.andrewlalis.model.StudentTeam; import org.apache.http.HttpResponse; @@ -88,7 +89,7 @@ public class GithubManager { StudentTeam t = new StudentTeam(); Student s = new Student(3050831, "Andrew Lalis", "andrewlalisofficial@gmail.com", "andrewlalis", null); - t.addStudent(s); + t.addMember(s); t.setId(42); this.setupStudentTeam(t, teamAll); @@ -99,6 +100,7 @@ public class GithubManager { * @param allTeachingAssistants A team consisting of all teaching assistants. * @throws IOException If an HTTP request failed. */ + @SuppressWarnings("deprecation") private void setupAssignmentsRepo(GHTeam allTeachingAssistants) throws IOException { // Check if the repository already exists. GHRepository existingRepo = this.organization.getRepository(this.assignmentsRepoName); @@ -139,10 +141,11 @@ public class GithubManager { * @param taTeam The team of teaching assistants that is responsible for these students. * @throws IOException If an HTTP request fails. */ + @SuppressWarnings("deprecation") private void setupStudentTeam(StudentTeam team, GHTeam taTeam) throws IOException { String teamRepoName = team.generateUniqueName(this.studentRepoPrefix); - List students = team.getStudents(); + Student[] students = team.getStudents(); StringBuilder description = new StringBuilder("Group "); description.append(team.getId()).append(": "); diff --git a/src/main/java/nl/andrewlalis/model/Person.java b/src/main/java/nl/andrewlalis/model/Person.java index ea12b84..66b0fb7 100644 --- a/src/main/java/nl/andrewlalis/model/Person.java +++ b/src/main/java/nl/andrewlalis/model/Person.java @@ -4,7 +4,7 @@ package nl.andrewlalis.model; * A generic object that students, teaching assistants, and professors can extend from. This covers all the basic * functionality that applies to anyone in the system. */ -public abstract class Person { +public abstract class Person { /** * The unique identification number for this person. (P- or S-Number) diff --git a/src/main/java/nl/andrewlalis/model/Storable.java b/src/main/java/nl/andrewlalis/model/Storable.java new file mode 100644 index 0000000..29a485e --- /dev/null +++ b/src/main/java/nl/andrewlalis/model/Storable.java @@ -0,0 +1,18 @@ +package nl.andrewlalis.model; + +import java.sql.Connection; + +/** + * Defines objects which may be stored in the database, and requires that they implement methods for both storage and + * retrieval of the objects. + */ +public interface Storable { + + /** + * Stores the object in the database. + * @param connection The connection to the database which can be used for preparation of and execution of queries. + * @return True if the object is successfully stored, false if an error occurred. + */ + boolean store(Connection connection); + +} diff --git a/src/main/java/nl/andrewlalis/model/Student.java b/src/main/java/nl/andrewlalis/model/Student.java index 321c4e4..ec8712b 100644 --- a/src/main/java/nl/andrewlalis/model/Student.java +++ b/src/main/java/nl/andrewlalis/model/Student.java @@ -39,9 +39,9 @@ public class Student extends Person { public StudentTeam getPreferredTeam(Map studentMap) { StudentTeam t = new StudentTeam(); for (int partnerNumber : this.getPreferredPartners()) { - t.addStudent(studentMap.get(partnerNumber)); + t.addMember(studentMap.get(partnerNumber)); } - t.addStudent(this); + t.addMember(this); return t; } } diff --git a/src/main/java/nl/andrewlalis/model/StudentTeam.java b/src/main/java/nl/andrewlalis/model/StudentTeam.java index d335c80..4243aa2 100644 --- a/src/main/java/nl/andrewlalis/model/StudentTeam.java +++ b/src/main/java/nl/andrewlalis/model/StudentTeam.java @@ -1,74 +1,22 @@ package nl.andrewlalis.model; -import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * Represents one or more students' collective information. */ -public class StudentTeam { - - /** - * The list of students in this team. - */ - private List students; - - /** - * The team identification number. - */ - private int id; +public class StudentTeam extends Team{ public StudentTeam() { - this.students = new ArrayList<>(); - this.id = -1; + super(-1); } /** - * Determines if a student is already included in this team. - * @param student A student. - * @return True if the student is in this team, false otherwise. + * Gets a list of students, casted from the original Person[]. + * @return An array of Students. */ - public boolean hasStudent(Student student) { - for (Student s : this.students) { - if (s.equals(student)) { - return true; - } - } - return false; - } - - public int getStudentCount() { - return this.students.size(); - } - - public int getId() { - return this.id; - } - - public void setId(int id) { - this.id = id; - } - - public void setStudents(List students) { - this.students = students; - } - - public List getStudents() { - return this.students; - } - - /** - * Adds a student to this team. - * @param student The student to add. - * @return True if the student could be added, false otherwise. - */ - public boolean addStudent(Student student) { - if (!this.hasStudent(student)) { - this.students.add(student); - return true; - } else { - return false; - } + public Student[] getStudents() { + return Arrays.copyOf(this.getMembers(), this.memberCount(), Student[].class); } /** @@ -81,10 +29,9 @@ public class StudentTeam { * @return True if the team is valid, and false otherwise. */ public boolean isValid(int teamSize) { - if (this.getStudentCount() == teamSize) { - List encounteredIds = new ArrayList<>(); - for (Student studentA : this.students) { - for (Student studentB : this.students) { + if (this.memberCount() == teamSize) { + for (Student studentA : this.getStudents()) { + for (Student studentB : this.getStudents()) { if (!studentA.equals(studentB) && !studentA.getPreferredPartners().contains(studentB.getNumber())) { return false; } @@ -105,48 +52,9 @@ public class StudentTeam { public String generateUniqueName(String prefix) { StringBuilder sb = new StringBuilder(prefix); sb.append("_team_").append(this.id); - for (Student s : this.students) { + for (Student s : (Student[]) this.getMembers()) { sb.append('_').append(s.getNumber()); } return sb.toString(); } - - /** - * Returns a pretty formatting of this team so that it can be viewed in the command line. This is mainly for - * debugging purposes. - * @return A string representing the team. - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder("StudentTeam: "); - sb.append(this.id).append('\n'); - for (Student s : this.students) { - sb.append('\t').append(s.toString()).append('\n'); - } - return sb.toString(); - } - - /** - * Determines if one team is equivalent to another. This is determined by if the two teams are comprised of the same - * students, in any order. - * @param o The object to compare to this team. - * @return True if the teams contain the same students, false otherwise. - */ - @Override - public boolean equals(Object o) { - if (o instanceof StudentTeam) { - StudentTeam t = (StudentTeam) o; - if (t.getStudentCount() != this.getStudentCount()) { - return false; - } - for (Student s : this.students) { - if (!t.hasStudent(s)) { - return false; - } - } - return true; - } else { - return false; - } - } } diff --git a/src/main/java/nl/andrewlalis/model/Team.java b/src/main/java/nl/andrewlalis/model/Team.java new file mode 100644 index 0000000..5d5cac4 --- /dev/null +++ b/src/main/java/nl/andrewlalis/model/Team.java @@ -0,0 +1,153 @@ +package nl.andrewlalis.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * An abstract Team object from which both Teaching Assistant and Student teams can be built. + */ +public abstract class Team { + + /** + * An identification number unique to this team alone. + */ + protected int id; + + /** + * A list of members of this team. + */ + private List members; + + /** + * Constructs this team with the given id. + * @param id The id to assign to this team. + */ + public Team(int id) { + this.id = id; + this.members = new ArrayList<>(); + } + + /** + * @param newId The new id number to assign to this team. + */ + public void setId(int newId) { + this.id = newId; + } + + /** + * @return This team's id number. + */ + public int getId() { + return this.id; + } + + /** + * Adds a new person to this team, only if they do not exist in this team yet. + * @param newMember The new member to add. + */ + public void addMember(Person newMember) { + for (Person person : this.members) { + if (person.equals(newMember)) { + return; + } + } + this.members.add(newMember); + } + + /** + * Removes a person from this team. + * @param person The person to remove. + */ + public void removeMember(Person person) { + this.members.remove(person); + } + + /** + * Checks if this team contains the given person. + * @param person The person to check for. + * @return True if the person is a member of this team, false otherwise. + */ + public boolean containsMember(Person person) { + for (Person p : this.members) { + if (p.equals(person)) { + return true; + } + } + return false; + } + + /** + * Sets the team to be comprised of only the members given in the array. + * @param people The people which will make up the members of this team. + */ + public void setMembers(Person[] people) { + this.members = new ArrayList<>(Arrays.asList(people)); + } + + /** + * Gets a list of people in this team. + * @return A list of people in this team. + */ + public Person[] getMembers() { + Person[] people = new Person[this.memberCount()]; + this.members.toArray(people); + return people; + } + + /** + * Gets the number of people in this team. + * @return The number of people in this team. + */ + public int memberCount() { + return this.members.size(); + } + + /** + * Determines if another team has the same members as this team. + * @param team The team to compare to this team. + * @return True if the other team has all the same members as this team. + */ + public boolean hasSameMembers(Team team) { + if (this.memberCount() == team.memberCount()) { + for (Person person : this.members) { + if (!team.containsMember(person)) { + return false; + } + } + return true; + } + return false; + } + + /** + * Checks if an object is equal to this team. First checks if the other object is a Team, and then if it has the + * same id and team size. If both of those conditions are met, then it will check that all team members are the + * same. + * @param obj The object to check for equality. + * @return True if the two objects represent the same team, or false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof Team) { + Team team = (Team) obj; + if (team.getId() == this.getId() && this.hasSameMembers(team)) { + return true; + } + } + return false; + } + + /** + * @return A String containing a line for each member in the team. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (Person person : this.members) { + sb.append(person.toString()).append('\n'); + } + return sb.toString(); + } + +} diff --git a/src/main/java/nl/andrewlalis/database/Database.java b/src/main/java/nl/andrewlalis/model/database/Database.java similarity index 88% rename from src/main/java/nl/andrewlalis/database/Database.java rename to src/main/java/nl/andrewlalis/model/database/Database.java index 14a7f1c..bd74edc 100644 --- a/src/main/java/nl/andrewlalis/database/Database.java +++ b/src/main/java/nl/andrewlalis/model/database/Database.java @@ -1,11 +1,11 @@ -package nl.andrewlalis.database; +package nl.andrewlalis.model.database; import nl.andrewlalis.model.Person; import nl.andrewlalis.model.Student; import nl.andrewlalis.model.TeachingAssistant; -import nl.andrewlalis.util.FileUtils; import java.sql.*; +import java.util.List; import java.util.logging.Logger; /** @@ -53,18 +53,13 @@ public class Database { * @return True, if successful, false if not. */ public boolean initialize() { - String sql = FileUtils.readStringFromFile("/sql/table_init.sql"); - String[] commands = sql.split(";"); - for (String command : commands) { - logger.finest("Executing command: " + command); - if (command.trim().length() > 1) { - try { - PreparedStatement statement = this.connection.prepareStatement(command); - statement.execute(); - } catch (SQLException e) { - logger.severe("SQLException: " + e.getErrorCode()); - return false; - } + List statements = Utils.prepareStatementsFromFile("/sql/table_init.sql", this.connection); + for (PreparedStatement statement : statements) { + try { + statement.execute(); + } catch (SQLException e) { + logger.severe("SQLException while executing prepared statement: " + statement.toString() + ". Code: " + e.getErrorCode()); + return false; } } logger.fine("Database initialized."); diff --git a/src/main/java/nl/andrewlalis/model/database/Utils.java b/src/main/java/nl/andrewlalis/model/database/Utils.java new file mode 100644 index 0000000..2dd006b --- /dev/null +++ b/src/main/java/nl/andrewlalis/model/database/Utils.java @@ -0,0 +1,52 @@ +package nl.andrewlalis.model.database; + +import nl.andrewlalis.util.FileUtils; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * Contains some methods which make database actions much easier. + */ +public class Utils { + + /** + * The logger for outputting debug info. + */ + private static final Logger logger = Logger.getLogger(Utils.class.getName()); + static { + logger.setParent(Logger.getGlobal()); + } + + /** + * Gets an ordered list of prepared statements from a file which contains multiple statements separated by a + * semicolon. This method separates those statements into their own strings, and prepares them individually to be + * executed later. + * @param filename The name of the file which contains the statements. + * @param connection The connection to a database; used to prepare statements. + * @return An ordered list of prepared statements which are based on the contents of the file provided. + */ + public static List prepareStatementsFromFile(String filename, Connection connection) { + String string = FileUtils.readStringFromFile(filename); + if (string == null || string.isEmpty()) { + return new ArrayList<>(); + } + String[] splits = string.split(";"); + List statements = new ArrayList<>(); + for (String split : splits) { + if (split.trim().length() > 1) { + try { + statements.add(connection.prepareStatement(split)); + } catch (SQLException e) { + logger.severe("SQLException while preparing a statement:\n" + split + "\nError Code: " + e.getErrorCode()); + } + } + } + return statements; + } + +} diff --git a/src/main/java/nl/andrewlalis/util/TeamGenerator.java b/src/main/java/nl/andrewlalis/util/TeamGenerator.java index 44cc264..2057b71 100644 --- a/src/main/java/nl/andrewlalis/util/TeamGenerator.java +++ b/src/main/java/nl/andrewlalis/util/TeamGenerator.java @@ -80,15 +80,15 @@ public class TeamGenerator { // For each student, try to make a team from its preferred partners. for (Map.Entry e : studentMap.entrySet()) { StudentTeam newTeam = e.getValue().getPreferredTeam(studentMap); - logger.finest("Checking if student's preferred team is valid: " + newTeam.getStudents()); + logger.finest("Checking if student's preferred team is valid:\n" + newTeam); // Check if the team is of a valid size, and is not a duplicate. // Note that at this stage, singles are treated as studentTeams of 1, and thus not valid for any teamSize > 1. if (newTeam.isValid(teamSize) && !studentTeams.contains(newTeam)) { // Once we know this team is completely valid, we remove all the students in it from the list of singles. newTeam.setId(teamCount++); - singleStudents.removeAll(newTeam.getStudents()); + singleStudents.removeAll(Arrays.asList(newTeam.getStudents())); studentTeams.add(newTeam); - logger.fine("Created team: " + newTeam); + logger.fine("Created team:\n" + newTeam); } } @@ -109,11 +109,11 @@ public class TeamGenerator { while (!singleStudents.isEmpty()) { StudentTeam t = new StudentTeam(); t.setId(teamIndex++); - logger.fine("Creating new team of single students: " + t); - while (t.getStudentCount() < teamSize && !singleStudents.isEmpty()) { + logger.fine("Creating new team of single students:\n" + t); + while (t.memberCount() < teamSize && !singleStudents.isEmpty()) { Student s = singleStudents.remove(0); logger.finest("Single student: " + s); - t.addStudent(s); + t.addMember(s); } studentTeams.add(t); logger.fine("Created team: " + t);