diff --git a/src/main/java/sba/sms/models/Course.java b/src/main/java/sba/sms/models/Course.java index be91a50..bdcb30e 100644 --- a/src/main/java/sba/sms/models/Course.java +++ b/src/main/java/sba/sms/models/Course.java @@ -2,19 +2,119 @@ import jakarta.persistence.*; import lombok.*; -import lombok.experimental.FieldDefaults; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * Course is a POJO, configured as a persistent class that represents (or maps to) a table * name 'course' in the database. A Course object contains fields that represent course - * information and a mapping of 'courses' that indicate an inverse or referencing side + * information and a mapping of that indicate an inverse or referencing side * of the relationship. Implement Lombok annotations to eliminate boilerplate code. */ +@Entity + public class Course { -} + // Getter Setter methods + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private int id; + + @Column(name = "name", length = 50, nullable = false) + private String name; + + + @Column(name = "instructor", length = 50, nullable = false) + private String instructor; + + @ManyToMany(mappedBy = "courses", fetch = FetchType.EAGER, cascade = {CascadeType.DETACH, CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) + private Set students = new HashSet<>(); + + public Course(){ + + } + + + public Course(int id, String name, String instructor, Set students){ + this.id = id; + this.name = name; + this.instructor = instructor; + this.students = students; + } + + // Required-args constructor + public Course(String name, String instructor){ + this.name = name; + this.instructor = instructor; + } + + public int getId(){ + return id; + } + + public void setId(int id){ + this.id = id; + } + + public String getName(){ + return name; + } + + public void setName(String name){ + this.name = name; + } + + public String getInstructor(){ + return instructor; + } + + public void setInstructor(String instructor){ + this.instructor = instructor; + } + + public Set getStudents(){ + return students; + } + + public void setStudents(Set students){ + this.students = students; + } + + // toString method + @Override + public String toString(){ + return "Course{" + + "id=" + id + + ", name='" + name + '\'' + + ", instructor='" + instructor + '\'' + + '}'; + + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Course course = (Course) o; + return id == course.id && Objects.equals(name, course.name) && Objects.equals(instructor, course.instructor) && Objects.equals(students, course.students); + } + + + // hash code method + @Override + public int hashCode(){ + return Objects.hash(id, name ,instructor); + } + + //Helper method + public boolean hasStudent(Student student){ + return this.students.contains(student); + } + + + +} \ No newline at end of file diff --git a/src/main/java/sba/sms/models/Student.java b/src/main/java/sba/sms/models/Student.java index db769c3..634a426 100644 --- a/src/main/java/sba/sms/models/Student.java +++ b/src/main/java/sba/sms/models/Student.java @@ -2,9 +2,8 @@ import jakarta.persistence.*; import lombok.*; -import lombok.experimental.FieldDefaults; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -13,14 +12,111 @@ * Student is a POJO, configured as a persistent class that represents (or maps to) a table * name 'student' in the database. A Student object contains fields that represent student * login credentials and a join table containing a registered student's email and course(s) - * data. The Student class can be viewed as the owner of the bi-directional relationship. + * data. The Student class can be viewed as the owner of the relationship. * Implement Lombok annotations to eliminate boilerplate code. */ +@NoArgsConstructor + + +@Table (name = "student") +@Entity public class Student { + // Getter Setters + @Id + @Column(name = "email", length = 50, nullable = false) + private String email; + + @Column(name = "name", length = 50, nullable = false) + private String name; + + @Column(name = "password", length = 50, nullable = false) + private String password; + + @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH, CascadeType.REMOVE, CascadeType.MERGE, CascadeType.PERSIST}) + @JoinTable( + name = "student_courses", + joinColumns = @JoinColumn(name = "student_email"), + inverseJoinColumns = @JoinColumn(name = "course_id") + ) + private Set courses = new HashSet<>(); + // + public Student(String email, String name, String password, Set courses){ + this.email = email; + this.name = name; + this.password = password; + this.courses = courses; + } + + public Student(String email, String name, String password) { + this.email = email; + this.name = name; + this.password = password; + } + + public String getEmail(){ + return email; + } + + public void setEmail(String email){ + this.email = email; + } + + public String getName(){ + return name; + } + + public void setName(String name){ + this.name = name; + } + + public String getPassword(){ + return password; + } + + public void setPassword(String password){ + this.password = password; + } + + public Set getCourses(){ + return courses; + } + + public void setCourses(Set courses){ + this.courses = courses; + } + + public static void addCourse(Course courseById) { + + } + + + @Override + public String toString(){ + return "Student{" + + "email='" + email + '\'' + + ", name='" + name + '\'' + + ", password='" + password + '\'' + + '}'; + } + + @Override + public boolean equals(Object o){ + if(this == o) return true; + if(o == null || getClass() != o.getClass()) return false; + Student student = (Student) o; + return Objects.equals(email, student.email) && + Objects.equals(name, student.name) && + Objects.equals(password, student.password); + } + + @Override + public int hashCode(){ + return Objects.hash(email, name, password); } +} \ No newline at end of file diff --git a/src/main/java/sba/sms/services/CourseService.java b/src/main/java/sba/sms/services/CourseService.java index ad01eed..1a14fa3 100644 --- a/src/main/java/sba/sms/services/CourseService.java +++ b/src/main/java/sba/sms/services/CourseService.java @@ -2,12 +2,14 @@ import org.hibernate.HibernateException; import org.hibernate.Session; +import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.query.Query; import sba.sms.dao.CourseI; import sba.sms.models.Course; import sba.sms.utils.HibernateUtil; +import javax.security.auth.login.Configuration; import java.util.ArrayList; import java.util.List; @@ -16,6 +18,62 @@ * CourseI interface, overrides all abstract service methods and * provides implementation for each method. */ -public class CourseService { +public class CourseService implements CourseI{ -} + @Override + public void createCourse(Course course) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + + try{ + tx = s.beginTransaction(); + s.persist(course); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + } finally { + s.close(); + } + } + + @Override + public Course getCourseById(int courseId) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + Course course = new Course(); + + try{ + tx = s.beginTransaction(); + Query q = s.createQuery("from Course where id = :id", Course.class); + q.setParameter("id", courseId); + course = q.getSingleResult(); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + return course; + } + + @Override + public List getAllCourses() { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + List courseList = new ArrayList<>(); + + try{ + tx = s.beginTransaction(); + Query q = s.createQuery("from Course", Course.class); + courseList = q.getResultList(); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + return courseList; + } +} \ No newline at end of file diff --git a/src/main/java/sba/sms/services/StudentService.java b/src/main/java/sba/sms/services/StudentService.java index 3bd2e2a..7d74d96 100644 --- a/src/main/java/sba/sms/services/StudentService.java +++ b/src/main/java/sba/sms/services/StudentService.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.List; + /** * StudentService is a concrete class. This class implements the * StudentI interface, overrides all abstract service methods and @@ -21,6 +22,133 @@ * generate a logger file. */ -public class StudentService { +@Log +public class StudentService implements StudentI { + private static final CourseService courseService = new CourseService(); + + @Override + public List getAllStudents() { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + List studentList = new ArrayList<>(); + + try{ + tx = s.beginTransaction(); + Query q = s.createQuery("from Student", Student.class); + studentList = q.getResultList(); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + return studentList; + } + + @Override + public void createStudent(Student student) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + + try{ + tx = s.beginTransaction(); + s.persist(student); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + exception. + printStackTrace(); + } finally { + s.close(); + } + } + + @Override + public Student getStudentByEmail(String email) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + Student student = null; + try{ + tx = s.beginTransaction(); + Query q = s.createQuery("from Student where email = :email", Student.class); + q.setParameter("email", email); + student = q.getSingleResult(); + tx.commit(); + } catch (Exception exception){ + if(tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + return student; + } + + @Override + public boolean validateStudent(String email, String password) { + if (email == null || email.isEmpty() || password == null || password.isEmpty()) { + return false; + } + + Student s = getStudentByEmail(email); + if (s != null && s.getPassword() != null) { + return s.getPassword().equals(password); + } + return false; + } + + + + + @Override + public void registerStudentToCourse(String email, int courseId) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + + try{ + tx = s.beginTransaction(); + Student student = getStudentByEmail(email); + Course course = courseService.getCourseById(courseId); + if (student != null && course != null) { + student.addCourse(course); // Ensure addCourse is an instance method + s.merge(student); + tx.commit(); + } else { + System.out.println("Student or Course not found."); + } + } catch (HibernateException exception) { + if (tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + } + + @Override + public List getStudentCourses(String email) { + Session s = HibernateUtil.getSessionFactory().openSession(); + Transaction tx = null; + List courseList = new ArrayList<>(); -} + try{ + tx = s.beginTransaction(); + String nativeGetStudentCourses = "SELECT c.id, c.name, c.instructor " + + "FROM course AS c " + + "JOIN student_courses AS sc " + + "ON c.id = sc.course_id " + + "JOIN student AS s " + + "ON s.email = sc.student_email " + + "WHERE s.email = ?"; + NativeQuery studentCourses = s.createNativeQuery(nativeGetStudentCourses, Course.class); + studentCourses.setParameter(1, email); + courseList = studentCourses.getResultList(); + tx.commit(); + } catch (HibernateException exception){ + if(tx != null) tx.rollback(); + exception.printStackTrace(); + } finally { + s.close(); + } + return courseList; + } +} \ No newline at end of file diff --git a/src/main/java/sba/sms/utils/CommandLine.java b/src/main/java/sba/sms/utils/CommandLine.java index 2b9cd57..f78c36e 100644 --- a/src/main/java/sba/sms/utils/CommandLine.java +++ b/src/main/java/sba/sms/utils/CommandLine.java @@ -20,7 +20,6 @@ private CommandLine(){ /** * Creates and persist student object to the 'student' table and * course objects to the 'course' table - * * ATTENTION PLEASE READ * Uncomment the following code after creating both models and entities for ease of adding and dropping dummy data into the database, remember that * in hibernate.cfg.xml hibernate.hbm2ddl.auto = create-drop will create and drop the tables every time the application @@ -29,7 +28,7 @@ private CommandLine(){ * */ public static void addData(){ - /* + StudentService studentService = new StudentService(); CourseService courseService = new CourseService(); @@ -49,6 +48,6 @@ public static void addData(){ courseService.createCourse(new Course("Web Services", "Raheem Abolfathzadeh")); courseService.createCourse(new Course("Microservices", "Eric Heilig")); - */ + } } diff --git a/src/main/java/sba/sms/utils/HibernateUtil.java b/src/main/java/sba/sms/utils/HibernateUtil.java index a54f60b..81fca6c 100644 --- a/src/main/java/sba/sms/utils/HibernateUtil.java +++ b/src/main/java/sba/sms/utils/HibernateUtil.java @@ -1,5 +1,7 @@ package sba.sms.utils; + + import lombok.Getter; import org.hibernate.SessionFactory; import org.hibernate.boot.Metadata; @@ -12,7 +14,7 @@ * secure connection to a database and permits CRUD operations on a table. * The session configuration derives from the hibernate.cfg.xml file in * the 'resources' folder. - * + * WARNING! * DO NOT MODIFY THIS CODE */ @@ -22,16 +24,19 @@ private HibernateUtil() { } /** - * @Getter builds a standard getter method for the object + * Getter builds a standard getter method for the object * sessionFactory. */ + + @Getter private static SessionFactory sessionFactory = buildSessionFactory(); + /** * Method builds a session factory from the 'hibernate.cfg.xml' file * in the 'resources' folder and returns a sessionFactory object. - * @return + * return */ private static SessionFactory buildSessionFactory() { diff --git a/src/main/resources/hibernate.cfg.xml b/src/main/resources/hibernate.cfg.xml index 0d6cb98..5d7b547 100644 --- a/src/main/resources/hibernate.cfg.xml +++ b/src/main/resources/hibernate.cfg.xml @@ -6,8 +6,9 @@ + - create-drop + create-drop com.mysql.cj.jdbc.Driver @@ -15,13 +16,14 @@ jdbc:mysql://localhost:3306/smsdb-ll?createDatabaseIfNotExist=true root - root + password org.hibernate.dialect.MySQLDialect - - + + + diff --git a/src/test/java/sba/sms/services/StudentServiceTest.java b/src/test/java/sba/sms/services/StudentServiceTest.java index ec32ae3..f62cf58 100644 --- a/src/test/java/sba/sms/services/StudentServiceTest.java +++ b/src/test/java/sba/sms/services/StudentServiceTest.java @@ -13,8 +13,16 @@ import static org.assertj.core.api.Assertions.*; - class StudentServiceTest { +@Test + void validateStudent(){} + + @Test + void getStudentCourses(){} + @Test + void registerStudentToCourse(){} + @Test + void getStudentByEmail(){} } \ No newline at end of file