Commit 36bb3422 authored by Matija Obreza's avatar Matija Obreza
Browse files

Source code cleanup

parent 43d6e21f
......@@ -23,7 +23,8 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Add this annotation to persisted entities to explicitly include them in auditing.
* Add this annotation to persisted entities to explicitly include them in
* auditing.
*
* @author Matija Obreza
*/
......
......@@ -18,7 +18,6 @@ package org.genesys.blocks.auditlog.component;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.text.Format;
import java.util.ArrayList;
import java.util.Calendar;
......@@ -63,30 +62,56 @@ import org.springframework.util.ReflectionUtils;
*/
@Component
public class AuditTrailInterceptor extends EmptyInterceptor implements InitializingBean {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1881637304461659508L;
/** The Constant LOG. */
private static final Logger LOG = LoggerFactory.getLogger(AuditTrailInterceptor.class);
/** The Constant DEFAULT_IGNORED_PROPERTIES. */
private static final Set<String> DEFAULT_IGNORED_PROPERTIES = Stream.of("serialVersionUID", "id", "password", "createdDate", "lastModifiedDate", "version", "lastModifiedBy")
.collect(Collectors.toSet());
.collect(Collectors.toSet());
/** The ignored properties. */
private Set<String> ignoredProperties = new HashSet<>(DEFAULT_IGNORED_PROPERTIES);
/** The audited classes. */
private Set<Class<?>> auditedClasses = new HashSet<>();
/** The included classes. */
// Two caches
private final Set<Class<?>> ignoredClasses, includedClasses;
/** The audit trail service. */
@Autowired
private AuditTrailService auditTrailService;
/** The entity manager. */
@PersistenceContext
private EntityManager entityManager;
private String dateFormat = "dd-MMM-yyyy";
private String timeFormat = "HH:mm:ss";
private String dateTimeFormat = "dd-MMM-yyyy HH:mm:ss";
/** The date format. */
private final String dateFormat = "dd-MMM-yyyy";
/** The time format. */
private final String timeFormat = "HH:mm:ss";
/** The date time format. */
private final String dateTimeFormat = "dd-MMM-yyyy HH:mm:ss";
/** The date formatter. */
private Format dateFormatter;
/** The date time formatter. */
private Format dateTimeFormatter;
/** The time formatter. */
private Format timeFormatter;
/**
* Instantiates a new audit trail interceptor.
*/
public AuditTrailInterceptor() {
// make synchronized local caches
ignoredClasses = Collections.synchronizedSet(new HashSet<>());
......@@ -95,7 +120,6 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
......@@ -113,8 +137,9 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
}
/**
* Explicitly set the list of classes that should be audited. Note that any class with {@link Audited} annotation
* will be included, even if not on this list.
* Explicitly set the list of classes that should be audited. Note that any
* class with {@link Audited} annotation will be included, even if not on this
* list.
*
* @param auditedClasses entity classes to audit
* @see Audited
......@@ -133,9 +158,10 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
}
/**
* Set the list of properties to ignore on all entities (e.g. "password"). Defaults to
* {@link #DEFAULT_IGNORED_PROPERTIES}. Note that you can explicitly exclude fields by annotating them with
* <code>@NotAudited</code> annotation (see {@link NotAudited}).
* Set the list of properties to ignore on all entities (e.g. "password").
* Defaults to {@link #DEFAULT_IGNORED_PROPERTIES}. Note that you can explicitly
* exclude fields by annotating them with <code>@NotAudited</code> annotation
* (see {@link NotAudited}).
*
* @param ignoredProperties entity property names to exclude from audit trail
* @see NotAudited
......@@ -173,13 +199,14 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
/*
* (non-Javadoc)
*
* @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[],
* java.lang.Object[], java.lang.String[], org.hibernate.type.Type[])
* @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.Object[],
* java.lang.String[], org.hibernate.type.Type[])
*/
/* We add more stuff to the transaction if that fails we're still good! */
@Override
public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState, final Object[] previousState, final String[] propertyNames, final Type[] types) {
public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState, final Object[] previousState, final String[] propertyNames,
final Type[] types) {
final Class<?> entityClass = entity.getClass();
if (LOG.isTraceEnabled()) {
LOG.trace("Inspecting Entity.class={} id={}", entityClass, id);
......@@ -201,7 +228,7 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
continue;
}
if (prev != null && !prev.equals(curr) || prev == null && curr != null) {
if (((prev != null) && !prev.equals(curr)) || ((prev == null) && (curr != null))) {
LOG.trace("prop={} prev={} curr={} type={}", propertyName, prev, curr, types[i].getReturnedClass());
if (isPrimitiveType(types[i].getReturnedClass())) {
......@@ -230,19 +257,28 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
return false;
}
private String formatValue(Object someValue, Type type, Class<?> entityClass, String propertyName) {
/**
* Format value.
*
* @param someValue the some value
* @param type the type
* @param entityClass the entity class
* @param propertyName the property name
* @return the string
*/
private String formatValue(final Object someValue, final Type type, final Class<?> entityClass, final String propertyName) {
if (someValue == null) {
return null;
}
Class<?> returnedClass = type.getReturnedClass();
final Class<?> returnedClass = type.getReturnedClass();
if (Date.class.equals(returnedClass) || Calendar.class.equals(returnedClass)) {
TemporalType temporalType = TemporalType.TIMESTAMP;
try {
Field field = entityClass.getDeclaredField(propertyName);
if (field != null && field.isAnnotationPresent(Temporal.class)) {
Temporal ta = field.getAnnotation(Temporal.class);
final Field field = entityClass.getDeclaredField(propertyName);
if ((field != null) && field.isAnnotationPresent(Temporal.class)) {
final Temporal ta = field.getAnnotation(Temporal.class);
temporalType = ta.value();
}
} catch (NoSuchFieldException | SecurityException e) {
......@@ -262,6 +298,12 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
return someValue.toString();
}
/**
* Checks if is entity.
*
* @param clazz the clazz
* @return true, if is entity
*/
private boolean isEntity(final Class<?> clazz) {
if (EntityId.class.isAssignableFrom(clazz)) {
return true;
......@@ -270,6 +312,12 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
return false;
}
/*
* (non-Javadoc)
* @see org.hibernate.EmptyInterceptor#onDelete(java.lang.Object,
* java.io.Serializable, java.lang.Object[], java.lang.String[],
* org.hibernate.type.Type[])
*/
@Override
public void onDelete(final Object entity, final Serializable id, final Object[] states, final String[] propertyNames, final Type[] types) {
final Class<?> entityClass = entity.getClass();
......@@ -311,11 +359,21 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
}
}
/*
* (non-Javadoc)
* @see org.hibernate.EmptyInterceptor#onCollectionRecreate(java.lang.Object,
* java.io.Serializable)
*/
@Override
public void onCollectionRecreate(final Object collection, final Serializable key) throws CallbackException {
LOG.debug("Collection recreated: key={} coll={}", key, collection);
}
/*
* (non-Javadoc)
* @see org.hibernate.EmptyInterceptor#onCollectionRemove(java.lang.Object,
* java.io.Serializable)
*/
@Override
public void onCollectionRemove(final Object collection, final Serializable key) throws CallbackException {
final PersistentCollection pc = (PersistentCollection) collection;
......@@ -348,6 +406,11 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
recordDelete(logDate, pc.getOwner(), (Long) key, propertyName, deleted.toString(), referencedEntity);
}
/*
* (non-Javadoc)
* @see org.hibernate.EmptyInterceptor#onCollectionUpdate(java.lang.Object,
* java.io.Serializable)
*/
@Override
public void onCollectionUpdate(final Object collection, final Serializable key) throws CallbackException {
final PersistentCollection pc = (PersistentCollection) collection;
......@@ -396,6 +459,13 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
recordChange(logDate, pc.getOwner(), (Long) key, propertyName, previous.toString(), remaining.toString(), referencedEntity);
}
/**
* Find property type.
*
* @param class1 the class 1
* @param propertyName the property name
* @return the class
*/
private Class<?> findPropertyType(final Class<? extends Object> class1, final String propertyName) {
LOG.trace("Finding property type for {}.{}", class1.getName(), propertyName);
......@@ -403,7 +473,7 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
final Field field = ReflectionUtils.findField(class1, propertyName);
if (field != null) {
LOG.debug("Found field: " + field + "\n\ttype=" + field.getType() + "\n\tgeneric=" + field.getGenericType() + "\n\tgenericTN=" + field.getGenericType().getTypeName());
ResolvableType t = ResolvableType.forField(field, class1);
final ResolvableType t = ResolvableType.forField(field, class1);
if (t.hasGenerics()) {
LOG.trace("\tResoved={} returning={}", t.toString(), t.resolveGeneric(0));
return t.resolveGeneric(0);
......@@ -425,6 +495,12 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
return null;
}
/**
* Convert entity id.
*
* @param previous the previous
* @return the collection
*/
private Collection<Object> convertEntityId(final Collection<?> previous) {
final Collection<Object> converted = new ArrayList<>();
for (final Object p : previous) {
......@@ -438,7 +514,7 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
}
/**
* Checks if class is a "primitive"
* Checks if class is a "primitive".
*
* @param class1 the property class
* @return true, if is primitive
......@@ -469,11 +545,32 @@ public class AuditTrailInterceptor extends EmptyInterceptor implements Initializ
return false;
}
/**
* Record change.
*
* @param logDate the log date
* @param entity the entity
* @param id the id
* @param propertyName the property name
* @param previousState the previous state
* @param currentState the current state
* @param referencedEntity the referenced entity
*/
private void recordChange(final Date logDate, final Object entity, final Long id, final String propertyName, final String previousState, final String currentState,
final Class<?> referencedEntity) {
auditTrailService.recordChange(logDate, entity, id, propertyName, previousState, currentState, referencedEntity);
}
/**
* Record delete.
*
* @param logDate the log date
* @param entity the entity
* @param id the id
* @param propertyName the property name
* @param state the state
* @param referencedEntity the referenced entity
*/
private void recordDelete(final Date logDate, final Object entity, final Long id, final String propertyName, final String state, final Class<?> referencedEntity) {
auditTrailService.recordDelete(logDate, entity, id, propertyName, state, referencedEntity);
}
......
......@@ -15,6 +15,13 @@
*/
package org.genesys.blocks.auditlog.model;
/**
* The Enum AuditAction.
*/
public enum AuditAction {
UPDATE, DELETE
/** The update. */
UPDATE,
/** The delete. */
DELETE
}
......@@ -45,6 +45,7 @@ import org.springframework.data.annotation.CreatedBy;
@NotAudited
public class AuditLog implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -2254427722756061411L;
/** The id. */
......@@ -53,41 +54,44 @@ public class AuditLog implements Serializable {
@Column(nullable = false, length = 20)
protected Long id;
/** The created by. */
@CreatedBy
private Long createdBy;
/** The log date. */
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "logdate", nullable = false)
private Date logDate;
/** Class name of the referenced entity */
/** Class name of the referenced entity. */
@ManyToOne(optional = false)
@JoinColumn(name = "classPk")
private ClassPK classPk;
/** ID of the referenced entity */
/** ID of the referenced entity. */
@Column(name = "entityId")
private long entityId;
/** The name of the property modified */
/** The name of the property modified. */
@Column(nullable = false, name = "prop", length = 50)
private String propertyName;
/** The type of entity referenced in the changed property */
/** The type of entity referenced in the changed property. */
@ManyToOne(optional = true)
@JoinColumn(name = "entityClassPk")
private ClassPK referencedEntity;
/** String representation of the previous state */
/** String representation of the previous state. */
@Lob
@Column(nullable = true)
private String previousState;
/** String representation of the updated state */
/** String representation of the updated state. */
@Lob
@Column(nullable = true)
private String newState;
/** The action. */
@Enumerated(EnumType.STRING)
@Column(length = 10, nullable = false, updatable = false)
private AuditAction action;
......@@ -254,10 +258,20 @@ public class AuditLog implements Serializable {
return newState;
}
/**
* Sets the action.
*
* @param action the new action
*/
public void setAction(final AuditAction action) {
this.action = action;
}
/**
* Gets the action.
*
* @return the action
*/
public AuditAction getAction() {
return action;
}
......
/*
* Copyright 2017 Global Crop Diversity Trust
*
* 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 org.genesys.blocks.auditlog.model.filters;
import java.util.Set;
......@@ -11,16 +26,33 @@ import org.genesys.blocks.auditlog.model.QAuditLog;
import org.genesys.blocks.model.filters.DateFilter;
/**
* Search filter
* Search filter.
*/
public class AuditLogFilter {
/** The classname. */
public String classname;
/** The entity id. */
public Long entityId;
/** The created by. */
public Set<Long> createdBy;
/** The action. */
public Set<AuditAction> action;
/** The property name. */
public Set<String> propertyName;
/** The log date. */
public DateFilter logDate;
/**
* Builds the query.
*
* @return the predicate
*/
public Predicate buildQuery() {
final BooleanBuilder and = new BooleanBuilder();
if (classname != null) {
......
......@@ -23,12 +23,42 @@ import org.genesys.blocks.model.EntityId;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
/**
* The Interface AuditLogCustomRepository.
*/
public interface AuditLogCustomRepository {
/**
* List audit logs.
*
* @param entity the entity
* @return the list
*/
List<AuditLog> listAuditLogs(EntityId entity);
/**
* Gets the last audit log.
*
* @param entity the entity
* @return the last audit log
*/
AuditLog getLastAuditLog(EntityId entity);
/**
* Gets the last audit log.
*
* @param entity the entity
* @param propertyName the property name
* @return the last audit log
*/
AuditLog getLastAuditLog(EntityId entity, String propertyName);
/**
* List audit logs.
*
* @param filters the filters
* @param page the page
* @return the page
*/
Page<AuditLog> listAuditLogs(AuditLogFilter filters, Pageable page);
}
......@@ -33,13 +33,36 @@ import org.springframework.stereotype.Repository;
@Repository
public interface AuditLogRepository extends AuditLogCustomRepository, JpaRepository<AuditLog, Long>, QueryDslPredicateExecutor<AuditLog> {
/** List audit log entries in descending order (most recent first) */
/**
* List audit log entries in descending order (most recent first).
*
* @param classname the classname
* @param entityId the entity id
* @return the list
*/
@Query("select al from AuditLog al where al.entityId = ?2 and al.classPk.classname = ?1 order by al.logDate desc")
List<AuditLog> listAuditLogs(String classname, Serializable entityId);
/**
* List audit logs.
*
* @param name the name
* @param id the id
* @param page the page
* @return the list
*/
@Query("select al from AuditLog al where al.entityId = ?2 and al.classPk.classname = ?1 order by al.logDate desc")
List<AuditLog> listAuditLogs(String name, Serializable id, Pageable page);
/**
* List audit logs.
*
* @param name the name
* @param id the id
* @param propertyName the property name
* @param page the page
* @return the list
*/
@Query("select al from AuditLog al where al.entityId = ?2 and al.classPk.classname = ?1 and al.propertyName = ?3 order by al.logDate desc")
List<AuditLog> listAuditLogs(String name, Serializable id, String propertyName, Pageable page);
......
......@@ -32,26 +32,48 @@ import org.springframework.data.domain.Pageable;
*/
public class AuditLogRepositoryCustomImpl implements AuditLogCustomRepository {
/** The repository. */
@Autowired
private AuditLogRepository repository;
/*
* (non-Javadoc)
* @see org.genesys.blocks.auditlog.persistence.AuditLogCustomRepository#
* listAuditLogs(org.genesys.blocks.model.EntityId)
*/
@Override
public List<AuditLog> listAuditLogs(final EntityId entity) {
return repository.listAuditLogs(entity.getClass().getName(), entity.getId());
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.auditlog.persistence.AuditLogCustomRepository#
* getLastAuditLog(org.genesys.blocks.model.EntityId)
*/
@Override
public AuditLog getLastAuditLog(final EntityId entity) {
final List<AuditLog> l = repository.listAuditLogs(entity.getClass().getName(), entity.getId(), new PageRequest(0, 1));
return l == null || l.isEmpty() ? null : l.get(0);
return (l == null) || l.isEmpty() ? null : l.get(0);
}
/*
* (non-Javadoc)
* @see org.genesys.blocks.auditlog.persistence.AuditLogCustomRepository#
* getLastAuditLog(org.genesys.blocks.model.EntityId, java.lang.String)
*/
@Override
public AuditLog getLastAuditLog(final EntityId entity, final String propertyName) {
final List<AuditLog> l = repository.listAuditLogs(entity.getClass().getName(), entity.getId(), propertyName, new PageRequest(0, 1));
return l == null || l.isEmpty() ? null : l.get(0);
return (l == null) || l.isEmpty() ? null : l.get(0);
}
/*
* (non-Javadoc)