package fi.otavanopisto.pyramus.changelog;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.persistence.metamodel.Attribute;
import fi.internetix.smvc.SmvcRuntimeException;
import fi.otavanopisto.pyramus.dao.DAOFactory;
import fi.otavanopisto.pyramus.dao.SystemDAO;
import fi.otavanopisto.pyramus.dao.changelog.ChangeLogEntryDAO;
import fi.otavanopisto.pyramus.dao.changelog.ChangeLogEntryEntityDAO;
import fi.otavanopisto.pyramus.dao.changelog.ChangeLogEntryEntityPropertyDAO;
import fi.otavanopisto.pyramus.dao.changelog.ChangeLogEntryPropertyDAO;
import fi.otavanopisto.pyramus.dao.users.StaffMemberDAO;
import fi.otavanopisto.pyramus.domainmodel.changelog.ChangeLogEntry;
import fi.otavanopisto.pyramus.domainmodel.changelog.ChangeLogEntryEntity;
import fi.otavanopisto.pyramus.domainmodel.changelog.ChangeLogEntryEntityProperty;
import fi.otavanopisto.pyramus.domainmodel.changelog.ChangeLogEntryProperty;
import fi.otavanopisto.pyramus.domainmodel.changelog.ChangeLogEntryType;
import fi.otavanopisto.pyramus.domainmodel.users.User;
import fi.otavanopisto.pyramus.persistence.events.EventType;
import fi.otavanopisto.pyramus.persistence.events.TrackedEntityUtils;
import fi.otavanopisto.pyramus.util.ReflectionApiUtils;
//@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") }, mappedName = "java:/jms/JPAEvents")
public class ChangeLogJPAEventsListener implements MessageListener {
public void onMessage(Message message) {
try {
MapMessage mapMessage = (MapMessage) message;
EventType eventType = EventType.valueOf(mapMessage.getString("eventType"));
switch (eventType) {
case Create:
handleCreate(mapMessage);
break;
case Update:
handleUpdate(mapMessage);
break;
case Delete:
handleDelete(mapMessage);
break;
}
} catch (Exception e) {
throw new SmvcRuntimeException(e);
}
}
private void handleCreate(MapMessage mapMessage) throws JMSException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
SystemDAO systemDAO = DAOFactory.getInstance().getSystemDAO();
StaffMemberDAO userDAO = DAOFactory.getInstance().getStaffMemberDAO();
ChangeLogEntryDAO logEntryDAO = DAOFactory.getInstance().getChangeLogEntryDAO();
ChangeLogEntryEntityDAO entryEntityDAO = DAOFactory.getInstance().getChangeLogEntryEntityDAO();
ChangeLogEntryEntityPropertyDAO entryEntityPropertyDAO = DAOFactory.getInstance().getChangeLogEntryEntityPropertyDAO();
ChangeLogEntryPropertyDAO logEntryPropertyDAO = DAOFactory.getInstance().getChangeLogEntryPropertyDAO();
Long loggedUserId = mapMessage.itemExists("loggedUserId") ? mapMessage.getLong("loggedUserId") : null;
User loggedUser = loggedUserId != null ? userDAO.findById(loggedUserId) : null;
String entityClassName = mapMessage.getString("entity");
Object id = mapMessage.getObject("id");
Date time = new Date(mapMessage.getLong("time"));
Class<?> entityClass = Class.forName(entityClassName);
Object entity = systemDAO.findEntityById(entityClass, id);
// First we need to check if ChangeLogEntryEntity is already in the database
ChangeLogEntryEntity changeLogEntryEntity = entryEntityDAO.findByName(entityClassName);
if (changeLogEntryEntity == null) {
// if not we need to add it
changeLogEntryEntity = entryEntityDAO.create(entityClassName);
}
// Then we can add the log entry
ChangeLogEntry entry = logEntryDAO.create(changeLogEntryEntity, ChangeLogEntryType.Create, String.valueOf(id), time, loggedUser);
// After the entry has been added we can add all initial properties into the entry
Set<Attribute<?, ?>> attributes = systemDAO.getEntityAttributes(entityClass);
for (Attribute<?, ?> attribute : attributes) {
String fieldName = attribute.getName();
if (TrackedEntityUtils.isTrackedProperty(entityClassName, fieldName)) {
String value = null;
switch (attribute.getPersistentAttributeType()) {
case BASIC:
value = String.valueOf(ReflectionApiUtils.getObjectFieldValue(entity, fieldName, true));
break;
case ONE_TO_ONE:
case MANY_TO_ONE:
Object joinedEntity = ReflectionApiUtils.getObjectFieldValue(entity, fieldName, true);
if (joinedEntity != null) {
value = String.valueOf(getEntityId(attribute.getJavaType(), joinedEntity));
}
break;
}
// We need to check if database already contains this entity property
ChangeLogEntryEntityProperty changeLogEntryEntityProperty = entryEntityPropertyDAO.findByEntityAndName(changeLogEntryEntity, fieldName);
if (changeLogEntryEntityProperty == null) {
// if not we add it there
changeLogEntryEntityProperty = entryEntityPropertyDAO.create(changeLogEntryEntity, fieldName);
}
// After entity property has been resolved we can add the property itself
logEntryPropertyDAO.create(entry, changeLogEntryEntityProperty, value);
}
}
}
private void handleDelete(MapMessage mapMessage) throws JMSException {
StaffMemberDAO userDAO = DAOFactory.getInstance().getStaffMemberDAO();
ChangeLogEntryDAO logEntryDAO = DAOFactory.getInstance().getChangeLogEntryDAO();
ChangeLogEntryEntityDAO entryEntityDAO = DAOFactory.getInstance().getChangeLogEntryEntityDAO();
Long loggedUserId = mapMessage.itemExists("loggedUserId") ? mapMessage.getLong("loggedUserId") : null;
User loggedUser = loggedUserId != null ? userDAO.findById(loggedUserId) : null;
String entityClassName = mapMessage.getString("entity");
Object id = mapMessage.getObject("id");
Date time = new Date(mapMessage.getLong("time"));
// First we need to check if ChangeLogEntryEntity is already in the database
ChangeLogEntryEntity changeLogEntryEntity = entryEntityDAO.findByName(entityClassName);
if (changeLogEntryEntity == null) {
// if not we need to add it
changeLogEntryEntity = entryEntityDAO.create(entityClassName);
}
// Then we can add the log entry it self
logEntryDAO.create(changeLogEntryEntity, ChangeLogEntryType.Delete, String.valueOf(id), time, loggedUser);
}
private void handleUpdate(MapMessage mapMessage) throws JMSException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
SystemDAO systemDAO = DAOFactory.getInstance().getSystemDAO();
StaffMemberDAO userDAO = DAOFactory.getInstance().getStaffMemberDAO();
ChangeLogEntryDAO logEntryDAO = DAOFactory.getInstance().getChangeLogEntryDAO();
ChangeLogEntryEntityDAO entryEntityDAO = DAOFactory.getInstance().getChangeLogEntryEntityDAO();
ChangeLogEntryEntityPropertyDAO entryEntityPropertyDAO = DAOFactory.getInstance().getChangeLogEntryEntityPropertyDAO();
ChangeLogEntryPropertyDAO logEntryPropertyDAO = DAOFactory.getInstance().getChangeLogEntryPropertyDAO();
Long loggedUserId = mapMessage.itemExists("loggedUserId") ? mapMessage.getLong("loggedUserId") : null;
User loggedUser = loggedUserId != null ? userDAO.findById(loggedUserId) : null;
String entityClassName = mapMessage.getString("entity");
Object id = mapMessage.getObject("id");
Date time = new Date(mapMessage.getLong("time"));
Class<?> entityClass = Class.forName(entityClassName);
Object entity = systemDAO.findEntityById(entityClass, id);
Map<ChangeLogEntryEntityProperty, String> values = new HashMap<>();
// First we need to check if ChangeLogEntryEntity is already in the database
ChangeLogEntryEntity changeLogEntryEntity = entryEntityDAO.findByName(entityClassName);
if (changeLogEntryEntity == null) {
// if not we need to add it
changeLogEntryEntity = entryEntityDAO.create(entityClassName);
}
// After that we add all changed properties into the values map
Set<Attribute<?, ?>> attributes = systemDAO.getEntityAttributes(entityClass);
for (Attribute<?, ?> attribute : attributes) {
String fieldName = attribute.getName();
if (TrackedEntityUtils.isTrackedProperty(entityClassName, fieldName)) {
ChangeLogEntryEntityProperty changeLogEntryEntityProperty = entryEntityPropertyDAO.findByEntityAndName(changeLogEntryEntity, fieldName);
if (changeLogEntryEntityProperty == null) {
changeLogEntryEntityProperty = entryEntityPropertyDAO.create(changeLogEntryEntity, fieldName);
}
String newValue = null;
switch (attribute.getPersistentAttributeType()) {
case BASIC:
newValue = String.valueOf(ReflectionApiUtils.getObjectFieldValue(entity, fieldName, true));
break;
case ONE_TO_ONE:
case MANY_TO_ONE:
Object joinedEntity = ReflectionApiUtils.getObjectFieldValue(entity, fieldName, true);
if (joinedEntity != null) {
newValue = String.valueOf(getEntityId(attribute.getJavaType(), joinedEntity));
}
break;
}
ChangeLogEntryProperty changeLogEntryProperty = logEntryPropertyDAO.findLatestByEntryEntityProperty(changeLogEntryEntityProperty, String.valueOf(id));
String oldValue = changeLogEntryProperty != null ? changeLogEntryProperty.getValue() : null;
if (newValue == null ? oldValue != null ? true : false : !newValue.equals(oldValue)) {
values.put(changeLogEntryEntityProperty, newValue);
}
}
}
// And finally we can iterate values map values into the database
if (!values.isEmpty()) {
ChangeLogEntry entry = logEntryDAO.create(changeLogEntryEntity, ChangeLogEntryType.Update, String.valueOf(id), time, loggedUser);
for (Map.Entry<ChangeLogEntryEntityProperty, String> changeLogEntry : values.entrySet()) {
logEntryPropertyDAO.create(entry, changeLogEntry.getKey(), changeLogEntry.getValue());
}
}
}
private Object getEntityId(Class<?> entityClass, Object entity) {
SystemDAO systemDAO = DAOFactory.getInstance().getSystemDAO();
Attribute<?, ?> idAttribute = systemDAO.getEntityIdAttribute(entityClass);
try {
return ReflectionApiUtils.getObjectFieldValue(entity, idAttribute.getName(), true);
} catch (Exception e) {
return null;
}
}
}