diff --git a/account/pom.xml b/account/pom.xml index 0d93b86..341b088 100644 --- a/account/pom.xml +++ b/account/pom.xml @@ -44,7 +44,6 @@ de.muehlencord.shared shared-jeeutil jar - 1.1-SNAPSHOT junit @@ -69,7 +68,6 @@ de.muehlencord.shared shared-util - 1.1-SNAPSHOT jar @@ -83,8 +81,10 @@ javax javaee-api + 7.0 + jar provided - + org.hibernate hibernate-core diff --git a/account/src/main/java/de/muehlencord/shared/account/business/AbstractController.java b/account/src/main/java/de/muehlencord/shared/account/business/AbstractController.java new file mode 100644 index 0000000..55a7bfb --- /dev/null +++ b/account/src/main/java/de/muehlencord/shared/account/business/AbstractController.java @@ -0,0 +1,119 @@ +/* + * Copyright 2016 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.account.business; + +import de.muehlencord.shared.account.business.account.entity.Account; +import de.muehlencord.shared.account.util.ApplicationPU; +import de.muehlencord.shared.account.util.Updateable; +import java.util.ArrayList; +import java.util.Arrays; +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.inject.Inject; +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Root; +import javax.transaction.Transactional; + +/** + * + * @author Joern Muehlencord + * @param + */ +public abstract class AbstractController { + + @Inject + @ApplicationPU + protected EntityManager em; + + @Inject + Account account; + + private final Class entityClass; + + public AbstractController(Class clazz) { + this.entityClass = clazz; + } + + public T attach(T entity) { + return em.merge(entity); + } + + @TransactionAttribute (TransactionAttributeType.REQUIRED) + @Transactional + @Lock(LockType.WRITE) + public void create(T entity) { + if (Updateable.class.isAssignableFrom(entity.getClass())) { + Updateable updateable = (Updateable) entity; + updateable.setCreatedBy(account.getUsername()); + updateable.setCreatedOn(new Date()); + updateable.setLastUpdatedBy(account.getUsername()); + updateable.setLastUpdatedOn(new Date()); + } + em.persist(entity); + } + + @TransactionAttribute (TransactionAttributeType.REQUIRED) + @Transactional + @Lock(LockType.WRITE) + public T update(T entity) { + if (Updateable.class.isAssignableFrom(entity.getClass())) { + Updateable updateable = (Updateable) entity; + updateable.setLastUpdatedBy(account.getUsername()); + updateable.setLastUpdatedOn(new Date()); + } + return em.merge(entity); + } + + @TransactionAttribute (TransactionAttributeType.REQUIRED) + @Transactional + @Lock(LockType.WRITE) + public void delete(T entity) { + em.remove(attach(entity)); + } + + @Lock(LockType.READ) + public List findAll() { + return findAll(new ArrayList<>()); + } + + @Lock(LockType.READ) + public List findAll(String... orderFields) { + return findAll(Arrays.asList(orderFields)); + } + + @Lock(LockType.READ) + public List findAll(List orderFields) { + final CriteriaBuilder cb = em.getCriteriaBuilder(); + final CriteriaQuery criteria = cb.createQuery(entityClass); + + final Root r = criteria.from(entityClass); + + List orderList = new ArrayList<>(); + orderFields.stream().forEachOrdered(field -> orderList.add(cb.asc(r.get(field)))); + final TypedQuery query = em.createQuery(criteria.orderBy(orderList)); + + return query.getResultList(); + } + +} diff --git a/account/src/main/java/de/muehlencord/shared/account/business/TransactionJoinInterceptor.java b/account/src/main/java/de/muehlencord/shared/account/business/TransactionJoinInterceptor.java new file mode 100644 index 0000000..77f7619 --- /dev/null +++ b/account/src/main/java/de/muehlencord/shared/account/business/TransactionJoinInterceptor.java @@ -0,0 +1,44 @@ +package de.muehlencord.shared.account.business; + +import de.muehlencord.shared.account.util.ApplicationPU; +import javax.annotation.Priority; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; +import javax.persistence.EntityManager; +import javax.transaction.Transactional; +import static javax.transaction.Transactional.TxType.REQUIRED; +import javax.validation.constraints.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * + * @author Joern Muehlencord + */ +@Transactional(value = REQUIRED) +@Interceptor +@Priority(value = TransactionJoinInterceptor.PRIORITY) +public class TransactionJoinInterceptor { + + private static final Logger LOGGER = LoggerFactory.getLogger(TransactionJoinInterceptor.class); + + // attach behind the interceptor of the container + public static final int PRIORITY = Interceptor.Priority.PLATFORM_BEFORE + 250; + + @Inject + @NotNull + @ApplicationPU + private EntityManager em; + + @AroundInvoke + public Object joinTransaction(InvocationContext context) throws Exception { + if (em.isJoinedToTransaction()) { + LOGGER.trace("transaction already joined"); + } else { + LOGGER.trace("joining transaction"); + em.joinTransaction(); + } + return context.proceed(); + } +} diff --git a/account/src/main/java/de/muehlencord/shared/account/util/ApplicationPU.java b/account/src/main/java/de/muehlencord/shared/account/util/ApplicationPU.java new file mode 100644 index 0000000..b320495 --- /dev/null +++ b/account/src/main/java/de/muehlencord/shared/account/util/ApplicationPU.java @@ -0,0 +1,36 @@ +/* + * Copyright 2018 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.account.util; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Target; +import javax.inject.Qualifier; + +/** + * + * @author Joern Muehlencord + */ +@Qualifier +@Retention(RUNTIME) +@Target({METHOD, FIELD, PARAMETER, TYPE}) +public @interface ApplicationPU { + +} diff --git a/account/src/main/java/de/muehlencord/shared/account/util/Updateable.java b/account/src/main/java/de/muehlencord/shared/account/util/Updateable.java new file mode 100644 index 0000000..dda107f --- /dev/null +++ b/account/src/main/java/de/muehlencord/shared/account/util/Updateable.java @@ -0,0 +1,29 @@ +package de.muehlencord.shared.account.util; + +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(); +}