Envers-style Auditing in DataNucleus?


ebenzacar@...
 

I'm evaluating DataNucleus as a JDO implementation vs a Hibernate JPA implementation.  On of the big selling points that Hibernate provides is the Hibernate-Envers (https://hibernate.org/orm/envers/) library to automatically keep an audit of Entity changes, including some contextual information (ex: who made the change, etc).

I would like to provide a similar style functionality using DataNucleus as my JDO implementation.  Does any similar functionality exist either as part of DN or as a third party extension/plugin that I can leverage?

Thanks,

Eric


Andy
 

Neither JDO nor JPA provide any standardised "auditing" capability.

DataNucleus provides first level support for auditing only, namely the ability to tag the create / update user/timestamp against each record, as per this link.

To provide second level support for auditing (being able to see records at particular points in time, to see what was updated in which change, etc) that would presumably require an audit table for each persistable entity table. It would require a definition of what the handling would be, and an implementation. Presumably you would only be looking at supporting it for RDBMS datastores.


ebenzacar@...
 

I would suspect non RDBMS would also be supportable.  Concept being that each time an object is modified, the dirty fields of the given object (before and after) are persisted in a document/table, with any custom contextual information that can be provided to the persistence manager.  

Envers essentially provides this behaviour by creating separate tables in a different connection/database to track changes to given entities.  I realize that JPA/JDO do not specify any of this, but was wondering if there was an easy way to create/implement something like this with DataNucleus.  I would essentially see if as putting a listener on the 'commit' phase, checking for dirty fields, and persisting the change of the fields with the object identifier in a table/document.  My immediate use case is RDBMS, but NOSQL could be interesting to support as well.

My problem is multi-fold.
1) I'm not sure how to put a listener on any 'commit'.  Rather, there seems to be separate listeners for 'create', 'update', 'delete'.
2) Once the listener triggers, I'm not sure how to retrieve which fields are 'dirty'.  I see there is a `JDOStateManager`, but not sure how to access it from an `InstanceLifecycleEvent`.  I suspect it must be from a `getPersistentInstance()` but I cannot seem to find a helper method anywhere that retrieves a `JDOStateManager`.
3) Even once I am able to get the dirty fields via the `JDOStateManager`, I do not know how to retrieve the original value of the field without needing to re-read the object from the DB

Any suggestions would be greatly appreciated.

Thanks,

Eric


Andy
 
Edited

I can't say there'll be an easy way of doing any of this. You have to create separate tables, hence table creation handling. You have to intercept inserts, updates, deletes hence persistence handling. You have to provide a way of retrieval of objects of a particular revision hence new API calls.

First step is to define what tables would be created, mentioning how relations will be handled / stored. Without an outline "design" of what is required and whether that caters for all needs then there is little point in doing further. You could create an issue (datanucleus-core plugin for example) and write the details there, giving examples, persistable class X with 1-N join table relation to persistable class Y, so what tables are created, what is entered in these tables with sample persistence operations etc.

All persistable objects are of type Persistable. That has dnGetStateManager.

But then there may not be adequate callbacks to do all that is needed and it could be better to have an Audit interface with suitable methods on it, and an implementation for each datastore that it is required for. StateManagerImpl has a savedLoadedFields/savedImage which would have "old" values, but then why you would need them I don't get. But your design would demonstrate what is needed and why.