/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.intel.mtwilson.audit.handler;
import com.intel.mtwilson.audit.annotations.AuditIgnore;
import com.intel.mtwilson.audit.api.AuditLogger;
//import com.intel.mtwilson.audit.helper.AuditConfig;
import com.intel.mtwilson.audit.helper.AuditEntryType;
import com.intel.mtwilson.audit.helper.AuditHandlerException;
import com.intel.mtwilson.audit.data.AuditColumnData;
import com.intel.mtwilson.audit.data.AuditLog;
import com.intel.mtwilson.audit.data.AuditTableData;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Id;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
//import org.codehaus.jackson.JsonGenerationException;
//import org.codehaus.jackson.map.JsonMappingException;
//import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.DescriptorEventAdapter;
import org.eclipse.persistence.queries.WriteObjectQuery;
import org.eclipse.persistence.sessions.changesets.ChangeRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* NOTE: this class is attached to ASData/MSData objects through the DescriptorCustomizer
* defined in audit-api; it loads this class at runtime to attach as a listener.
*
* @author dsmagadx
*/
public class AuditEventHandlerImpl extends DescriptorEventAdapter {
private static Logger log = LoggerFactory.getLogger(AuditEventHandlerImpl.class);
private static boolean isAuditEnabled = true;
private static boolean isUnchangedColumnsRequired = true;
static{
isAuditEnabled = true; // AuditConfig.isAuditEnabled();
isUnchangedColumnsRequired = false; // AuditConfig.isUnchangedColumnsRequired();
log.debug("Audit - {}",isAuditEnabled );
log.debug("Log Unchanged Columns - {}",isUnchangedColumnsRequired);
}
/*
* Get the security context
*/
private static ObjectMapper mapper = new ObjectMapper();
private AuditColumnData getAuditColumnData(Column col, Field field, Object table, HashMap<String, Object> changedColumns) throws IllegalAccessException, IllegalArgumentException, SecurityException {
AuditColumnData auditColumnData = new AuditColumnData();
log.trace("Column: " + col.name());
auditColumnData.setName(col.name());
log.trace("Field: " + field.getName());
field.setAccessible(true);
log.trace("Value: " + field.get(table));
auditColumnData.setValue(field.get(table));
field.setAccessible(false);
auditColumnData.setIsUpdated(changedColumns.containsKey(field.getName()));
return auditColumnData;
}
@Override
public void postDelete(DescriptorEvent event) {
handleEvent(AuditEntryType.DELETE.toString(), event);
}
@Override
public void postInsert(DescriptorEvent event) {
handleEvent(AuditEntryType.CREATE.toString(), event);
}
@Override
public void postUpdate(DescriptorEvent event) {
handleEvent(AuditEntryType.UPDATE.toString(), event);
}
private void handleEvent(String action,
DescriptorEvent event) {
log.trace("Thread: {}",Thread.currentThread().getName());
if(isAuditEnabled){
try {
log.trace("Action: " + action);
log.trace("Class: " + event.getObject());
AuditLog auditLog = getAuditLog(event,action);
if(auditLog != null)
new AuditLogger().addLog(auditLog);
} catch (Exception ex) {
log.error("Error while generating json :", new AuditHandlerException(ex));
}
}
}
private AuditTableData getTableData(DescriptorEvent event) throws IllegalAccessException, IllegalArgumentException, SecurityException {
AuditTableData auditTableData = new AuditTableData();
Object table = event.getObject();
HashMap<String, Object> changedColumns = getChangedColumns(event);
for (Field field : table.getClass().getDeclaredFields()) {
Column col;
log.trace("Is it required to log this column {}" , field.isAnnotationPresent(AuditIgnore.class));
if ((col = field.getAnnotation(Column.class)) != null && !field.isAnnotationPresent(AuditIgnore.class)){
if(isUnchangedColumnsRequired || event.getEventCode() != 7){ // Log all columns
auditTableData.getColumns().add(getAuditColumnData(col, field, table, changedColumns));
}else if(changedColumns.containsKey(field.getName())){ // log only changed colmuns
auditTableData.getColumns().add(getAuditColumnData(col, field, table, changedColumns));
}
}
}
return auditTableData;
}
private HashMap<String, Object> getChangedColumns(DescriptorEvent event) {
HashMap<String, Object> changedColumns = new HashMap<String, Object>();
if(event.getEventCode() == 7){
WriteObjectQuery query = (WriteObjectQuery) event.getQuery();
List<ChangeRecord> changes = query.getObjectChangeSet().getChanges();
for (ChangeRecord change : changes) {
log.debug("Change: " + change.getAttribute() + " " + change.getOldValue());
changedColumns.put(change.getAttribute(), change.getOldValue());
}
}
return changedColumns;
}
private AuditLog getAuditLog(DescriptorEvent event, String action) throws IllegalAccessException,
IllegalArgumentException,
SecurityException,
JsonGenerationException,
JsonMappingException,
IOException
{
AuditLog auditLog = new AuditLog();
auditLog.setEntityType(event.getObject().getClass().getSimpleName());
AuditTableData auditTableData = getTableData(event);
if(auditTableData.getColumns().size() > 0){
auditLog.setData(mapper.writeValueAsString(auditTableData));
auditLog.setEntityId(getPrimaryKey(event));
auditLog.setAction(action);
return auditLog;
}else{
log.info("No Columns changed. Returning null");
return null;
}
}
private Integer getPrimaryKey(DescriptorEvent event) throws IllegalArgumentException, IllegalAccessException {
Integer pk = -1;
Object table = event.getObject();
for (Field field : table.getClass().getDeclaredFields()) {
if ((field.getAnnotation(Id.class)) != null) {
log.trace("ID Column Field: " + field.getName());
field.setAccessible(true);
log.trace("ID Data Type :" + field.getType() + "value: " + field.get(table));
pk = (Integer) field.get(table);
field.setAccessible(false);
}
}
return pk;
}
}