diff --git a/pom.xml b/pom.xml index b31c130..1d00503 100644 --- a/pom.xml +++ b/pom.xml @@ -143,7 +143,7 @@ validate - validate + verify UTF-8 true diff --git a/src/main/java/by/academy/it/task09/App.java b/src/main/java/by/academy/it/task09/App.java index 1b6b633..71d518e 100644 --- a/src/main/java/by/academy/it/task09/App.java +++ b/src/main/java/by/academy/it/task09/App.java @@ -1,36 +1,66 @@ package by.academy.it.task09; +import by.academy.it.task09.dao.DaoFactory; +import by.academy.it.task09.dao.TaskDao; +import by.academy.it.task09.entity.Task; +import by.academy.it.task09.util.HomeTaskEnum; +import by.academy.it.task09.util.TaskEnum; +import by.academy.it.task09.util.WorkTaskEnum; + +import java.util.List; + /** * Create three classes * 1) Task - has the following fields * - id * - name * - description - * + *

* 2) HomeTask extends Task - has additional fields * - startDate * - endDate - * @Embedded - * - performer (type Person [has two fields first and last name, make them Embeddable]) - * @Embedded - * - accepter (type Person [has two fields first and last name, make them Embeddable]) * + * @Embedded - performer + * (type Person [has two fields first and last name, make them Embeddable]) + * @Embedded - accepter + * (type Person [has two fields first and last name, make them Embeddable]) + *

* 3) WorkTask extends Task - has additional field * - cost - * + *

* In three git branches, implement 3 inheritance strategies: * 1 - Table per class hierarchy * 2 - Table per subclass * 3 - Table Per Concrete class mapping - * + *

* Write there some data from the main method. * Check through tests on H2, connect checkstyle, jacoco. - * */ -public class App -{ - public static void main( String[] args ) - { +public final class App { + /** + * + */ + private App() { + + } + /** + * @param args + */ + public static void main(final String[] args) { + System.out.println("\'Single table\' implementation"); + List taskList = + List.of(TaskEnum.FIRST_TASK.getTask(), + HomeTaskEnum.FIRST_HOME_TASK.getHomeTask(), + WorkTaskEnum.FIRST_WORK_TASK.getWorkTask(), + TaskEnum.SECOND_TASK.getTask(), + HomeTaskEnum.SECOND_HOME_TASK.getHomeTask(), + WorkTaskEnum.SECOND_WORK_TASK.getWorkTask()); + TaskDao dao = DaoFactory.getInstance().getDaoProduction(); + dao.save(taskList); + List result = dao.findAll(); + for (Task task : result) { + System.out.println(task); + } } } diff --git a/src/main/java/by/academy/it/task09/dao/DaoFactory.java b/src/main/java/by/academy/it/task09/dao/DaoFactory.java new file mode 100644 index 0000000..38a95dd --- /dev/null +++ b/src/main/java/by/academy/it/task09/dao/DaoFactory.java @@ -0,0 +1,39 @@ +package by.academy.it.task09.dao; + +import by.academy.it.task09.dao.impl.TaskDaoImpl; +import by.academy.it.task09.dao.util.PersistenceUnitName; + +/** + * + */ +public class DaoFactory { + + private static class SingletonHolder { + private final static DaoFactory INSTANCE = new DaoFactory(); + } + + private DaoFactory() { + + } + + /** + * @return - + */ + public static DaoFactory getInstance() { + return SingletonHolder.INSTANCE; + } + + /** + * @return - + */ + public TaskDao getDaoProduction() { + return new TaskDaoImpl(PersistenceUnitName.PRODUCTION); + } + + /** + * @return - + */ + public TaskDao getDaoTest() { + return new TaskDaoImpl(PersistenceUnitName.TEST); + } +} diff --git a/src/main/java/by/academy/it/task09/dao/TaskDao.java b/src/main/java/by/academy/it/task09/dao/TaskDao.java new file mode 100644 index 0000000..e2aeb66 --- /dev/null +++ b/src/main/java/by/academy/it/task09/dao/TaskDao.java @@ -0,0 +1,41 @@ +package by.academy.it.task09.dao; + +import by.academy.it.task09.entity.Task; + +import java.util.List; + +/** + * + */ +public interface TaskDao { + /** + * @param id + * @return - + */ + Task findById(Long id); + + /** + * @return - + */ + List findAll(); + + /** + * @param task + */ + void save(Task task); + + /** + * @param list + */ + void save(List list); + + /** + * @param task + */ + void update(Task task); + + /** + * @param id + */ + void delete(Long id); +} diff --git a/src/main/java/by/academy/it/task09/dao/exception/TaskDaoException.java b/src/main/java/by/academy/it/task09/dao/exception/TaskDaoException.java new file mode 100644 index 0000000..0bb5f52 --- /dev/null +++ b/src/main/java/by/academy/it/task09/dao/exception/TaskDaoException.java @@ -0,0 +1,21 @@ +package by.academy.it.task09.dao.exception; + +/** + * + */ +public class TaskDaoException extends RuntimeException { + public TaskDaoException() { + } + + public TaskDaoException(String message) { + super(message); + } + + public TaskDaoException(String message, Throwable cause) { + super(message, cause); + } + + public TaskDaoException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/by/academy/it/task09/dao/impl/TaskDaoImpl.java b/src/main/java/by/academy/it/task09/dao/impl/TaskDaoImpl.java new file mode 100644 index 0000000..be88e10 --- /dev/null +++ b/src/main/java/by/academy/it/task09/dao/impl/TaskDaoImpl.java @@ -0,0 +1,136 @@ +package by.academy.it.task09.dao.impl; + +import by.academy.it.task09.dao.TaskDao; +import by.academy.it.task09.dao.exception.TaskDaoException; +import by.academy.it.task09.dao.util.PersistenceUnitName; +import by.academy.it.task09.entity.Task; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; +import java.util.List; + +/** + * + */ +public class TaskDaoImpl implements TaskDao { + /** + * + */ + private final EntityManagerFactory factory; + + public TaskDaoImpl(final PersistenceUnitName name) { + this.factory = + Persistence + .createEntityManagerFactory(name.getValue()); + } + + /** + * @param id + * @return + */ + @Override + public Task findById(final Long id) { + EntityManager entityManager = factory.createEntityManager(); + Task result = null; + try { + result = entityManager.find(Task.class, id); + } catch (IllegalArgumentException e) { + throw new TaskDaoException(e); + } finally { + entityManager.close(); + } + return result; + } + + /** + * @return - + */ + @Override + public List findAll() { + EntityManager entityManager = factory.createEntityManager(); + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Task.class); + Root rootEntry = criteriaQuery.from(Task.class); + CriteriaQuery all = criteriaQuery.select(rootEntry); + TypedQuery allQuery = entityManager.createQuery(all); + return allQuery.getResultList(); + } + + /** + * @param task + */ + @Override + public void save(final Task task) { + EntityManager entityManager = factory.createEntityManager(); + try { + entityManager.getTransaction().begin(); + entityManager.persist(task); + entityManager.getTransaction().commit(); + } catch (RuntimeException e) { + entityManager.getTransaction().rollback(); + throw new TaskDaoException(e); + } finally { + entityManager.close(); + } + } + + /** + * @param list + */ + @Override + public void save(final List list) { + EntityManager entityManager = factory.createEntityManager(); + try { + entityManager.getTransaction().begin(); + list.forEach(entityManager::persist); + entityManager.getTransaction().commit(); + } catch (RuntimeException e) { + entityManager.getTransaction().rollback(); + throw new TaskDaoException(e); + } finally { + entityManager.close(); + } + } + + /** + * @param task + */ + @Override + public void update(final Task task) { + EntityManager entityManager = factory.createEntityManager(); + try { + entityManager.getTransaction().begin(); + entityManager.merge(task); + entityManager.getTransaction().commit(); + } catch (RuntimeException e) { + entityManager.getTransaction().rollback(); + throw new TaskDaoException(e); + } finally { + entityManager.close(); + } + } + + /** + * @param id + */ + @Override + public void delete(final Long id) { + EntityManager entityManager = factory.createEntityManager(); + try { + Task task = entityManager.find(Task.class,id); + entityManager.getTransaction().begin(); + entityManager.remove(task); + entityManager.getTransaction().commit(); + } catch (RuntimeException e) { + entityManager.getTransaction().rollback(); + throw new TaskDaoException(e); + } finally { + entityManager.close(); + } + } +} diff --git a/src/main/java/by/academy/it/task09/dao/util/PersistenceUnitName.java b/src/main/java/by/academy/it/task09/dao/util/PersistenceUnitName.java new file mode 100644 index 0000000..09c382c --- /dev/null +++ b/src/main/java/by/academy/it/task09/dao/util/PersistenceUnitName.java @@ -0,0 +1,24 @@ +package by.academy.it.task09.dao.util; + +/** + * + */ +public enum PersistenceUnitName { + /** + * + */ + PRODUCTION("production"), + /** + * + */ + TEST("test"); + private String value; + + PersistenceUnitName(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/by/academy/it/task09/entity/HomeTask.java b/src/main/java/by/academy/it/task09/entity/HomeTask.java new file mode 100644 index 0000000..335f2c4 --- /dev/null +++ b/src/main/java/by/academy/it/task09/entity/HomeTask.java @@ -0,0 +1,73 @@ +package by.academy.it.task09.entity; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import java.time.LocalDate; + +/** + * + */ +@NoArgsConstructor +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +@Entity +@DiscriminatorValue("home_task") +@Access(AccessType.FIELD) +public class HomeTask extends Task { + /** + * + */ + @Column + private LocalDate startDate; + /** + * + */ + @Column + private LocalDate finishDate; + /** + * + */ + @Embedded + @AttributeOverrides({ + @AttributeOverride(name = "surname", + column = @Column(name = "p_surname")), + @AttributeOverride(name = "name", + column = @Column(name = "p_name")) + }) + private Person performer; + /** + * + */ + @Embedded + @AttributeOverrides({ + @AttributeOverride(name = "surname", + column = @Column(name = "a_surname")), + @AttributeOverride(name = "name", + column = @Column(name = "a_name")) + }) + private Person accepter; + + public HomeTask(String name, + String description, + LocalDate startDate, + LocalDate finishDate, + Person performer, + Person accepter) { + super(name, description); + this.startDate = startDate; + this.finishDate = finishDate; + this.performer = performer; + this.accepter = accepter; + } +} diff --git a/src/main/java/by/academy/it/task09/entity/Person.java b/src/main/java/by/academy/it/task09/entity/Person.java new file mode 100644 index 0000000..b4f2de9 --- /dev/null +++ b/src/main/java/by/academy/it/task09/entity/Person.java @@ -0,0 +1,27 @@ +package by.academy.it.task09.entity; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import javax.persistence.Embeddable; + +/** + * + */ +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@ToString +@Embeddable +public class Person { + /** + * + */ + private String surname; + /** + * + */ + private String name; +} diff --git a/src/main/java/by/academy/it/task09/entity/Task.java b/src/main/java/by/academy/it/task09/entity/Task.java new file mode 100644 index 0000000..e266100 --- /dev/null +++ b/src/main/java/by/academy/it/task09/entity/Task.java @@ -0,0 +1,62 @@ +package by.academy.it.task09.entity; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Column; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorType; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.Table; + +/** + * + */ +@NoArgsConstructor +@ToString +@EqualsAndHashCode +@Entity +@Table +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn(name = "task_type", discriminatorType = DiscriminatorType.STRING) +@DiscriminatorValue("null") +@Access(AccessType.FIELD) +public class Task { + /** + * + */ + @Id + @Column + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + /** + * + */ + @Column + private String name; + /** + * + */ + @Column(length = 1000) + private String description; + + public Task(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/by/academy/it/task09/entity/WorkTask.java b/src/main/java/by/academy/it/task09/entity/WorkTask.java new file mode 100644 index 0000000..73e92ca --- /dev/null +++ b/src/main/java/by/academy/it/task09/entity/WorkTask.java @@ -0,0 +1,42 @@ +package by.academy.it.task09.entity; + +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.Column; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import java.math.BigDecimal; + +/** + * + */ +@Entity +@NoArgsConstructor +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +@DiscriminatorValue("work_task") +@Access(AccessType.FIELD) +public class WorkTask extends Task { + /** + * + */ + @Column + private BigDecimal cost; + + public WorkTask(String surname, String name, BigDecimal cost) { + super(surname, name); + this.cost = cost; + } + + public BigDecimal getCost() { + return cost; + } + + public void setCost(BigDecimal cost) { + this.cost = cost; + } +} diff --git a/src/main/java/by/academy/it/task09/util/HomeTaskEnum.java b/src/main/java/by/academy/it/task09/util/HomeTaskEnum.java new file mode 100644 index 0000000..568a184 --- /dev/null +++ b/src/main/java/by/academy/it/task09/util/HomeTaskEnum.java @@ -0,0 +1,51 @@ +package by.academy.it.task09.util; + +import by.academy.it.task09.entity.HomeTask; + +import java.time.LocalDate; + +/** + * + */ +public enum HomeTaskEnum { + /** + * + */ + FIRST_HOME_TASK( + new HomeTask( + "HomeTask01", + "zxcvbnm", + LocalDate.of(2012, 9, 13), + LocalDate.of(2012, 12, 15), + PersonEnum.JAMES_BOND.getPerson(), + PersonEnum.CURT_COBAIN.getPerson() + )), + /** + * + */ + SECOND_HOME_TASK(new HomeTask( + "HomeTask02", + "mnbvcxz", + LocalDate.of(1987, 2, 27), + LocalDate.of(1988, 3, 12), + PersonEnum.CURT_COBAIN.getPerson(), + PersonEnum.JAMES_BOND.getPerson() + )); + + private HomeTask homeTask; + + HomeTaskEnum(HomeTask homeTask) { + this.homeTask = homeTask; + } + + public HomeTask getHomeTask() { + return homeTask; + } + + @Override + public String toString() { + return "HomeTaskEnum{" + + "homeTask=" + homeTask + + '}'; + } +} diff --git a/src/main/java/by/academy/it/task09/util/PersonEnum.java b/src/main/java/by/academy/it/task09/util/PersonEnum.java new file mode 100644 index 0000000..0c47e9a --- /dev/null +++ b/src/main/java/by/academy/it/task09/util/PersonEnum.java @@ -0,0 +1,26 @@ +package by.academy.it.task09.util; + +import by.academy.it.task09.entity.Person; + +/** + * + */ +public enum PersonEnum { + /** + * + */ + JAMES_BOND(new Person("Bond", "James")), + /** + * + */ + CURT_COBAIN(new Person("Cobain", "Curt")); + private Person person; + + PersonEnum(Person person) { + this.person = person; + } + + public Person getPerson() { + return person; + } +} diff --git a/src/main/java/by/academy/it/task09/util/TaskEnum.java b/src/main/java/by/academy/it/task09/util/TaskEnum.java new file mode 100644 index 0000000..f6c1277 --- /dev/null +++ b/src/main/java/by/academy/it/task09/util/TaskEnum.java @@ -0,0 +1,27 @@ +package by.academy.it.task09.util; + +import by.academy.it.task09.entity.Task; + +/** + * + */ +public enum TaskEnum { + /** + * + */ + FIRST_TASK(new Task("Task01", "Description for Task01")), + /** + * + */ + SECOND_TASK(new Task("Task02", "Description for Task02")); + + private final Task task; + + TaskEnum(Task task) { + this.task = task; + } + + public Task getTask() { + return task; + } +} diff --git a/src/main/java/by/academy/it/task09/util/WorkTaskEnum.java b/src/main/java/by/academy/it/task09/util/WorkTaskEnum.java new file mode 100644 index 0000000..9c1a1ea --- /dev/null +++ b/src/main/java/by/academy/it/task09/util/WorkTaskEnum.java @@ -0,0 +1,39 @@ +package by.academy.it.task09.util; + +import by.academy.it.task09.entity.WorkTask; + +import java.math.BigDecimal; + +/** + * + */ +public enum WorkTaskEnum { + /** + * + */ + FIRST_WORK_TASK(new WorkTask("Name: WorkTask01", + "qwertyuiop", + new BigDecimal("200.98"))), + /** + * + */ + SECOND_WORK_TASK(new WorkTask("Name: WorkTask02", + "asdfghjkl", + new BigDecimal("593.74"))); + private WorkTask workTask; + + WorkTaskEnum(WorkTask workTask) { + this.workTask = workTask; + } + + public WorkTask getWorkTask() { + return workTask; + } + + @Override + public String toString() { + return "WorkTaskEnum{" + + "workTask=" + workTask + + '}'; + } +} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 0000000..2a1d00f --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,45 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + by.academy.it.task09.entity.HomeTask + by.academy.it.task09.entity.WorkTask + by.academy.it.task09.entity.Task + true + + + + + + + + + + + + + + + + org.hibernate.jpa.HibernatePersistenceProvider + by.academy.it.task09.entity.HomeTask + by.academy.it.task09.entity.WorkTask + by.academy.it.task09.entity.Task + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/by/academy/it/task09/AppTest.java b/src/test/java/by/academy/it/task09/AppTest.java index f4b21f6..7dfcedd 100644 --- a/src/test/java/by/academy/it/task09/AppTest.java +++ b/src/test/java/by/academy/it/task09/AppTest.java @@ -1,18 +1,95 @@ package by.academy.it.task09; +import by.academy.it.task09.dao.DaoFactory; +import by.academy.it.task09.dao.TaskDao; +import by.academy.it.task09.entity.Task; +import by.academy.it.task09.entity.WorkTask; +import by.academy.it.task09.util.HomeTaskEnum; +import by.academy.it.task09.util.TaskEnum; +import by.academy.it.task09.util.WorkTaskEnum; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import java.math.BigDecimal; +import java.util.List; + /** * Unit test for simple App. */ public class AppTest extends Assertions { + public static final long FIRST_HOME_TASK_ID = 2L; + public static final long FIRST_WORK_TASK_ID = 3L; + public static final long SECOND_HOME_TASK_ID = 5L; + public static final String COST_FOR_CHANGE = "999.99"; + private static TaskDao dao; + + @BeforeAll + static void beforeAll() { + dao = DaoFactory.getInstance().getDaoTest(); + List taskList = + List.of(TaskEnum.FIRST_TASK.getTask(), + HomeTaskEnum.FIRST_HOME_TASK.getHomeTask(), + WorkTaskEnum.FIRST_WORK_TASK.getWorkTask(), + TaskEnum.SECOND_TASK.getTask(), + HomeTaskEnum.SECOND_HOME_TASK.getHomeTask()); + dao.save(taskList); + } + /** * Rigorous Test :-) */ + @Test public void shouldAnswerWithTrue() { assertTrue(true); } + + @Test + public void shouldAddAndFindAddedElement() { + dao.save(WorkTaskEnum.SECOND_WORK_TASK.getWorkTask()); + List task = dao.findAll(); + int count = (int) task.stream() + .filter(t -> t.getName() + .equals(WorkTaskEnum.SECOND_WORK_TASK.getWorkTask().getName())) + .count(); + assertEquals(1, count); + } + + @Test + public void shouldFindFirstHomeTask() { + Task task = dao.findById(FIRST_HOME_TASK_ID); + assertEquals(HomeTaskEnum.FIRST_HOME_TASK.getHomeTask(), task); + } + + @Test + public void shouldUpdateCostInWorkTask() { + WorkTask workTask = (WorkTask) dao.findById(FIRST_WORK_TASK_ID); + BigDecimal cost = new BigDecimal(COST_FOR_CHANGE); + workTask.setCost(cost); + dao.update(workTask); + WorkTask updatedWorkTask = (WorkTask) dao.findById(FIRST_WORK_TASK_ID); + assertEquals(cost, updatedWorkTask.getCost()); + + } + + @Test + public void shouldDeleteSecondHomeTask() { + List result = dao.findAll(); + for (Task task : result) { + System.out.println(task); + } + dao.delete(SECOND_HOME_TASK_ID); + List task = dao.findAll(); + int count = (int) task.stream() + .filter(t -> t.equals(HomeTaskEnum.SECOND_HOME_TASK.getHomeTask())) + .count(); + assertEquals(0, count); + } + + @Test + public void shouldNotNullProductionDao(){ + assertNotNull(DaoFactory.getInstance().getDaoProduction()); + } }