All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.thksystems.persistence.hibernate.immutable.ImmutableCheckInterceptor Maven / Gradle / Ivy

/*
 * tksCommons / mugwort
 * 
 * Author : Thomas Kuhlmann (ThK-Systems, http://oss.thk-systems.de) License : LGPL (https://www.gnu.org/licenses/lgpl.html)
 */
package de.thksystems.persistence.hibernate.immutable;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Date;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

/**
 * Checks the immutablity of entities.
 * 

* The interceptor must be registered!! * * @author Thomas Kuhlmann (kuhl025), arvato D1CS, extern */ public class ImmutableCheckInterceptor extends EmptyInterceptor { private static final long serialVersionUID = -298527553545916632L; private static final Logger LOG = LoggerFactory.getLogger(ImmutableCheckInterceptor.class); /** * Checks the immutablity of entities. * * @throws IllegalModifactionException * in case of an illegal modification. * @see org.hibernate.EmptyInterceptor#onFlushDirty(java.lang.Object, java.io.Serializable, java.lang.Object[], java.lang.Object[], java.lang.String[], org.hibernate.type.Type[]) */ @Override public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { boolean modified = false; // Check for Immutable annoation if (AnnotationUtils.findAnnotation(entity.getClass(), Immutable.class) != null) { // For every property for (int i = 0; i < propertyNames.length; i++) { // Check for modification if (!checkForModification(currentState[i], previousState[i])) { // Get modified field Field field = ReflectionUtils.findField(entity.getClass(), propertyNames[i]); // Check if modification is allowed or illegal if (!checkModificationAllowed(field, previousState[i])) { // Throwing an (even runtime-) exception is not allowed here and leaves persistence in a very inconsistent state. String msg = String.format("ILLEGAL MODIFICATION ATTEMPT: %s[%s].%s: %s -> %s", entity.getClass(), id, propertyNames[i], previousState[i], currentState[i]); LOG.error(msg); // Revert modification currentState[i] = previousState[i]; modified = true; } } } } return modified; } private boolean checkForModification(Object currentState, Object previousState) { if (currentState == null && previousState == null) { return true; } if (currentState instanceof Date) { return ((Date) currentState).getTime() == ((Date) previousState).getTime(); } return currentState != null && currentState.equals(previousState); } /** * Returns true, if modification is allowed. */ private boolean checkModificationAllowed(Field field, Object previous) { Mutable mutableAnnotation = findMutableAnnotation(field); // No Mutable annotation -> Illegal modification if (mutableAnnotation == null) { return false; } // If finall, previous value must be null, otherwise it is a illegal modification if (mutableAnnotation.finall()) { return previous == null; } // Mutable annotation is present and not finall. -> Allowed modification. return true; } /** * Returns the {@link Mutable} anntotation for the {@link Field}, or null, if not found. */ private Mutable findMutableAnnotation(Field field) { for (Annotation annotation : field.getDeclaredAnnotations()) { if (annotation instanceof Mutable) { return (Mutable) annotation; } } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy