From: Gustavo Martin Morcuende Date: Mon, 18 Jul 2016 21:01:43 +0000 (+0200) Subject: Using Envers X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=f688e6f05658a9b3a1f5b75c7724935c12769e8f;p=JavaForFun Using Envers --- diff --git a/SpringJava/JPA/src/main/java/de/spring/example/context/UsernameThreadContext.java b/SpringJava/JPA/src/main/java/de/spring/example/context/UsernameThreadContext.java new file mode 100644 index 0000000..4d698ee --- /dev/null +++ b/SpringJava/JPA/src/main/java/de/spring/example/context/UsernameThreadContext.java @@ -0,0 +1,26 @@ +package de.spring.example.context; + +import javax.inject.Named; + +import org.springframework.util.Assert; + +@Named("userNameThreadContext") +public class UsernameThreadContext { + public static final String USERNAME_HEADER = "USERNAME"; + + private final ThreadLocal contextHolder = new ThreadLocal<>(); + + public void setUsername(String username) { + Assert.notNull(username); + + contextHolder.set(username); + } + + public String getUsername() { + return contextHolder.get(); + } + + public void clearUsername() { + contextHolder.remove(); + } +} diff --git a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/Ad.java b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/Ad.java index 7d90e0c..0f91253 100644 --- a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/Ad.java +++ b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/Ad.java @@ -23,6 +23,8 @@ import javax.validation.constraints.Max; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import org.hibernate.envers.Audited; + import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; @@ -30,6 +32,7 @@ import com.fasterxml.jackson.annotation.ObjectIdGenerators; import de.spring.example.persistence.converters.OffsetDateTimeAttributeConverter; @Entity +@Audited(withModifiedFlag=true) @Table(name="ad", schema="mybatis_example") @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="jsonId") // 1. Named query is JPL. It is portable. diff --git a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/AdDescription.java b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/AdDescription.java index b933c42..2142b39 100644 --- a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/AdDescription.java +++ b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/AdDescription.java @@ -16,10 +16,13 @@ import javax.validation.constraints.Max; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import org.hibernate.envers.Audited; + import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; @Entity +@Audited @Table(name="ad_description", schema="mybatis_example") @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="jsonId") public class AdDescription implements Serializable { diff --git a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevision.java b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevision.java new file mode 100644 index 0000000..f8ebfe9 --- /dev/null +++ b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevision.java @@ -0,0 +1,35 @@ +package de.spring.example.persistence.domain.audit; + +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.hibernate.envers.RevisionEntity; + +@Entity +@RevisionEntity(MyCustomRevisionListener.class) +@Table(name="CUSTOM_REVISION", schema="mybatis_example") +public class MyCustomRevision { + private String username; + + // It will be used by JPA when filling the property fields with data coming from data base. + protected MyCustomRevision() { + + } + + // It will be used by my code (for example by Unit Tests) + public MyCustomRevision(String username) { + this.username = username; + } + + /** + * WARNING: JPA REQUIRES GETTERS!!! + */ + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevisionListener.java b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevisionListener.java new file mode 100644 index 0000000..f4c63c7 --- /dev/null +++ b/SpringJava/JPA/src/main/java/de/spring/example/persistence/domain/audit/MyCustomRevisionListener.java @@ -0,0 +1,33 @@ +package de.spring.example.persistence.domain.audit; + +import org.hibernate.envers.RevisionListener; + +import de.spring.example.context.UsernameThreadContext; + +public class MyCustomRevisionListener implements RevisionListener { + private final UsernameThreadContext userNameThreadContext; + + public MyCustomRevisionListener(UsernameThreadContext userNameThreadContext) { + this.userNameThreadContext = userNameThreadContext; + } + + @Override + public void newRevision(Object revisionEntity) { + MyCustomRevision myCustomRevision = (MyCustomRevision) revisionEntity; + + final String username = getSafeUsername(); + myCustomRevision.setUsername(username); + + } + + private String getSafeUsername() { + String userName = userNameThreadContext.getUserName(); + + if (userName == null) { + userName = "NO_USER"; + } + + return userName; + } + +} diff --git a/SpringJava/JPA/src/main/java/de/spring/example/rest/handler/UsernameHandler.java b/SpringJava/JPA/src/main/java/de/spring/example/rest/handler/UsernameHandler.java new file mode 100644 index 0000000..9878f3d --- /dev/null +++ b/SpringJava/JPA/src/main/java/de/spring/example/rest/handler/UsernameHandler.java @@ -0,0 +1,32 @@ +package de.spring.example.rest.handler; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import de.spring.example.context.UsernameThreadContext; + +public class UsernameHandler extends HandlerInterceptorAdapter { + private final UsernameThreadContext usernameThreadContext; + + @Inject + public UsernameHandler(UsernameThreadContext userNameThreadContext) { + this.usernameThreadContext = userNameThreadContext; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + final String userName = request.getHeader(UsernameThreadContext.USERNAME_HEADER); + + if (userName != null) { + usernameThreadContext.setUsername(userName); + } else { + usernameThreadContext.clearUsername(); + } + + return super.preHandle(request, response, handler); + } +} diff --git a/SpringJava/JPA/src/main/resources/spring-configuration/jpa-configuration.xml b/SpringJava/JPA/src/main/resources/spring-configuration/jpa-configuration.xml index a80d040..b460a27 100644 --- a/SpringJava/JPA/src/main/resources/spring-configuration/jpa-configuration.xml +++ b/SpringJava/JPA/src/main/resources/spring-configuration/jpa-configuration.xml @@ -27,6 +27,22 @@ + + + + _AUDITED + REVISION + REVISION_TYPE + true + org.hibernate.envers.strategy.ValidityAuditStrategy + REVISION_END + true + REVISION_END_TIMESTAMP + _MODIFIED + + - +