AuditVersionListener.java

  1. package no.nav.data.common.auditing;

  2. import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
  3. import com.fasterxml.jackson.annotation.PropertyAccessor;
  4. import com.fasterxml.jackson.core.JsonGenerator;
  5. import com.fasterxml.jackson.core.JsonProcessingException;
  6. import com.fasterxml.jackson.databind.ObjectWriter;
  7. import com.fasterxml.jackson.databind.SerializerProvider;
  8. import com.fasterxml.jackson.databind.ser.FilterProvider;
  9. import com.fasterxml.jackson.databind.ser.PropertyWriter;
  10. import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
  11. import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
  12. import jakarta.persistence.Entity;
  13. import jakarta.persistence.PrePersist;
  14. import jakarta.persistence.PreRemove;
  15. import jakarta.persistence.PreUpdate;
  16. import lombok.extern.slf4j.Slf4j;
  17. import no.nav.data.common.auditing.domain.Action;
  18. import no.nav.data.common.auditing.domain.AuditVersion;
  19. import no.nav.data.common.auditing.domain.AuditVersionRepository;
  20. import no.nav.data.common.auditing.domain.Auditable;
  21. import no.nav.data.common.storage.domain.GenericStorage;
  22. import no.nav.data.common.utils.HibernateUtils;
  23. import no.nav.data.common.utils.JsonUtils;
  24. import no.nav.data.common.utils.MdcUtils;
  25. import org.hibernate.proxy.HibernateProxy;
  26. import org.springframework.util.Assert;

  27. import java.util.Optional;
  28. import java.util.UUID;

  29. import static no.nav.data.common.storage.domain.TypeRegistration.isAudited;

  30. @Slf4j
  31. public class AuditVersionListener {

  32.     private static AuditVersionRepository repository;

  33.     private static final ObjectWriter wr;

  34.     static {
  35.         FilterProvider filters = new SimpleFilterProvider().addFilter("relationFilter", new RelationFilter());
  36.         var om = JsonUtils.createObjectMapper();
  37.         om.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
  38.         om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
  39.         wr = om.writer(filters);
  40.     }

  41.     public static void setRepo(AuditVersionRepository repository) {
  42.         AuditVersionListener.repository = repository;
  43.     }

  44.     @PrePersist
  45.     public void prePersist(Object entity) {
  46.         audit(entity, Action.CREATE);
  47.     }

  48.     @PreUpdate
  49.     public void preUpdate(Object entity) {
  50.         audit(entity, Action.UPDATE);
  51.     }

  52.     @PreRemove
  53.     public void preRemove(Object entity) {
  54.         audit(entity, Action.DELETE);
  55.     }

  56.     private void audit(Object entity, Action action) {
  57.         Assert.isTrue(entity instanceof Auditable, "Invalid object");
  58.         if (entity instanceof GenericStorage gs && !isAudited((gs).getType())) {
  59.             return;
  60.         }
  61.         AuditVersion auditVersion = convertAuditVersion(entity, action);
  62.         if (auditVersion != null) {
  63.             repository.save(auditVersion);
  64.         }
  65.     }

  66.     public static AuditVersion convertAuditVersion(Object entity, Action action) {
  67.         try {
  68.             String tableName;
  69.             if (entity instanceof GenericStorage gs) {
  70.                 tableName = gs.getType();
  71.             } else {
  72.                 tableName = AuditVersion.tableName(((Auditable) entity).getClass());
  73.             }
  74.             String id = getIdForObject(entity);
  75.             String data = wr.writeValueAsString(entity);
  76.             String user = Optional.ofNullable(MdcUtils.getUser()).orElse("no user set");
  77.             return AuditVersion.builder()
  78.                     .action(action).table(tableName).tableId(id).data(data).user(user)
  79.                     .build();
  80.         } catch (JsonProcessingException e) {
  81.             log.error("failed to serialize object", e);
  82.             return null;
  83.         }
  84.     }

  85.     public static String getIdForObject(Object entity) {
  86.         UUID uuid = HibernateUtils.getId(entity);
  87.         Assert.notNull(uuid, "entity has not set id");
  88.         return uuid.toString();
  89.     }

  90.     private static class RelationFilter extends SimpleBeanPropertyFilter {

  91.         @Override
  92.         public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
  93.             boolean root = jgen.getOutputContext().getParent().getParent() == null;
  94.             boolean isEntity = pojo.getClass().isAnnotationPresent(Entity.class) || pojo instanceof HibernateProxy;
  95.             if (root || !isEntity) {
  96.                 super.serializeAsField(pojo, jgen, provider, writer);
  97.             } else {
  98.                 String fieldName = writer.getName();
  99.                 if (fieldName.equals("id")) {
  100.                     UUID id = HibernateUtils.getId(pojo);
  101.                     jgen.writeFieldName(fieldName);
  102.                     jgen.writeString(id.toString());
  103.                 }
  104.             }
  105.         }
  106.     }
  107. }