From e3df2923ffba792d90cd41d1109a9186ae69315f Mon Sep 17 00:00:00 2001
From: jez04 <david.jezek@post.cz>
Date: Thu, 17 Apr 2025 02:06:27 +0200
Subject: [PATCH] feat: :tada: solution

---
 pom.xml                                       | 19 ++++-
 src/main/java/lab/Setup.java                  |  2 +
 src/main/java/lab/data/Score.java             | 13 ++++
 src/main/java/lab/storage/JpaConnector.java   | 40 ++++++++--
 src/main/java/module-info.java                |  4 +-
 src/main/resources/META-INF/persistence.xml   | 40 ++++++++++
 .../structure/test/ClassStructureTestHw.java  | 77 +++++++++++++++++++
 7 files changed, 185 insertions(+), 10 deletions(-)
 create mode 100644 src/main/resources/META-INF/persistence.xml
 create mode 100644 src/test/java/jez04/structure/test/ClassStructureTestHw.java

diff --git a/pom.xml b/pom.xml
index ec1d0f0..1d7427f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,10 +3,10 @@
 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>cz.vsb.fei.java2</groupId>
-	<artifactId>java2-lab05-v3</artifactId>
+	<artifactId>java2-lab09-v3</artifactId>
 	<version>0.0.1-SNAPHOST</version>
 	<packaging>jar</packaging>
-	<name>java2-lab05-v3</name>
+	<name>java2-lab09-v3</name>
 	<properties>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<maven.compiler.source>21</maven.compiler.source>
@@ -24,6 +24,21 @@
 		</repository>
 	</repositories>
 	<dependencies>
+
+		<!--
+		https://mvnrepository.com/artifact/jakarta.persistence/jakarta.persistence-api -->
+		<dependency>
+			<groupId>jakarta.persistence</groupId>
+			<artifactId>jakarta.persistence-api</artifactId>
+			<version>3.2.0</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core -->
+		<dependency>
+			<groupId>org.hibernate.orm</groupId>
+			<artifactId>hibernate-core</artifactId>
+			<version>6.6.11.Final</version>
+		</dependency>
+
 		<dependency>
 			<groupId>cz.vsb.fei</groupId>
 			<artifactId>kelvin-java-unittest-support</artifactId>
diff --git a/src/main/java/lab/Setup.java b/src/main/java/lab/Setup.java
index d1f4b9e..84caa5c 100644
--- a/src/main/java/lab/Setup.java
+++ b/src/main/java/lab/Setup.java
@@ -1,5 +1,6 @@
 package lab;
 
+import jakarta.persistence.Entity;
 import lab.storage.DbConnector;
 import lab.storage.ScoreStorageInterface;
 import lombok.AllArgsConstructor;
@@ -7,6 +8,7 @@ import lombok.Builder;
 import lombok.Builder.Default;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.ToString;
 
 @Getter
diff --git a/src/main/java/lab/data/Score.java b/src/main/java/lab/data/Score.java
index 247a9b4..c6219a5 100644
--- a/src/main/java/lab/data/Score.java
+++ b/src/main/java/lab/data/Score.java
@@ -2,16 +2,26 @@ package lab.data;
 
 import java.util.Random;
 
+import jakarta.persistence.Entity;
+import jakarta.persistence.EnumType;
+import jakarta.persistence.Enumerated;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
+import lombok.NoArgsConstructor;
 import lombok.Setter;
 import lombok.ToString;
 
+@Entity
 @Getter
 @Setter
 @AllArgsConstructor
+@NoArgsConstructor
 @EqualsAndHashCode
 @ToString
 @Builder(toBuilder = true)
@@ -19,9 +29,12 @@ public class Score {
 
 	private static final Random RANDOM = new Random();
 	
+	@Id
+	@GeneratedValue(strategy = GenerationType.AUTO)
 	private Long id;
 	private String name;
 	private int points;
+	@Enumerated(EnumType.STRING)
 	private Level level;
 	
 	
diff --git a/src/main/java/lab/storage/JpaConnector.java b/src/main/java/lab/storage/JpaConnector.java
index b1f5bf1..8735854 100644
--- a/src/main/java/lab/storage/JpaConnector.java
+++ b/src/main/java/lab/storage/JpaConnector.java
@@ -1,25 +1,32 @@
 package lab.storage;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.function.Consumer;
 
+import jakarta.persistence.EntityManager;
+import jakarta.persistence.EntityManagerFactory;
+import jakarta.persistence.Persistence;
 import lab.data.Score;
 
 public class JpaConnector implements ScoreStorageInterface {
 
 
+	private EntityManagerFactory entityManagerFactory;
+	private EntityManager entityManager;
+	
 	public JpaConnector() {
+		entityManagerFactory = Persistence.createEntityManagerFactory("java2");
+		entityManager = entityManagerFactory.createEntityManager();
 	}
 
 	@Override
 	public List<Score> getAll() {
-		return Collections.emptyList();
+		return entityManager.createQuery("select s from Score s", Score.class).getResultList();
 	}
 
 	@Override
 	public List<Score> getFirstTen() {
-		return Collections.emptyList();
+		return entityManager.createQuery("select s from Score s order by s.points DESC", Score.class).setMaxResults(10).getResultList();
 	}
 
 	@Override
@@ -28,27 +35,46 @@ public class JpaConnector implements ScoreStorageInterface {
 
 	@Override
 	public Score save(Score score) {
-		return null;
+		Score result;
+		entityManager.getTransaction().begin();
+		if(score.getId() == null || score.getId() == 0) {
+			entityManager.persist(score);
+			result = score;
+		} else {
+			result = entityManager.merge(score);
+		}
+		entityManager.getTransaction().commit();
+		return result;
 	}
 
 	@Override
 	public void delete(List<Score> scores) {
+		entityManager.getTransaction().begin();
+		for (Score score : scores) {
+			entityManager.remove(score);
+		}
+		entityManager.getTransaction().commit();
 	}
 
 	@Override
 	public void stop() {
+		entityManager.close();
+		entityManagerFactory.close();
 	}
 
 	public Object getEntityManager() {
 		//return entity manager. Type Object is there because of compilation of empty task assignment
-		return null;
+		return entityManager;
 	}
 
 	public Score find(long id) {
-		return null;
+		return entityManager.find(Score.class, id);
 	}
 	
 	public void modifyNoPersistOrMerge(long id, Consumer<Score> motificator) {
+		entityManager.getTransaction().begin();
+		Score score = find(id);
+		motificator.accept(score);
+		entityManager.getTransaction().commit();
 	}
-	
 }
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 8f97c19..abec138 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -6,9 +6,11 @@ module lab05_module {
 	requires org.apache.logging.log4j;
 	requires static lombok;
 	requires com.h2database;
+	requires jakarta.persistence;
+	requires org.hibernate.orm.core;
 	
 	opens lab.gui to javafx.fxml;
-	opens lab.data to javafx.base;
+	opens lab.data to javafx.base,org.hibernate.orm.core;
 
 	exports lab.gui to javafx.fxml, javafx.graphics;
 }
diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..3a1bac1
--- /dev/null
+++ b/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="3.0"
+    xmlns="https://jakarta.ee/xml/ns/persistence"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="
+        https://jakarta.ee/xml/ns/persistence
+        https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
+    <persistence-unit name="java2"
+        transaction-type="RESOURCE_LOCAL">
+
+        <!-- If you are running in a production environment, add a managed data 
+            source, this example data source is just for development and testing! -->
+        <properties>
+            <property name="jakarta.persistence.jdbc.url"
+                value="jdbc:h2:file:./db/java2" />
+            <!-- In memory DB no store to disk
+                <property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:java2" />
+            -->
+            <property name="jakarta.persistence.jdbc.driver"
+                value="org.h2.Driver" />
+
+
+            <property name="jakarta.persistence.jdbc.user" value="app" />
+            <property name="jakarta.persistence.jdbc.password"
+                value="app" />
+            <property
+                name="jakarta.persistence.schema-generation.database.action"
+                value="create"></property>
+
+            <!-- Properties for Hibernate -->
+            <property name="hibernate.show_sql" value="false" />
+            <property name="hibernate.format_sql" value="true" />
+            <!--
+                <property name="hibernate.hbm2ddl.auto" value="update" />
+            -->
+
+        </properties>
+    </persistence-unit>
+
+</persistence>
\ No newline at end of file
diff --git a/src/test/java/jez04/structure/test/ClassStructureTestHw.java b/src/test/java/jez04/structure/test/ClassStructureTestHw.java
new file mode 100644
index 0000000..fc22107
--- /dev/null
+++ b/src/test/java/jez04/structure/test/ClassStructureTestHw.java
@@ -0,0 +1,77 @@
+package jez04.structure.test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import cz.vsb.fei.kelvin.unittest.ProjectContains;
+import cz.vsb.fei.kelvin.unittest.StructureHelper;
+import cz.vsb.fei.kelvin.unittest.TextFileContains;
+import cz.vsb.fei.kelvin.unittest.XmlFileContains;
+
+class ClassStructureTestHw {
+
+	StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
+
+	@Test
+	void jakartaAndHibernateAsDependencyTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
+				"/project/dependencies/dependency/artifactId[text() = 'jakarta.persistence-api']"));
+		assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
+				"/project/dependencies/dependency/artifactId[text() = 'hibernate-core']"));
+	}
+
+	@Test
+	void jakartaInModulInfoTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains("module-info.java", "jakarta.persistence;"));
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains("module-info.java", "opens\\s+lab.data;|opens\\s+lab.data\\s+to\\s+javafx.base,org.hibernate.orm.core;"));
+
+	}
+
+	@Test
+	void pesistenceXmlTest() throws URISyntaxException {
+		ProjectContains projectContains = new ProjectContains("persistence.xml");
+		assertThat(TextFileContains.getProjectRoot(getClass()), projectContains);
+		assertThat(projectContains.getFoundFiles(), Matchers.not(Matchers.hasSize(0)));
+		Path persistenceXml = projectContains.getFoundFiles().getFirst();
+		assertThat(persistenceXml.toAbsolutePath().toString(),
+				Matchers.endsWith(Paths.get("resources", "META-INF", "persistence.xml").toString()));
+	}
+
+	@Test
+	void useEntityTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains(".*\\.java", "@Entity").useRegExpForName(true));
+	}
+
+	@Test
+	void useIdTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains(".*\\.java", "@Id").useRegExpForName(true));
+	}
+
+	@Test
+	void useGeneratedValueTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains(".*\\.java", "@GeneratedValue").useRegExpForName(true));
+	}
+
+	@Test
+	void useEntityManagerTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains(".*\\.java", "EntityManager").useRegExpForName(true));
+	}
+
+	@Test
+	void usePersistOrMergeTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()),
+				new TextFileContains(".*\\.java", "\\.persist\\(|\\.merge\\(").useRegExpForName(true));
+	}
+}
-- 
GitLab