/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package framework.audit;
import framework.beans.BaseEntity;
import framework.beans.GenericEntity;
import framework.beans.collaborator.CollaboratorAbstract;
import framework.generic.ClipsServerException;
import framework.generic.HasEntityInfo;
import framework.utils.Converter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.JoinColumn;
import org.jdom.JDOMException;
import reportgen.cores.ejb.annotations.DefineQueryEntity;
import reportgen.cores.ejb.annotations.DefineQueryProperty;
/**
*
* @author vip
*/
public class AuditDoc<GEN extends BaseEntity> {
private String value;
private String title;
private EntityValue oldValues;
public CollaboratorAbstract collab;
private Date date;
private String className;
private Integer id;
private Map<String, String> xmlFormat = new HashMap<String, String>();
private String nameEntity;
private boolean checked;
boolean changed;
public AuditDoc(GEN old, CollaboratorAbstract collab) throws ClipsServerException {
boolean isNew = false;
if (old == null) {
isNew = true;
}
if (old instanceof GenericEntity && ((GenericEntity)old).getId() == 0) {
isNew = true;
}
//Запомним старые значения
if (isNew) {
oldValues = null;
} else {
Class aClass = old.getClass();
if (aClass.isAnnotationPresent(DefineQueryEntity.class)) {
DefineQueryEntity annotation = (DefineQueryEntity) aClass.getAnnotation(DefineQueryEntity.class);
nameEntity = annotation.title();
} else {
nameEntity = aClass.getSimpleName();
}
className = old.getClass().getSimpleName();
oldValues = getValues(old);
id = oldValues.id;
}
this.collab = collab;
this.date = new Date();
}
private EntityValue getValues(GEN old) throws ClipsServerException {
EntityValue entityValue = new EntityValue(getValueOfField(old, null));
HashMap<Field, Method> methodMap = getMethodMap(old == null ? null : old.getClass());
Set<Entry<Field, Method>> entrySet = methodMap.entrySet();
for (Entry<Field, Method> entry : entrySet) {
try {
Field field = entry.getKey();
String metaData = xmlFormat.get(field.getName());
Method method = entry.getValue();
method.setAccessible(true);
String valueOfField = getValueOfField(method.invoke(old), metaData);
entityValue.put(entry.getKey(), valueOfField);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
if (old instanceof GenericEntity) {
entityValue.id = ((GenericEntity)old).getId();
}
return entityValue;
}
/**
* Вызывается при удалении чекапов, передается старая сущность для
* запоминания старых значений на основе старого значения сущности и метаданных.
* Вообщето для всех нормальных способов старые значения запоминаются в конструкторе,
* но в данном случае невозможно невозможно передать метаданные в конструктор,
* поэтому старые значения формируются здесь.
* Вызывается таким способом потомучто невозможно передать метаданные в конструктор
* @param old
* @param fieldName
* @param metaData
*/
public void addFieldFormat(GEN old, String fieldName, String metaData) throws ClipsServerException {
xmlFormat.put(fieldName, metaData);
oldValues = getValues(old);
}
/**
* Вызывается при создании/модификации чекапов
* @param fieldName
* @param metaData
*/
public void addFieldFormat(String fieldName, String metaData) {
xmlFormat.put(fieldName, metaData);
}
public Date getDate() {
return date;
}
private void add(String title) {
value += title + "\n";
}
private void setTitle(String title) {
this.title = title;
}
public String getResult() {
if (changed) {
return title + "\n" + value;
} else {
return null;
}
}
public String getClassName() {
return className;
}
public Integer getId() {
return id;
}
/**
* Проверяет были ли произведены какие либо изменения в сущности, и формирует
* строковое значение аудита.
* @param current
* @return
* @throws ClipsServerException
*/
public boolean check(GEN current) throws ClipsServerException {
changed = false;
value = "";
title = "";
Class aClass = null;
if (current != null) {
aClass = current.getClass();
className = current.getClass().getSimpleName();
if (current instanceof GenericEntity) {
id = ((GenericEntity)current).getId();
}
if (aClass.isAnnotationPresent(DefineQueryEntity.class)) {
DefineQueryEntity annotation = (DefineQueryEntity) aClass.getAnnotation(DefineQueryEntity.class);
nameEntity = annotation.title();
} else {
nameEntity = aClass.getSimpleName();
}
}
HashMap<Field, Method> methodMap = getMethodMap(aClass);
if (oldValues != null && current == null) {
//Удаление
changed = true;
Set<Entry<Field, String>> entrySet = oldValues.entrySet();
for (Entry<Field, String> entry : entrySet) {
Field field = entry.getKey();
boolean protectedField = (field.getAnnotation(AuditProtectedProperty.class) != null);
String titleField;
if (field.getAnnotation(DefineQueryProperty.class) != null) {
titleField = field.getAnnotation(DefineQueryProperty.class).title();
} else {
titleField = field.getName();
}
if (!protectedField) {
add(titleField + " : \"" + entry.getValue() + "\"");
} else {
add(titleField + " : \"*****\"");
}
}
setTitle(Converter.dateToString(date, "dd.MM.yyyy-HH:mm:ss") + " сотрудником " +
collab.getClient().getFio() + " удален объект \"" + nameEntity + "\"\n" +
oldValues.info +
" (ID = " + oldValues.id + ")");
checked = true;
return true;
}
if (oldValues == null) {
//Создание
changed = true;
Set<Entry<Field, Method>> entrySet = methodMap.entrySet();
for (Entry<Field, Method> entry : entrySet) {
try {
Field field = entry.getKey();
boolean protectedField = (field.getAnnotation(AuditProtectedProperty.class) != null);
String metaData = xmlFormat.get(field.getName());
Method method = entry.getValue();
method.setAccessible(true);
String titleField;
if (field.getAnnotation(DefineQueryProperty.class) != null) {
titleField = field.getAnnotation(DefineQueryProperty.class).title();
} else {
titleField = field.getName();
}
if (!protectedField) {
add(titleField + " : \"" + getValueOfField(method.invoke(current), metaData) + "\"");
} else {
add(titleField + " : \"*****\"");
}
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
String t = Converter.dateToString(date, "dd.MM.yyyy-HH:mm:ss") + " сотрудником " +
collab.getClient().getFio() + " создан объект \"" + nameEntity + "\"\n" +
getValueOfField(current, null);
if (current instanceof GenericEntity) {
t = t + " (ID = " + ((GenericEntity)current).getId() + ")";
}
setTitle(t);
} else {
//Изменение
Set<Entry<Field, String>> entrySet = oldValues.entrySet();
for (Entry<Field, String> entry : entrySet) {
try {
Field field = entry.getKey();
boolean protectedField = (field.getAnnotation(AuditProtectedProperty.class) != null);
Method method = methodMap.get(field);
method.setAccessible(true);
String titleField;
if (field.getAnnotation(DefineQueryProperty.class) != null) {
titleField = field.getAnnotation(DefineQueryProperty.class).title();
} else {
titleField = field.getName();
}
String metaData = xmlFormat.get(field.getName());
String oldFieldValue = entry.getValue();
Object newField = method.invoke(current);
String currentfieldValue = getValueOfField(newField, metaData);
if ((oldFieldValue == null) ? (currentfieldValue != null) : !oldFieldValue.equals(currentfieldValue)
|| metaData != null) {
//Поле было изменено
if (metaData != null) {
oldFieldValue = null;
}
if (!protectedField) {
if (oldFieldValue == null) {
add(titleField + " : \"" + currentfieldValue + "\"");
} else {
add(titleField + " : \""+ oldFieldValue + "\" --> \"" + currentfieldValue + "\"");
}
} else {
if (oldFieldValue == null) {
add(titleField + " : \"*****\"");
} else {
add(titleField + " : \"*****\" --> \"*****\"");
}
}
changed = true;
}
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
if (changed) {
String t = Converter.dateToString(date, "dd.MM.yyyy-HH:mm:ss") + " сотрудником " +
collab.getClient().getFio() + " изменен объект \"" + nameEntity + "\"\n" +
getValueOfField(current, null);
if (current instanceof GenericEntity) {
t = t + " (ID = " + ((GenericEntity)current).getId() + ")";
}
setTitle(t);
}
}
checked = true;
return changed;
}
private HashMap<Field, Method> getMethodMap(Class aClass) throws ClipsServerException{
/*
* Выбираем из класса и всех его предков все поля и ищем для них геттеры по имени.
* исключая поля коллекции
*/
HashMap<Field, Method> methodMap = new HashMap<Field, Method>();
if (aClass == null) {
return methodMap;
}
do {
Field[] fields = aClass.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(Column.class) == null
&& field.getAnnotation(JoinColumn.class) == null) {
continue;
}
if (Collection.class.isAssignableFrom(field.getType())) {
continue;
}
Method method = null;
String methodName = "get" + Converter.firstUpper(field.getName(), false);
try {
method = aClass.getMethod(methodName);
} catch (NoSuchMethodException ex) {
//Not found
} catch (SecurityException ex) {
//Blocked
}
if (method == null) {
String alterName = "is" + Converter.firstUpper(field.getName(), false);
try {
method = aClass.getMethod(alterName);
} catch (NoSuchMethodException ex) {
throw new ClipsServerException("Несоответствие методов в сущности", ex);
} catch (SecurityException ex) {
throw new ClipsServerException("Метод в сущности заблокирован", ex);
}
}
if (!methodMap.containsKey(field) && method != null) {
methodMap.put(field, method);
}
}
aClass = aClass.getSuperclass();
} while (!aClass.equals(Object.class));
return methodMap;
}
private String getValueOfField(Object field, String metaData) throws ClipsServerException {
String valueField;
if (field == null) {
valueField = "-";
} else if (field instanceof HasEntityInfo){
valueField = ((HasEntityInfo)field).getInfo();
} else if (field instanceof GenericEntity){
valueField = String.valueOf(((GenericEntity)field).getId());
} else if (field instanceof Date){
valueField = Converter.dateToString((Date)field, "dd.MM.yyyy");
} else if (field instanceof byte[]){
valueField = Converter.hexDump((byte[]) field);
} else if (metaData != null) {
try {
if (getClassName().equals("Checkup")) {
valueField = Parser.xmlCheckupToUserView(field.toString(), metaData);
} else if (getClassName().equals("Certificate")) {
valueField = Parser.xmlCertificateToUserView(field.toString(), metaData);
} else if (getClassName().equals("Collaborator")) {
valueField = Parser.xmlCollaboratorToUserView(field.toString(), metaData);
} else {
throw new ClipsServerException("Неизвестный формат XML");
}
} catch (JDOMException ex) {
throw new ClipsServerException("Невалидная XML");
}
} else {
valueField = field.toString();
}
return valueField;
}
private class EntityValue extends HashMap<Field, String> {
String info;
int id;
public EntityValue(String info) {
this.info = info;
}
}
public boolean isChecked() {
return checked;
}
}