Added hibernate support on the most basic level. Not yet implemented in production code.
This commit is contained in:
parent
4a4628e6e6
commit
6e9ebcad74
19
pom.xml
19
pom.xml
|
@ -54,11 +54,22 @@
|
|||
<artifactId>github-api</artifactId>
|
||||
<version>1.93</version>
|
||||
</dependency>
|
||||
<!-- SQLite JDBC Driver -->
|
||||
<!-- MySQL JDBC Driver -->
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.23.1</version>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.12</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.4.197</version>
|
||||
</dependency>
|
||||
<!-- Hibernate Database ORM -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>5.3.6.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
package nl.andrewlalis;
|
||||
|
||||
import nl.andrewlalis.model.Student;
|
||||
import nl.andrewlalis.model.database.DbUtil;
|
||||
import nl.andrewlalis.ui.control.command.CommandExecutor;
|
||||
import nl.andrewlalis.ui.control.command.executables.*;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
import nl.andrewlalis.util.CommandLine;
|
||||
import nl.andrewlalis.util.Logging;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -46,6 +50,13 @@ public class Main {
|
|||
logger.info("GithubManager for Github Repositories in Educational Organizations.\n" +
|
||||
"© Andrew Lalis (2018), All rights reserved.\n" +
|
||||
"Program initialized.");
|
||||
|
||||
SessionFactory factory = DbUtil.getSessionFactory();
|
||||
Session session = factory.openSession();
|
||||
session.beginTransaction();
|
||||
System.out.println(session.save(new Student(1, "a", "a@e.com", "git", null)));
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ public class GithubManager {
|
|||
GHRepository repo = this.createRepository(team.generateUniqueName(prefix), taTeam.getGithubTeam(), team.generateRepoDescription(), false, true, true);
|
||||
|
||||
if (repo == null) {
|
||||
logger.severe("Repository for student team " + team.getId() + " could not be created.");
|
||||
logger.severe("Repository for student team " + team.getNumber() + " could not be created.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ public class GithubManager {
|
|||
*/
|
||||
private void inviteStudentsToRepos(StudentTeam team, GHRepository assignmentsRepo) {
|
||||
try {
|
||||
logger.finest("Adding students from team: " + team.getId() + " as collaborators.");
|
||||
logger.finest("Adding students from team: " + team.getNumber() + " as collaborators.");
|
||||
for (Student student : team.getStudents()) {
|
||||
GHUser user = this.github.getUser(student.getGithubUsername());
|
||||
|
||||
|
|
|
@ -1,31 +1,53 @@
|
|||
package nl.andrewlalis.model;
|
||||
|
||||
import nl.andrewlalis.model.database.BaseEntity;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
@Entity(name = "Person")
|
||||
@Table(name = "persons")
|
||||
public abstract class Person extends BaseEntity {
|
||||
|
||||
/**
|
||||
* The unique identification number for this person. (P- or S-Number)
|
||||
*/
|
||||
@Column(name="number")
|
||||
protected int number;
|
||||
|
||||
/**
|
||||
* The person's first and last name.
|
||||
*/
|
||||
@Column(name="name")
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* The person's email address.
|
||||
*/
|
||||
@Column(name="email_address")
|
||||
protected String emailAddress;
|
||||
|
||||
/**
|
||||
* The person's github username.
|
||||
*/
|
||||
@Column(name="github_username")
|
||||
protected String githubUsername;
|
||||
|
||||
/**
|
||||
* Constructs an empty default Person.
|
||||
*/
|
||||
public Person() {
|
||||
this.number = -1;
|
||||
this.name = null;
|
||||
this.emailAddress = null;
|
||||
this.githubUsername = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Person from only a github username, which is, in some cases, enough to perform a lot of actions.
|
||||
* @param githubUsername The person's github username.
|
||||
|
@ -58,18 +80,34 @@ public abstract class Person {
|
|||
return this.number;
|
||||
}
|
||||
|
||||
public void setNumber(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmailAddress(){
|
||||
return this.emailAddress;
|
||||
}
|
||||
|
||||
public void setEmailAddress(String emailAddress) {
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
public String getGithubUsername(){
|
||||
return this.githubUsername;
|
||||
}
|
||||
|
||||
public void setGithubUsername(String githubUsername) {
|
||||
this.githubUsername = githubUsername;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two persons are the same. This is defined as:
|
||||
* Two persons are equal if at least one of their personal data points is identical. Because each of the data points
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package nl.andrewlalis.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Represents one student's github information.
|
||||
*/
|
||||
@Entity(name = "Student")
|
||||
@Table(name="students")
|
||||
public class Student extends Person {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Student.class.getName());
|
||||
|
@ -17,7 +20,20 @@ public class Student extends Person {
|
|||
/**
|
||||
* A list of partners that the student has said that they would like to be partners with.
|
||||
*/
|
||||
private List<Integer> preferredPartners;
|
||||
@ManyToMany
|
||||
@JoinTable(
|
||||
name = "student_preferred_partners",
|
||||
joinColumns = { @JoinColumn(name = "student_id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "preferred_partner_id")}
|
||||
)
|
||||
private List<Student> preferredPartners;
|
||||
|
||||
/**
|
||||
* Constructs an empty student object.
|
||||
*/
|
||||
public Student() {
|
||||
this.preferredPartners = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a student similarly to a Person, but with an extra preferredPartners list.
|
||||
|
@ -28,24 +44,31 @@ public class Student extends Person {
|
|||
* @param preferredPartners A list of this student's preferred partners, as a list of integers representing the
|
||||
* other students' numbers.
|
||||
*/
|
||||
public Student(int number, String name, String emailAddress, String githubUsername, List<Integer> preferredPartners) {
|
||||
public Student(int number, String name, String emailAddress, String githubUsername, List<Student> preferredPartners) {
|
||||
super(number, name, emailAddress, githubUsername);
|
||||
this.preferredPartners = preferredPartners;
|
||||
}
|
||||
|
||||
public List<Integer> getPreferredPartners() {
|
||||
public List<Student> getPreferredPartners() {
|
||||
return this.preferredPartners;
|
||||
}
|
||||
|
||||
public void setPreferredPartners(List<Student> preferredPartners) {
|
||||
this.preferredPartners = preferredPartners;
|
||||
}
|
||||
|
||||
public void addPreferredPartner(Student student) {
|
||||
this.preferredPartners.add(student);
|
||||
}
|
||||
|
||||
/**
|
||||
* Using a given map of all students, returns a student's preferred team.
|
||||
* @param studentMap A mapping from student number to student for all students who have signed up.
|
||||
* @return A team with unknown id, comprised of this student's preferred partners.
|
||||
* Returns a student's preferred team, including himself.
|
||||
* @return A team with unknown number, comprised of this student's preferred partners.
|
||||
*/
|
||||
public StudentTeam getPreferredTeam(Map<Integer, Student> studentMap) {
|
||||
public StudentTeam getPreferredTeam() {
|
||||
StudentTeam t = new StudentTeam();
|
||||
for (int partnerNumber : this.getPreferredPartners()) {
|
||||
t.addMember(studentMap.get(partnerNumber));
|
||||
for (Student partner : this.getPreferredPartners()) {
|
||||
t.addMember(partner);
|
||||
}
|
||||
t.addMember(this);
|
||||
return t;
|
||||
|
|
|
@ -2,21 +2,29 @@ package nl.andrewlalis.model;
|
|||
|
||||
import org.kohsuke.github.GHRepository;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Represents one or more students' collective information.
|
||||
*/
|
||||
public class StudentTeam extends Team{
|
||||
@Entity(name = "StudentTeam")
|
||||
@Table(name = "student_teams")
|
||||
public class StudentTeam extends Team {
|
||||
|
||||
/**
|
||||
* The repository belonging to this team.
|
||||
*/
|
||||
@Transient
|
||||
private GHRepository repository;
|
||||
|
||||
/**
|
||||
* The TATeam responsible for this student team.
|
||||
*/
|
||||
@ManyToOne
|
||||
private TATeam taTeam;
|
||||
|
||||
public StudentTeam() {
|
||||
|
@ -62,11 +70,11 @@ public class StudentTeam extends Team{
|
|||
* Generates a unique name which is intended to be used for the repository name of this team.
|
||||
* @param prefix A prefix to further reduce the chances of duplicate names.
|
||||
* It is suggested to use something like "2018_OOP"
|
||||
* @return A string comprised of the prefix, team id, and student number of each team member.
|
||||
* @return A string comprised of the prefix, team number, and student number of each team member.
|
||||
*/
|
||||
public String generateUniqueName(String prefix) {
|
||||
StringBuilder sb = new StringBuilder(prefix);
|
||||
sb.append("_team_").append(this.id);
|
||||
sb.append("_team_").append(this.number);
|
||||
for (Student s : this.getStudents()) {
|
||||
sb.append('_').append(s.getNumber());
|
||||
}
|
||||
|
@ -79,7 +87,7 @@ public class StudentTeam extends Team{
|
|||
*/
|
||||
public String generateRepoDescription() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Group ").append(this.id).append(": ");
|
||||
sb.append("Group ").append(this.number).append(": ");
|
||||
for (int i = 0; i < this.memberCount(); i++) {
|
||||
sb.append(this.getStudents()[i].getName());
|
||||
if (i != this.memberCount()-1) {
|
||||
|
|
|
@ -2,14 +2,19 @@ package nl.andrewlalis.model;
|
|||
|
||||
import org.kohsuke.github.GHTeam;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a teaching assistant team, which is itself a 'team' in the organization. This class is used for parsing
|
||||
* json from requests to github to get a list of all teams in the organization.
|
||||
* Represents a teaching assistant team, which is itself a 'team' in the organization.
|
||||
*/
|
||||
@Entity(name = "TATeam")
|
||||
@Table(name = "ta_teams")
|
||||
public class TATeam extends Team {
|
||||
|
||||
/**
|
||||
|
@ -20,11 +25,13 @@ public class TATeam extends Team {
|
|||
/**
|
||||
* The Github team associated with this team.
|
||||
*/
|
||||
@Transient
|
||||
private GHTeam githubTeam;
|
||||
|
||||
/**
|
||||
* A list of all student teams for which this TA team is responsible.
|
||||
*/
|
||||
@OneToMany
|
||||
private List<StudentTeam> studentTeams;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package nl.andrewlalis.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
/**
|
||||
* Represents an administrator in the organization, who manages student teams.
|
||||
*/
|
||||
@Entity(name = "TeachingAssistant")
|
||||
@Table(name = "teaching_assistants")
|
||||
public class TeachingAssistant extends Person {
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package nl.andrewlalis.model;
|
||||
|
||||
import nl.andrewlalis.model.database.BaseEntity;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -8,39 +11,48 @@ import java.util.List;
|
|||
* An abstract Team object from which both Teaching Assistant and Student teams can be built. A Team consists of a list
|
||||
* of members, and a unique identification number.
|
||||
*/
|
||||
public abstract class Team {
|
||||
@Entity(name = "Team")
|
||||
@Table(name = "teams")
|
||||
public abstract class Team extends BaseEntity {
|
||||
|
||||
/**
|
||||
* An identification number unique to this team alone.
|
||||
*/
|
||||
protected int id;
|
||||
@Column(name = "number")
|
||||
protected int number;
|
||||
|
||||
/**
|
||||
* A list of members of this team.
|
||||
*/
|
||||
@OneToMany
|
||||
@JoinTable(
|
||||
name = "team_members",
|
||||
joinColumns = {@JoinColumn(name = "team_id")},
|
||||
inverseJoinColumns = {@JoinColumn(name = "person_id")}
|
||||
)
|
||||
private List<Person> members;
|
||||
|
||||
/**
|
||||
* Constructs this team with the given id.
|
||||
* @param id The id to assign to this team.
|
||||
* Constructs this team with the given number.
|
||||
* @param number The number to assign to this team.
|
||||
*/
|
||||
public Team(int id) {
|
||||
this.id = id;
|
||||
public Team(int number) {
|
||||
this.number = number;
|
||||
this.members = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param newId The new id number to assign to this team.
|
||||
* @param newId The new number number to assign to this team.
|
||||
*/
|
||||
public void setId(int newId) {
|
||||
this.id = newId;
|
||||
public void setNumber(int newId) {
|
||||
this.number = newId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return This team's id number.
|
||||
* @return This team's number number.
|
||||
*/
|
||||
public int getId() {
|
||||
return this.id;
|
||||
public int getNumber() {
|
||||
return this.number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +135,7 @@ public abstract class Team {
|
|||
|
||||
/**
|
||||
* 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 number 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.
|
||||
|
@ -132,7 +144,7 @@ public abstract class Team {
|
|||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Team) {
|
||||
Team team = (Team) obj;
|
||||
return team.getId() == this.getId() && this.hasSameMembers(team);
|
||||
return team.getNumber() == this.getNumber() && this.hasSameMembers(team);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -143,7 +155,7 @@ public abstract class Team {
|
|||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Team of ").append(this.memberCount()).append(" members:\tID: ").append(this.id).append('\n');
|
||||
sb.append("Team of ").append(this.memberCount()).append(" members:\tID: ").append(this.number).append('\n');
|
||||
for (Person person : this.members) {
|
||||
sb.append(person.toString()).append('\n');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package nl.andrewlalis.model.database;
|
||||
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Defines a base entity which all others in the database extend from.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class BaseEntity {
|
||||
|
||||
/**
|
||||
* The number for this entity.
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
|
@ -1,266 +0,0 @@
|
|||
package nl.andrewlalis.model.database;
|
||||
|
||||
import nl.andrewlalis.model.*;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class abstracts many of the functions needed for interaction with the application's SQLite database.
|
||||
*/
|
||||
public class Database {
|
||||
|
||||
private static final int PERSON_TYPE_STUDENT = 0;
|
||||
private static final int PERSON_TYPE_TA = 1;
|
||||
|
||||
private static final int TEAM_TYPE_STUDENT = 0;
|
||||
private static final int TEAM_TYPE_TA = 1;
|
||||
private static final int TEAM_TYPE_TA_ALL = 2;
|
||||
|
||||
private static final int TEAM_NONE = 1000000;
|
||||
private static final int TEAM_TA_ALL = 1000001;
|
||||
|
||||
private static final int ERROR_TYPE_TEAM = 0;
|
||||
private static final int ERROR_TYPE_PERSON = 1;
|
||||
private static final int ERROR_TYPE_SYSTEM = 2;
|
||||
|
||||
/**
|
||||
* The connection needed for all queries.
|
||||
*/
|
||||
private Connection connection;
|
||||
|
||||
/**
|
||||
* The logger for outputting debug info.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(Database.class.getName());
|
||||
static {
|
||||
logger.setParent(Logger.getGlobal());
|
||||
}
|
||||
|
||||
public Database(String databaseFilename) {
|
||||
try {
|
||||
this.connection = DriverManager.getConnection("jdbc:sqlite:" + databaseFilename);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the database from the table_init.sql script, which defines the table schema.
|
||||
* Then, inserts some constant starter data from /sql/insert/types.sql.
|
||||
* @return True if successful, false if not.
|
||||
*/
|
||||
public boolean initialize() {
|
||||
List<PreparedStatement> tableStatements = Utils.prepareStatementsFromFile("/sql/table_init.sql", this.connection);
|
||||
for (PreparedStatement statement : tableStatements) {
|
||||
try {
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQLException while executing prepared statement:\n" + statement.toString() + "\nCode: " + e.getErrorCode());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
logger.fine("Database tables initialized.");
|
||||
List<PreparedStatement> insertStatements = Utils.prepareStatementsFromFile("/sql/insert/types.sql", this.connection);
|
||||
for (PreparedStatement statement : insertStatements) {
|
||||
try {
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQLException while inserting into table:\n" + statement.toString() + "\nCode: " + e.getErrorCode());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
logger.fine("Initial types inserted.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a person in the database.
|
||||
* @param person The person object to store.
|
||||
* @param personType The type of person to store, using a constant defined above.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
public boolean insertPerson(Person person, int personType) {
|
||||
try {
|
||||
logger.finest("Storing person: " + person);
|
||||
String sql = "INSERT INTO persons (id, name, email_address, github_username, person_type_id) VALUES (?, ?, ?, ?, ?);";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, person.getNumber());
|
||||
stmt.setString(2, person.getName());
|
||||
stmt.setString(3, person.getEmailAddress());
|
||||
stmt.setString(4, person.getGithubUsername());
|
||||
stmt.setInt(5, personType);
|
||||
return stmt.execute();
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQLException while inserting Person: " + person + '\n' + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a student in the database.
|
||||
* @param student The student to store.
|
||||
* @return True if the operation was successful, false otherwise.
|
||||
*/
|
||||
public boolean insertStudent(Student student) {
|
||||
logger.finest("Storing student: " + student);
|
||||
if (!insertPerson(student, PERSON_TYPE_STUDENT)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String sql = "INSERT INTO students (person_id, chose_partner) VALUES (?, ?);";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, student.getNumber());
|
||||
stmt.setInt(2, student.getPreferredPartners().size() > 0 ? 1 : 0);
|
||||
if (!stmt.execute()) {
|
||||
return false;
|
||||
}
|
||||
// Storing partners.
|
||||
String sqlPartner = "INSERT INTO student_preferred_partners (student_id, partner_id) VALUES (?, ?);";
|
||||
PreparedStatement stmtPartner = this.connection.prepareStatement(sqlPartner);
|
||||
for (int partnerId : student.getPreferredPartners()) {
|
||||
stmtPartner.setInt(1, student.getNumber());
|
||||
stmtPartner.setInt(2, partnerId);
|
||||
stmtPartner.execute();
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQL Exception while inserting Student into database.\n" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a teaching assistant in the database.
|
||||
* @param ta The teaching assistant to store.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
public boolean insertTeachingAssistant(TeachingAssistant ta) {
|
||||
if (!insertPerson(ta, PERSON_TYPE_TA)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String sql = "INSERT INTO teaching_assistants (person_id) VALUES (?);";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, ta.getNumber());
|
||||
stmt.execute();
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQL Exception while inserting TeachingAssistant.\n" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a team in the database, and any persons who do not yet exist.
|
||||
* @param team The team to store.
|
||||
* @param type The type of team that this is.
|
||||
* @param personType The type of people that this team is made of.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
public boolean insertTeam(Team team, int type, int personType) {
|
||||
try {
|
||||
String sql = "INSERT INTO teams (id, team_type_id) VALUES (?, ?);";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, team.getId());
|
||||
stmt.setInt(2, type);
|
||||
if (stmt.execute()) {
|
||||
for (Person p : team.getMembers()) {
|
||||
this.insertPerson(p, personType);
|
||||
String sqlMembers = "INSERT INTO team_members (team_id, person_id) VALUES (?, ?);";
|
||||
PreparedStatement stmtMembers = this.connection.prepareStatement(sqlMembers);
|
||||
stmtMembers.setInt(1, team.getId());
|
||||
stmtMembers.setInt(2, p.getNumber());
|
||||
stmtMembers.execute();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQLException while inserting team: " + team + '\n' + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a student team in the database.
|
||||
* @param team The team to store.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
public boolean insertStudentTeam(StudentTeam team) {
|
||||
if (!this.insertTeam(team, TEAM_TYPE_STUDENT, PERSON_TYPE_STUDENT)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String sql = "INSERT INTO student_teams (team_id, repository_name, teaching_assistant_team_id) VALUES (?, ?, ?);";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, team.getId());
|
||||
stmt.setString(2, (team.getRepository() == null) ? null : team.getRepository().getName());
|
||||
stmt.setInt(3, (team.getTaTeam() == null) ? TEAM_NONE : team.getTaTeam().getId());
|
||||
return stmt.execute();
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQLException while inserting student team: " + team + '\n' + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a list of student teams in the database.
|
||||
* @param teams The list of teams to store.
|
||||
* @return True if successful, or false if an error occurred.
|
||||
*/
|
||||
public boolean storeStudentTeams(List<StudentTeam> teams) {
|
||||
for (StudentTeam team : teams) {
|
||||
this.insertStudentTeam(team);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of preferred partners that each student has set.
|
||||
* @param studentId The student id to search by.
|
||||
* @return A list of student id's for all students that the given student wishes to be their partner.
|
||||
*/
|
||||
private List<Integer> retrievePreferredPartners(int studentId) {
|
||||
try {
|
||||
logger.finest("Retrieving preferred partners of student: " + studentId);
|
||||
String sql = "SELECT partner_id FROM student_preferred_partners WHERE student_id=?;";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, studentId);
|
||||
ResultSet results = stmt.executeQuery();
|
||||
List<Integer> partners = new ArrayList<>();
|
||||
while (results.next()) {
|
||||
partners.add(results.getInt(1));
|
||||
}
|
||||
return partners;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQL Exception while retrieving preferred partners of student: " + studentId + '\n' + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a student by their id.
|
||||
* @param id The id of the student (student number)
|
||||
* @return The student corresponding to this number, or null if it could not be found.
|
||||
*/
|
||||
public Student retrieveStudent(int id) {
|
||||
try {
|
||||
String sql = "SELECT * FROM persons WHERE id=?";
|
||||
PreparedStatement stmt = this.connection.prepareStatement(sql);
|
||||
stmt.setInt(1, id);
|
||||
ResultSet result = stmt.executeQuery();
|
||||
return new Student(id, result.getString("name"), result.getString("email_address"), result.getString("github_username"), this.retrievePreferredPartners(id));
|
||||
} catch (SQLException e) {
|
||||
logger.severe("SQL Exception while retrieving Student.\n" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package nl.andrewlalis.model.database;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.boot.MetadataSources;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||
|
||||
/**
|
||||
* A utility class for easier interaction with the Hibernate database.
|
||||
*/
|
||||
public class DbUtil {
|
||||
|
||||
private static SessionFactory sessionFactory;
|
||||
|
||||
/**
|
||||
* Set up the session factory based on hibernate.cfg.xml.
|
||||
*/
|
||||
private static void setUp() {
|
||||
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
|
||||
.configure()
|
||||
.build();
|
||||
try {
|
||||
sessionFactory = new MetadataSources(registry)
|
||||
.buildMetadata()
|
||||
.buildSessionFactory();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
StandardServiceRegistryBuilder.destroy(registry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the session factory when it's no longer needed.
|
||||
*/
|
||||
public static void tearDown() {
|
||||
if (sessionFactory != null) {
|
||||
sessionFactory.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the session factory so that sessions can be made.
|
||||
* @return The session factory.
|
||||
*/
|
||||
public static SessionFactory getSessionFactory() {
|
||||
if (sessionFactory == null) {
|
||||
setUp();
|
||||
}
|
||||
return sessionFactory;
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
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() + '\n' + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return statements;
|
||||
}
|
||||
|
||||
}
|
|
@ -2,9 +2,6 @@ package nl.andrewlalis.util;
|
|||
|
||||
import nl.andrewlalis.model.Student;
|
||||
import nl.andrewlalis.model.StudentTeam;
|
||||
import nl.andrewlalis.model.error.Error;
|
||||
import nl.andrewlalis.model.error.Severity;
|
||||
import nl.andrewlalis.ui.view.InitializerApp;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
|
||||
|
@ -45,9 +42,9 @@ public class TeamGenerator {
|
|||
Iterable<CSVRecord> records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(new FileReader(filename));
|
||||
|
||||
logger.fine("Reading all records into map.");
|
||||
Map<Integer, Student> studentMap;
|
||||
List<Student> students;
|
||||
try {
|
||||
studentMap = readAllStudents(records, teamSize);
|
||||
students = readAllStudents(records, teamSize);
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
logger.severe("StudentTeam size does not match column count in records.");
|
||||
throw new IllegalArgumentException("StudentTeam size does not match column count in records.");
|
||||
|
@ -55,7 +52,7 @@ public class TeamGenerator {
|
|||
|
||||
|
||||
logger.fine("Generating all valid teams from student map.");
|
||||
return generateAllValidTeams(studentMap, teamSize);
|
||||
return generateAllValidTeams(students, teamSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,21 +68,23 @@ public class TeamGenerator {
|
|||
* After all students with preferred partners are placed in teams, the single students are merged, and their teams
|
||||
* are added afterwards.
|
||||
*
|
||||
* @param studentMap A mapping for each student to their student number.
|
||||
* @param students A list of students, each with a list of preferred partners.
|
||||
* @param teamSize The preferred maximum size for a team.
|
||||
* @return A list of teams, most of which are of teamSize size.
|
||||
*/
|
||||
private static List<StudentTeam> generateAllValidTeams(Map<Integer, Student> studentMap, int teamSize) {
|
||||
List<Student> singleStudents = new ArrayList<>(studentMap.values());
|
||||
private static List<StudentTeam> generateAllValidTeams(List<Student> students, int teamSize) {
|
||||
List<Student> singleStudents = new ArrayList<>(students);
|
||||
List<StudentTeam> studentTeams = new ArrayList<>();
|
||||
|
||||
// An integer which increments for each valid team. Used to create identifiers for each team.
|
||||
int teamCount = 1;
|
||||
|
||||
// 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);
|
||||
for (Student student : students) {
|
||||
StudentTeam newTeam = student.getPreferredTeam();
|
||||
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.
|
||||
// Note that at this stage, singles are treated as student teams of 1, and thus not valid for any team size > 1.
|
||||
if (newTeam.isValid(teamSize)) {
|
||||
// We know that the team is valid on its own, so now we check if it has members identical to any team already created.
|
||||
boolean matchFound = false;
|
||||
|
@ -97,7 +96,7 @@ public class TeamGenerator {
|
|||
}
|
||||
if (!matchFound) {
|
||||
// Once we know this team is completely valid, we remove all the students in it from the list of singles.
|
||||
newTeam.setId(teamCount++);
|
||||
newTeam.setNumber(teamCount++);
|
||||
singleStudents.removeAll(Arrays.asList(newTeam.getStudents()));
|
||||
studentTeams.add(newTeam);
|
||||
logger.fine("Created team:\n" + newTeam);
|
||||
|
@ -114,14 +113,14 @@ public class TeamGenerator {
|
|||
* size as possible.
|
||||
* @param singleStudents A list of students who have no preferred partners.
|
||||
* @param teamSize The preferred team size.
|
||||
* @param teamIndex The current number used in assigning an id to the team.
|
||||
* @param teamIndex The current number used in assigning an number to the team.
|
||||
* @return A list of teams comprising of single students.
|
||||
*/
|
||||
private static List<StudentTeam> mergeSingleStudents(List<Student> singleStudents, int teamSize, int teamIndex) {
|
||||
List<StudentTeam> studentTeams = new ArrayList<>();
|
||||
while (!singleStudents.isEmpty()) {
|
||||
StudentTeam t = new StudentTeam();
|
||||
t.setId(teamIndex++);
|
||||
t.setNumber(teamIndex++);
|
||||
logger.fine("Creating new team of single students:\n" + t);
|
||||
while (t.memberCount() < teamSize && !singleStudents.isEmpty()) {
|
||||
Student s = singleStudents.remove(0);
|
||||
|
@ -141,8 +140,10 @@ public class TeamGenerator {
|
|||
* @return A map of all students in the file.
|
||||
* @throws ArrayIndexOutOfBoundsException if the teamSize does not work with the columns in the record.
|
||||
*/
|
||||
private static Map<Integer, Student> readAllStudents(Iterable<CSVRecord> records, int teamSize) throws ArrayIndexOutOfBoundsException {
|
||||
private static List<Student> readAllStudents(Iterable<CSVRecord> records, int teamSize) throws ArrayIndexOutOfBoundsException {
|
||||
Map<Integer, Student> studentMap = new HashMap<>();
|
||||
Map<Student, List<Integer>> studentPreferredIds = new HashMap<>();
|
||||
// Perform the initial read of the students.
|
||||
for (CSVRecord record : records) {
|
||||
logger.finest("Read record: " + record);
|
||||
List<Integer> preferredIds = new ArrayList<>();
|
||||
|
@ -152,21 +153,38 @@ public class TeamGenerator {
|
|||
preferredIds.add(Integer.parseInt(record.get(columnOffset + i)));
|
||||
}
|
||||
}
|
||||
Student s = new Student(Integer.parseInt(record.get(3)), record.get(2), record.get(1), record.get(4), preferredIds);
|
||||
Student s = new Student();
|
||||
s.setNumber(Integer.parseInt(record.get(3)));
|
||||
s.setName(record.get(2));
|
||||
s.setEmailAddress(record.get(1));
|
||||
s.setGithubUsername(record.get(4));
|
||||
if (studentMap.containsValue(s)) {
|
||||
logger.warning("Duplicate entry found for student: " + s + "\nOverwriting previous value.");
|
||||
}
|
||||
studentMap.put(s.getNumber(), s);
|
||||
studentPreferredIds.put(s, preferredIds);
|
||||
}
|
||||
|
||||
// Perform a safety check to ensure all preferred partners are valid students.
|
||||
for (Map.Entry<Integer, Student> entry : studentMap.entrySet()) {
|
||||
// Remove any ids that don't exist in the whole list of students.
|
||||
entry.getValue().getPreferredPartners().removeIf(partnerId -> !studentMap.containsKey(partnerId));
|
||||
// The final list of students, with preferred partners set.
|
||||
List<Student> students = new ArrayList<>();
|
||||
|
||||
// Assign students to their preferred students.
|
||||
for (Map.Entry<Student, List<Integer>> entry : studentPreferredIds.entrySet()) {
|
||||
Student s = entry.getKey();
|
||||
for (int partnerNumber : entry.getValue()) {
|
||||
// Check that this preferred partner number exists.
|
||||
if (studentMap.containsKey(partnerNumber)) {
|
||||
s.addPreferredPartner(studentMap.get(partnerNumber));
|
||||
} else {
|
||||
logger.warning("Student " + s + " has invalid preferred partner.");
|
||||
}
|
||||
}
|
||||
students.add(s);
|
||||
}
|
||||
|
||||
// At this point, all students are valid, and all preferred partners are valid.
|
||||
logger.fine("Read " + studentMap.size() + " students from records.");
|
||||
return studentMap;
|
||||
logger.fine("Read " + students.size() + " students from records.");
|
||||
return students;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE hibernate-configuration PUBLIC
|
||||
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
|
||||
<hibernate-configuration>
|
||||
<session-factory>
|
||||
<!-- Database connection settings -->
|
||||
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
|
||||
<property name="hibernate.connection.url">jdbc:h2:./initializer.h2</property>
|
||||
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
|
||||
<property name="hibernate.connection.username">root</property>
|
||||
<property name="hibernate.connection.password">root</property>
|
||||
|
||||
<!-- JDBC connection pool -->
|
||||
<property name="connection.pool_size">1</property>
|
||||
|
||||
<!-- Debugging to show sql queries. -->
|
||||
<property name="show_sql">false</property>
|
||||
|
||||
<!-- Set Hibernate to create tables beforehand. -->
|
||||
<property name="hibernate.hbm2ddl.auto">create-drop</property>
|
||||
|
||||
<!-- Mapping -->
|
||||
<mapping class="nl.andrewlalis.model.Team"/>
|
||||
<mapping class="nl.andrewlalis.model.Student"/>
|
||||
<mapping class="nl.andrewlalis.model.StudentTeam"/>
|
||||
<mapping class="nl.andrewlalis.model.TeachingAssistant"/>
|
||||
<mapping class="nl.andrewlalis.model.TATeam"/>
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
Loading…
Reference in New Issue