Merge pull request #258 from bsinno/feature_add_entity_interceptor

Add entity lifercycle interceptor interface and add a entity listener.
This commit is contained in:
Michael Hirsch
2016-07-28 15:47:32 +02:00
committed by GitHub
6 changed files with 388 additions and 1 deletions

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.model;
/**
* Interface for the entity interceptor lifecycle.
*/
public interface EntityInterceptor {
/**
* Callback for the {@link @PrePersist} lifecycle event.
*
* @param entity
* the model entity
*/
default void prePersist(final Object entity) {
};
/**
* Callback for the {@link @PostPersist} lifecycle event.
*
* @param entity
* the model entity
*/
default void postPersist(final Object entity) {
};
/**
* Callback for the {@link @PostRemove} lifecycle event.
*
* @param entity
* the model entity
*/
default void postRemove(final Object entity) {
};
/**
* Callback for the {@link @PreRemove} lifecycle event.
*
* @param entity
* the model entity
*/
default void preRemove(final Object entity) {
};
/**
* Callback for the {@link @PostLoad} lifecycle event.
*
* @param entity
* the model entity
*/
default void postLoad(final Object entity) {
};
/**
* Callback for the {@link @PreUpdate} lifecycle event.
*
* @param entity
* the model entity
*/
default void preUpdate(final Object entity) {
};
/**
* Callback for the {@link @PostUpdate} lifecycle event.
*
* @param entity
* the model entity
*/
default void postUpdate(final Object entity) {
};
}

View File

@@ -46,6 +46,7 @@ import org.eclipse.hawkbit.repository.jpa.aspects.ExceptionMappingAspectHandler;
import org.eclipse.hawkbit.repository.jpa.configuration.MultiTenantJpaTransactionManager;
import org.eclipse.hawkbit.repository.jpa.model.helper.AfterTransactionCommitExecutorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.CacheManagerHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemSecurityContextHolder;
@@ -144,6 +145,14 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
return SecurityTokenGeneratorHolder.getInstance();
}
/**
* @return the singleton instance of the {@link EntityInterceptorHolder}
*/
@Bean
public EntityInterceptorHolder entityInterceptorHolder() {
return EntityInterceptorHolder.getInstance();
}
/**
* @return the singleton instance of the {@link CacheManagerHolder}
*/

View File

@@ -31,7 +31,8 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
*/
@MappedSuperclass
@Access(AccessType.FIELD)
@EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class })
@EntityListeners({ AuditingEntityListener.class, CacheFieldEntityListener.class, EntityPropertyChangeListener.class,
EntityInterceptorListener.class })
public abstract class AbstractJpaBaseEntity implements BaseEntity {
private static final long serialVersionUID = 1L;

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import java.util.function.Consumer;
import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.model.EntityInterceptor;
/**
* Entity listener which calls the callback's of all registered entity
* interceptors.
*/
public class EntityInterceptorListener {
@PrePersist
protected void prePersist(final Object entity) {
notifyAll(interceptor -> interceptor.prePersist(entity));
}
@PostPersist
protected void postPersist(final Object entity) {
notifyAll(interceptor -> interceptor.postPersist(entity));
}
@PostRemove
protected void postRemove(final Object entity) {
notifyAll(interceptor -> interceptor.postRemove(entity));
}
@PreRemove
protected void preRemove(final Object entity) {
notifyAll(interceptor -> interceptor.preRemove(entity));
}
@PostLoad
protected void postLoad(final Object entity) {
notifyAll(interceptor -> interceptor.postLoad(entity));
}
@PreUpdate
protected void preUpdate(final Object entity) {
notifyAll(interceptor -> interceptor.preUpdate(entity));
}
@PostUpdate
protected void postUpdate(final Object entity) {
notifyAll(interceptor -> interceptor.postUpdate(entity));
}
private void notifyAll(final Consumer<? super EntityInterceptor> action) {
EntityInterceptorHolder.getInstance().getEntityInterceptors().forEach(action);
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model.helper;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.hawkbit.repository.model.EntityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
/**
* A singleton bean which holds the {@link EntityInterceptor} to have all
* interceptors in spring beans.
*
*/
public final class EntityInterceptorHolder {
private static final EntityInterceptorHolder SINGLETON = new EntityInterceptorHolder();
@Autowired(required = false)
private final List<EntityInterceptor> entityInterceptors = new ArrayList<>();
private EntityInterceptorHolder() {
}
/**
* @return the entity intreceptor holder singleton instance
*/
public static EntityInterceptorHolder getInstance() {
return SINGLETON;
}
public List<EntityInterceptor> getEntityInterceptors() {
return entityInterceptors;
}
}

View File

@@ -0,0 +1,186 @@
/**
* Copyright (c) 2015 Bosch Software Innovations GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.eclipse.hawkbit.repository.jpa.model;
import static org.fest.assertions.Assertions.assertThat;
import org.eclipse.hawkbit.repository.jpa.AbstractJpaIntegrationTest;
import org.eclipse.hawkbit.repository.jpa.model.helper.EntityInterceptorHolder;
import org.eclipse.hawkbit.repository.model.EntityInterceptor;
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
import org.eclipse.hawkbit.repository.model.Target;
import org.junit.Test;
import ru.yandex.qatools.allure.annotations.Description;
import ru.yandex.qatools.allure.annotations.Features;
import ru.yandex.qatools.allure.annotations.Stories;
/**
* Test the entity listener interceptor.
*/
@Features("Component Tests - Repository")
@Stories("Entity Listener Interceptor")
public class EntityInterceptorListenerTest extends AbstractJpaIntegrationTest {
@Override
public void after() {
EntityInterceptorHolder.getInstance().getEntityInterceptors().clear();
super.after();
}
@Test
@Description("Verfies that the pre persist is called after a entity creation.")
public void prePersistIsCalledWhenPersistingATarget() {
executePersistAndAssertCallbackResult(new PrePersistEntityListener());
}
@Test
@Description("Verfies that the post persist is called after a entity creation.")
public void postPersistIsCalledWhenPersistingATarget() {
executePersistAndAssertCallbackResult(new PostPersistEntityListener());
}
@Test
@Description("Verfies that the post load is called after a entity is loaded.")
public void postLoadIsCalledWhenLoadATarget() {
final PostLoadEntityListener postLoadEntityListener = new PostLoadEntityListener();
EntityInterceptorHolder.getInstance().getEntityInterceptors().add(postLoadEntityListener);
final Target targetToBeCreated = entityFactory.generateTarget("targetToBeCreated");
targetManagement.createTarget(targetToBeCreated);
final Target loadedTarget = targetManagement.findTargetByControllerID(targetToBeCreated.getControllerId());
assertThat(postLoadEntityListener.getEntity()).isNotNull();
assertThat(postLoadEntityListener.getEntity()).isEqualTo(loadedTarget);
}
@Test
@Description("Verfies that the pre update is called after a entity update.")
public void preUpdateIsCalledWhenUpdateATarget() {
executeUpdateAndAssertCallbackResult(new PreUpdateEntityListener());
}
@Test
@Description("Verfies that the post update is called after a entity update.")
public void postUpdateIsCalledWhenUpdateATarget() {
executeUpdateAndAssertCallbackResult(new PostUpdateEntityListener());
}
@Test
@Description("Verfies that the pre remove is called after a entity deletion.")
public void preRemoveIsCalledWhenDeletingATarget() {
executeDeleteAndAssertCallbackResult(new PreRemoveEntityListener());
}
@Test
@Description("Verfies that the post remove is called after a entity deletion.")
public void postRemoveIsCalledWhenDeletingATarget() {
executeDeleteAndAssertCallbackResult(new PostRemoveEntityListener());
}
private void executePersistAndAssertCallbackResult(final AbstractEntityListener entityInterceptor) {
final Target targetToBeCreated = entityFactory.generateTarget("targetToBeCreated");
addListenerAndCreateTarget(entityInterceptor, targetToBeCreated);
assertThat(entityInterceptor.getEntity()).isNotNull();
assertThat(entityInterceptor.getEntity()).isEqualTo(targetToBeCreated);
}
private void executeUpdateAndAssertCallbackResult(final AbstractEntityListener entityInterceptor) {
Target updateTarget = addListenerAndCreateTarget(entityInterceptor,
entityFactory.generateTarget("targetToBeCreated"));
updateTarget.setDescription("New");
updateTarget = targetManagement.updateTarget(updateTarget);
assertThat(entityInterceptor.getEntity()).isNotNull();
assertThat(entityInterceptor.getEntity()).isEqualTo(updateTarget);
}
private void executeDeleteAndAssertCallbackResult(final AbstractEntityListener entityInterceptor) {
EntityInterceptorHolder.getInstance().getEntityInterceptors().add(entityInterceptor);
final SoftwareModuleType type = softwareManagement
.createSoftwareModuleType(entityFactory.generateSoftwareModuleType("test", "test", "test", 1));
softwareManagement.deleteSoftwareModuleType(type);
assertThat(entityInterceptor.getEntity()).isNotNull();
assertThat(entityInterceptor.getEntity()).isEqualTo(type);
}
private Target addListenerAndCreateTarget(final AbstractEntityListener entityInterceptor,
final Target targetToBeCreated) {
EntityInterceptorHolder.getInstance().getEntityInterceptors().add(entityInterceptor);
return targetManagement.createTarget(targetToBeCreated);
}
private static abstract class AbstractEntityListener implements EntityInterceptor {
private Object entity;
public Object getEntity() {
return entity;
}
public void setEntity(final Object entity) {
this.entity = entity;
}
}
private static class PrePersistEntityListener extends AbstractEntityListener {
@Override
public void prePersist(final Object entity) {
setEntity(entity);
}
}
private static class PostPersistEntityListener extends AbstractEntityListener {
@Override
public void postPersist(final Object entity) {
setEntity(entity);
}
}
private static class PostLoadEntityListener extends AbstractEntityListener {
@Override
public void postLoad(final Object entity) {
setEntity(entity);
}
}
private static class PreUpdateEntityListener extends AbstractEntityListener {
@Override
public void preUpdate(final Object entity) {
setEntity(entity);
}
}
private static class PostUpdateEntityListener extends AbstractEntityListener {
@Override
public void postUpdate(final Object entity) {
setEntity(entity);
}
}
private static class PreRemoveEntityListener extends AbstractEntityListener {
@Override
public void preRemove(final Object entity) {
setEntity(entity);
}
}
private static class PostRemoveEntityListener extends AbstractEntityListener {
@Override
public void postRemove(final Object entity) {
setEntity(entity);
}
}
}