Abstracted team object.

This commit is contained in:
Andrew Lalis 2018-08-18 17:48:42 +02:00
parent b7a89c0946
commit 54498a4955
10 changed files with 258 additions and 130 deletions

View File

@ -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;

View File

@ -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<Student> students = team.getStudents();
Student[] students = team.getStudents();
StringBuilder description = new StringBuilder("Group ");
description.append(team.getId()).append(": ");

View File

@ -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);
}

View File

@ -39,9 +39,9 @@ public class Student extends Person {
public StudentTeam getPreferredTeam(Map<Integer, Student> 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;
}
}

View File

@ -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<Student> 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<Student> students) {
this.students = students;
}
public List<Student> 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<Integer> 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;
}
}
}

View File

@ -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<Person> 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();
}
}

View File

@ -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,20 +53,15 @@ 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) {
List<PreparedStatement> statements = Utils.prepareStatementsFromFile("/sql/table_init.sql", this.connection);
for (PreparedStatement statement : statements) {
try {
PreparedStatement statement = this.connection.prepareStatement(command);
statement.execute();
} catch (SQLException e) {
logger.severe("SQLException: " + e.getErrorCode());
logger.severe("SQLException while executing prepared statement: " + statement.toString() + ". Code: " + e.getErrorCode());
return false;
}
}
}
logger.fine("Database initialized.");
return true;
}

View File

@ -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<PreparedStatement> prepareStatementsFromFile(String filename, Connection connection) {
String string = FileUtils.readStringFromFile(filename);
if (string == null || string.isEmpty()) {
return new ArrayList<>();
}
String[] splits = string.split(";");
List<PreparedStatement> 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;
}
}

View File

@ -80,15 +80,15 @@ public class TeamGenerator {
// For each student, try to make a team from its preferred partners.
for (Map.Entry<Integer, Student> 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);