Conditional Envers Auditing
Asked Answered
P

5

10

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

Pointed answered 10/1, 2013 at 3:57 Comment(6)
And what happens currently? Is your custom integrator code called at all?Bister
@adamw: I have added sysout statements to integrator code, but none of them are appearing. It seems Services are not recognized by JBOSS. I have created project using Eclipse 4.2 Juno as Dynamic Web project. Not sure whether Location of META-INF is correct. Any advice..Pointed
Did you check the resulting jar/war, if it has the file in the correct place?Bister
@Adamw, Sorry for delayed reply, Yes META-INF is located in WAR file at G:\jboss-as-web-7.0.2.Final\standalone\deployments\sample.war\META-INF\services\Pointed
And the classes are directly in the war as well, not in a .jar?Bister
Hi Shirish, were you able to solve the problem?Electropositive
M
13

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

Malaco answered 28/3, 2019 at 15:51 Comment(0)
T
1

Try to place integrator file into:

sample.war\WEB-INF\classes\META-INF\services\...
Troopship answered 4/2, 2014 at 13:59 Comment(0)
M
0

Maybe...

In my case, I use Maven, and I had to include in the pom.xml, the following line : <include>**/*.Integrator</include>, because the file was not packaged in the .ear.

My pom.xml:

<resources>
       <resource>
           <directory>src/main/resources</directory>
           <filtering>true</filtering>
           <includes>
                <include>**/*.xml</include>
               <include>**/*.Integrator</include>
           </includes>
       </resource>
       ...
Mirage answered 11/5, 2015 at 20:38 Comment(0)
D
0

creating a file org.hibernate.integrator.spi.Integrator (containing the qualified name of my custom integrator) in a folder META-INF/services/ under src/main/resources of my maven project made my custom integrator code be called.

Djambi answered 6/5, 2016 at 13:34 Comment(0)
S
0

@ComponentScan(basePackages = {"com.example.demo"}, lazyInit = true)

Adding lazyInit = true, triggered the custom integrator for me.

Spittoon answered 25/10, 2018 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.