diff --git a/db/src/main/java/de/muehlencord/shared/db/AbstractController.java b/db/src/main/java/de/muehlencord/shared/db/AbstractController.java index b545046..15a609e 100644 --- a/db/src/main/java/de/muehlencord/shared/db/AbstractController.java +++ b/db/src/main/java/de/muehlencord/shared/db/AbstractController.java @@ -16,6 +16,7 @@ package de.muehlencord.shared.db; import de.muehlencord.shared.util.DateUtil; +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -40,6 +41,7 @@ import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.SingularAttribute; import javax.transaction.Transactional; +import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; /** @@ -47,7 +49,7 @@ import org.apache.commons.lang3.StringUtils; * @author Joern Muehlencord * @param */ -public abstract class AbstractController { +public abstract class AbstractController { @Inject @ApplicationPU @@ -190,14 +192,19 @@ public abstract class AbstractController { return path; } -// public void applyUpdateableChanges(Updateable updateable, boolean onCreate, String updatedBy) throws ControllerException { -// if (onCreate) { -// updateable.setCreatedBy(updatedBy); -// updateable.setCreatedOn(new Date()); -// } -// updateable.setLastUpdatedBy(updatedBy); -// updateable.setLastUpdatedOn(new Date()); -// } + public Audit applyAuditChanges(Audit audit, boolean onCreate, String changedBy) throws ControllerException { + if (audit == null) { + audit = new Audit(); + } + if (onCreate) { + audit.setCreatedBy(changedBy); + audit.setCreatedOn(DateUtil.getCurrentTimeInUTC()); + } + audit.setLastUpdatedBy(changedBy); + audit.setLastUpdatedOn(DateUtil.getCurrentTimeInUTC()); + + return audit; + } public T attach(T entity) { return em.merge(entity); @@ -207,10 +214,10 @@ public abstract class AbstractController { @Transactional @Lock(LockType.WRITE) public T create(T entity, String createdBy) throws ControllerException { -// if (Updateable.class.isAssignableFrom(entity.getClass())) { -// Updateable updateable = (Updateable) entity; -// applyUpdateableChanges(updateable, true, createdBy); -// } + if (Auditable.class.isAssignableFrom(entity.getClass())) { + Audit audit = ((Auditable) entity).getAudit(); + ((Auditable) entity).setAudit(applyAuditChanges(audit, true, createdBy)); + } if (EndDateable.class.isAssignableFrom(entity.getClass())) { EndDateable endDateable = (EndDateable) entity; endDateable.setValidFrom(DateUtil.getCurrentTimeInUTC()); @@ -223,11 +230,26 @@ public abstract class AbstractController { @Transactional @Lock(LockType.WRITE) public T update(T entity, String updatedBy) throws ControllerException { -// if (Updateable.class.isAssignableFrom(entity.getClass())) { -// Updateable updateable = (Updateable) entity; -// applyUpdateableChanges(updateable, false, updatedBy); -// } - return em.merge(entity); + T currentEntity = attach(entity); + T newEntity = getClone(currentEntity); + if (Auditable.class.isAssignableFrom(entity.getClass())) { + Audit audit = ((Auditable) entity).getAudit(); + ((Auditable) entity).setAudit(applyAuditChanges(audit, false, updatedBy)); + } + + if (EndDateable.class.isAssignableFrom(entity.getClass())) { + // end date existing entity + EndDateable endDateable = (EndDateable) entity; + endDateable.setValidTo(DateUtil.getCurrentTimeInUTC()); + em.merge(entity); + // and create new entity instead + + return create(newEntity, updatedBy); + } else { + // if it is not enddatable, just update it (already done above) + // and save it + return em.merge(entity); + } } @TransactionAttribute(TransactionAttributeType.REQUIRED) @@ -236,8 +258,6 @@ public abstract class AbstractController { public void delete(T entity, String deletedBy) throws ControllerException { // if the entity is endDateable just set the validToDate to now intead of executing the deletion if (EndDateable.class.isAssignableFrom(entity.getClass())) { - EndDateable endDateable = (EndDateable) entity; - endDateable.setValidTo(DateUtil.getCurrentTimeInUTC()); update(entity, deletedBy); } else { em.remove(attach(entity)); @@ -329,4 +349,18 @@ public abstract class AbstractController { return of.getId(of.getIdType().getJavaType()); } + private T getClone(T entity) { + T newEntity = SerializationUtils.clone(entity); + // remove audit if class is auditable - it is a new clone + if (Auditable.class.isAssignableFrom(newEntity.getClass())) { + ((Auditable) newEntity).setAudit(null); + } + // set new valid dates if class is enddateable + if (EndDateable.class.isAssignableFrom(newEntity.getClass())) { + ((EndDateable) newEntity).setValidFrom(DateUtil.getCurrentTimeInUTC()); + ((EndDateable) newEntity).setValidTo(null); + } + return newEntity; + } + } diff --git a/db/src/main/java/de/muehlencord/shared/db/AbstractEnddateableController.java b/db/src/main/java/de/muehlencord/shared/db/AbstractEnddateableController.java deleted file mode 100644 index 4f4dca5..0000000 --- a/db/src/main/java/de/muehlencord/shared/db/AbstractEnddateableController.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2019 Joern Muehlencord . - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.muehlencord.shared.db; - -import de.muehlencord.shared.util.DateUtil; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import javax.ejb.Lock; -import javax.ejb.LockType; -import javax.ejb.TransactionAttribute; -import javax.ejb.TransactionAttributeType; -import javax.persistence.TypedQuery; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Order; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.transaction.Transactional; - -/** - * - * @author Joern Muehlencord - * @param an entity which needs to extend EndDateable - */ -public abstract class AbstractEnddateableController> extends AbstractController { - - private final Class endDateableClass; - - public AbstractEnddateableController(Class clazz) { - super(clazz); - this.endDateableClass = clazz; - } - - @TransactionAttribute(TransactionAttributeType.REQUIRED) - @Transactional - @Lock(LockType.WRITE) - @Override - public void delete(T entity, String deletedBy) throws ControllerException { - T entityToUpdate = attach(entity); -// if (Updateable.class.isAssignableFrom(entityToUpdate.getClass())) { -// Updateable updateable = (Updateable) entityToUpdate; -// applyUpdateableChanges(updateable, false, deletedBy); -// } - entityToUpdate.setValidTo(DateUtil.getCurrentTimeInUTC()); - em.merge(entityToUpdate); - } - - @Override - @TransactionAttribute(TransactionAttributeType.REQUIRED) - @Transactional - @Lock(LockType.WRITE) - public T create(T entity, String createdBy) throws ControllerException { - entity.setValidFrom(DateUtil.getCurrentTimeInUTC()); - return super.create(entity, createdBy); - } - - @TransactionAttribute(TransactionAttributeType.REQUIRED) - @Transactional - @Lock(LockType.WRITE) - @Override - public T update(T entity, String createdBy) throws ControllerException { - T newEntity = entity.cloneEndDateable(); - delete(entity, createdBy); - return create(newEntity, createdBy); - } - - @Lock(LockType.READ) - @Override - public List findAll(List orderFields) { - Date now = DateUtil.getCurrentTimeInUTC(); - final CriteriaBuilder cb = em.getCriteriaBuilder(); - final CriteriaQuery criteria = cb.createQuery(endDateableClass); - final Root root = criteria.from(endDateableClass); - - Predicate alreadyValid = cb.lessThanOrEqualTo(root.get("validFrom"), now); - - Predicate validToNotSet = cb.isNull(root.get("validTo")); - Predicate isBeforeValidTo = cb.greaterThanOrEqualTo(root.get("validTo"), now); - Predicate stillValid = cb.or(isBeforeValidTo, validToNotSet); - Predicate isValid = cb.and(alreadyValid, stillValid); - criteria.where(isValid); - - List orderList = new ArrayList<>(); - orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(root.get(field)))); - final TypedQuery query = em.createQuery(criteria.orderBy(orderList)); - - return query.getResultList(); - } - -} diff --git a/db/src/main/java/de/muehlencord/shared/db/Audit.java b/db/src/main/java/de/muehlencord/shared/db/Audit.java index 5ed5564..0597f9e 100644 --- a/db/src/main/java/de/muehlencord/shared/db/Audit.java +++ b/db/src/main/java/de/muehlencord/shared/db/Audit.java @@ -15,6 +15,7 @@ */ package de.muehlencord.shared.db; +import java.io.Serializable; import java.util.Date; import javax.persistence.Basic; import javax.persistence.Column; @@ -26,29 +27,29 @@ import javax.validation.constraints.NotNull; * * @author joern.muehlencord */ -public class Audit { +public class Audit implements Serializable { - private static final long serialVersionUID = 971294035102346924L; + private static final long serialVersionUID = -955765069412891842L; @Basic(optional = false) - @NotNull + @NotNull @Column(name = "created_on") @Temporal(TemporalType.TIMESTAMP) private Date createdOn; @Basic(optional = false) - @NotNull + @NotNull @Column(name = "created_by") private String createdBy; @Basic(optional = false) - @NotNull + @NotNull @Column(name = "last_updated_on") @Temporal(TemporalType.TIMESTAMP) private Date lastUpdatedOn; @Basic(optional = false) - @NotNull + @NotNull @Column(name = "last_updated_by") private String lastUpdatedBy; diff --git a/db/src/main/java/de/muehlencord/shared/db/AuditListener.java b/db/src/main/java/de/muehlencord/shared/db/AuditListener.java index 797cf5f..75a1583 100644 --- a/db/src/main/java/de/muehlencord/shared/db/AuditListener.java +++ b/db/src/main/java/de/muehlencord/shared/db/AuditListener.java @@ -17,20 +17,18 @@ package de.muehlencord.shared.db; import de.muehlencord.shared.util.DateUtil; import java.util.Date; -import javax.persistence.PrePersist; -import javax.persistence.PreUpdate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * + * Does not work, cannot Spring independet inject current username - implemented in AbstractController manually * @author joern.muehlencord */ public class AuditListener { private static final Logger LOGGER = LoggerFactory.getLogger(AuditListener.class); - @PrePersist +// @PrePersist public void prePersist(Auditable auditable) { Audit audit = auditable.getAudit(); @@ -50,7 +48,7 @@ public class AuditListener { } - @PreUpdate +// @PreUpdate public void preUpdate(Auditable auditable) { Audit audit = auditable.getAudit(); diff --git a/db/src/main/java/de/muehlencord/shared/db/EndDateable.java b/db/src/main/java/de/muehlencord/shared/db/EndDateable.java index 1c43a7c..e4840c3 100644 --- a/db/src/main/java/de/muehlencord/shared/db/EndDateable.java +++ b/db/src/main/java/de/muehlencord/shared/db/EndDateable.java @@ -24,8 +24,6 @@ import java.util.Date; */ public interface EndDateable { - T cloneEndDateable(); - Date getValidFrom(); Date getValidTo(); diff --git a/db/src/main/java/de/muehlencord/shared/db/Updateable.java b/db/src/main/java/de/muehlencord/shared/db/Updateable.java deleted file mode 100644 index b320fcf..0000000 --- a/db/src/main/java/de/muehlencord/shared/db/Updateable.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.muehlencord.shared.db; - -import java.util.Date; - -/** - * This interface is used for Entities which provide createdOn / createdBy - * lastUpatedBy / lastUpdatedOn fields. The AbstractController uses this interface - * to automatically update the fields on creation / update. - * - * @author Joern Muehlencord - */ -public interface Updateable { - - void setCreatedBy(String createdBy); - - String getCreatedBy(); - - void setCreatedOn(Date createdOn); - - Date getCreatedOn(); - - void setLastUpdatedBy(String lastUpdatedBy); - - String getLastUpdatedBy(); - - void setLastUpdatedOn(Date lastUpdatedOn); - - Date getLastUpdatedOn(); -}