There are lots of samples in internet creating audit data for hibernate with Interceptors.
With these samples (maybe I missed some of them) you do not know the order of changes.
We needed to know the order for some reasons.
Luckily our hibernate code was generated with a tool we wrote. We put a method as 1st
line in our setter methods. We were calling a method to understand if this field is changed.
(By this way u can also get full path (stacktrace) of change )
public class User {
public void setPersonel( YPerson personel )
{
this.setEditedFieldValue( "personel", this.personel, personel, true ) ;
this.personel = personel ;
}
public void setCode( String code )
{
this.setEditedFieldValue( "code", this.code, code, true ) ;
this.code = code ;
}
}
Below is the generic code to check if field is changed.
There are cases like
1)Object created with new,we are assigning necessary fields (You do not need to keep ,
because objects former values are null before creation so if an object does not have any audit data,it is same from beginning)
2)Object is being read from database ( We are attaching object so all values will seem null,be careful)
Hibernate creates object with null constructor and calls setters.
3)Object attached , in the flow we changed a field.
protected void setEditedFieldValue( String fieldName, Object oldValue, Object newValue, boolean isNullable )
{
//Beans can override isIntercepted method to skip being audited
if( !this.isIntercepted( ) )
{
return ;
}
//Do not need to audit initially null ones, or you can skip at time of attaching
if( oldValue == null )
{
return ;
}
//for not null int values our code has 0. So if something is not nullable (we know at time of code generation )
// but it is 0 it means null for us return without auditing
if( !isNullable )
{
if( ( oldValue instanceof Integer ) && ( ( Integer )oldValue ).intValue( ) == 0 )
{
return ;
}
if( ( oldValue instanceof BigDecimal ) && ( ( BigDecimal )oldValue ).compareTo( BigDecimal.ZERO ) == 0 )
{
return ;
}
}
//Do not audit if value did not change,
//Example : You opened edit page, change some values and some not.So audit only changed ones.
if( oldValue == newValue )
{
return ;
}
if( oldValue instanceof YBean )
{
String oldDisp = "[N/A]" ;
String newDisp = "[N/A]" ;
if( YServerConstants.IS_AUDIT_DEBUG_MODE )
{
//want to know when if beans are proxy or no.
if( HibernateUtils.isproxy( ( YBean )oldValue ) )
{
oldDisp = "##BeanProxy##;" + oldValue.getClass( ).getSimpleName( ) + "; id:" + ( ( YBean )oldValue ).getId( ) ;
}
else
{
oldDisp = "##YBean##;" + ( ( YBean )oldValue ).getInstanceBeanName( ) + "; id:" + ( ( YBean )oldValue ).getId( ) + "; disp:" + ( ( YBean )oldValue ).getShortDisplay( ) ;
}
if( newValue != null )
{
if( HibernateUtils.isproxy( ( YBean )newValue ) )
{
newDisp = "##BeanProxy##;" + newValue.getClass( ).getSimpleName( ) + "; id:" + ( ( YBean )newValue ).getId( ) ;
}
else
{
newDisp = "##YBean##;" + ( ( YBean )newValue ).getInstanceBeanName( ) + "; id:" + ( ( YBean )newValue ).getId( ) + "; disp:" + ( ( YBean )newValue ).getShortDisplay( ) ;
}
}
if( !oldDisp.equals( newDisp ) )
{
if( this._editedFieldValuesPool == null )
{
this._editedFieldValuesPool = new YAuditFieldNameValuePairPool( ) ;
}
this._editedFieldValuesPool.setFieldValue( fieldName, oldDisp ) ;
}
}
}
else
{
//We do not know if any of objects are null so can not call , o1.equals(02)
if( isObjectEquals( oldValue, newValue ) )
{
return ;
}
if( this._editedFieldValuesPool == null )
{
this._editedFieldValuesPool = new YAuditFieldNameValuePairPool( ) ;
}
this._editedFieldValuesPool.setFieldValue( fieldName, oldValue ) ;
}
}
public static boolean isObjectEquals( Object o1, Object o2 )
{
if( o1 == o2 )
{
return true ;
}
if( o1 == null || o2 == null )
{
return false ;
}
return o1.equals( o2 ) ;
}
//This class is holding audit data. Since audits are hold at Arraylist you do not loose order.
//Also you can even add stack traces with conditions to monitor your system.
public class YAuditFieldNameValuePairPool implements Serializable
{
protected ArrayList<String> nameList = new ArrayList<String>( 0 ) ;
protected ArrayList<Object> valueList = new ArrayList<Object>( 0 ) ;
public int setFieldValue( String fieldName, Object value )
{
boolean isFound = false ;
//check If you have same record do not save again
//This is a decision you can think this is usefull to see if
//a change is being applied mutiple time.
for( int i = this.nameList.size( ) - 1; i >= 0; --i )
{
String name = this.nameList.get( i ) ;
Object val = this.valueList.get( i ) ;
if( name.equals( fieldName ) )
{
if( YClientUtils.isObjectEquals( value, val ) )
{
isFound = true ;
break ;
}
}
}
if( !isFound )
{
this.nameList.add( fieldName ) ;
this.valueList.add( value ) ;
return this.nameList.size( ) - 1 ;
}
return -1 ;
}
No comments:
Post a Comment