Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional Envers Auditing

I have a requirement where I want to audit records only on change of Status field. I've followed documentation chapter tutorial "15.8. Conditional auditing".

Step 1: Turn off automatic Envers event listeners registration. I have following:

<prop key="hibernate.listeners.envers.autoRegister">false</prop>

Step 2: Create subclasses for appropriate event listeners.

public class DeleteEnversListener extends EnversPostDeleteEventListenerImpl {   
    private static final long serialVersionUID = 5906427978349712224L;
    private static Log log = LogFactory.getLog(DeleteEnversListener.class);

    public DeleteEnversListener(AuditConfiguration enversConfiguration) {
        super(enversConfiguration);
    }

    @Override
    public void onPostDelete(PostDeleteEvent event) {
        log.info("!!! just logging entity !! "+ event.getEntity());
        super.onPostDelete(event);
    }   
}

In similar way, I have

  • InsertEnversListener
  • UpdateEnversListener
  • DeleteEnversListener
  • CollectionRecreateEnversListener
  • PreCollectionRemoveEnversListener
  • PreCollectionUpdateEnversListener

Step 3: Create your own implementation of org.hibernate.integrator.spi.Integrator

public class CustomEnversIntegrator extends EnversIntegrator   {

    private static Log log = LogFactory.getLog(CustomEnversIntegrator.class);

    @Override
    public void integrate(Configuration configuration,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {

        super.integrate(configuration, sessionFactory, serviceRegistry);
        final AuditConfiguration enversConfiguration = AuditConfiguration.getFor( configuration, serviceRegistry.getService( ClassLoaderService.class ) );
        EventListenerRegistry listenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );

        System.out.println("Registering event listeners");
        if (enversConfiguration.getEntCfg().hasAuditedEntities()) {
            listenerRegistry.appendListeners(EventType.POST_INSERT, new InsertEnversListener(enversConfiguration));
            listenerRegistry.appendListeners(EventType.POST_UPDATE, new UpdateEnversListener(enversConfiguration));
            listenerRegistry.appendListeners(EventType.POST_DELETE, new DeleteEnversListener(enversConfiguration ) );
            listenerRegistry.appendListeners(EventType.POST_COLLECTION_RECREATE, new CollectionRecreateEnversListener(enversConfiguration ) );
            listenerRegistry.appendListeners(EventType.PRE_COLLECTION_REMOVE, new PreCollectionRemoveEnversListener(enversConfiguration ) );
            listenerRegistry.appendListeners(EventType.PRE_COLLECTION_UPDATE, new PreCollectionUpdateEnversListener(enversConfiguration ) );
        }

    }
}

Step 4: For the integrator to be automatically used when Hibernate starts up, you will need to add a META-INF/services/org.hibernate.integrator.spi.Integrator file. Here is content of org.hibernate.integrator.spi.Integrator file

com.hib.sample.listener.CustomEnversIntegrator

I am not sure, if I am missing anything. I am using JBOSS AS 7.0 with Hibernate 4.1.8

like image 507
Shirish Bathe Avatar asked Jan 10 '13 03:01

Shirish Bathe


People also ask

What is conditional auditing?

With the conditional audit, you can configure what to filter without programming. The conditional audit uses a filtering configuration, which is a filtering rule, consisting of conditional audit groups. An audit group consists of a hierarchy of logically related types and an auditing condition.

What is @NotAudited?

NotAudited means "I just don't care for this field in historical data" (it won't be saved, relationship will be null, you won't see it when looking historical data about CustomerBooking ) Follow this answer to receive notifications.


2 Answers

Here is a Spring-only solution for the conditional Envers auditing without an ugly META-INF folder etc. All what you need is a bean in your configuration class and a CustomEnversEventListener.

@Bean
public EventListenerRegistry listenerRegistry(EntityManagerFactory entityManagerFactory) {
    ServiceRegistryImplementor serviceRegistry = entityManagerFactory.unwrap(SessionFactoryImpl.class).getServiceRegistry();

    final EnversService enversService = serviceRegistry.getService(EnversService.class);
    EventListenerRegistry listenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);

    listenerRegistry.setListeners(EventType.POST_UPDATE, new CustomEnversEventListener(enversService));
    return listenerRegistry;
  }

and

  public class CustomEnversEventListener extends EnversPostUpdateEventListenerImpl {

    CustomEnversEventListener(EnversService enversService) {
      super(enversService);
    }

    @Override
    public void onPostUpdate(PostUpdateEvent event) {

      // custom conditional stuff

      super.onPostUpdate(event);
    }
  }

If you want to customise only one listener i.e. EnversPostUpdateEventListener, you don't need to disable hibernate.listeners.envers.autoRegister in order to let Envers register the other listener.

Then you can override Envers listeners by listenerRegistry.setListeners or append by listenerRegistry.appendListeners

like image 162
Peyman Avatar answered Oct 12 '22 23:10

Peyman


Try to place integrator file into:

sample.war\WEB-INF\classes\META-INF\services\...
like image 35
Paweł Kaczorowski Avatar answered Oct 12 '22 23:10

Paweł Kaczorowski