blob: 286587d0c0a27f21e71bcbb7b20ea372946e9797 [file] [log] [blame]
package org.eclipse.osbp.jpa.services.history;
import java.util.Calendar;
import java.util.Date;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.expressions.ExpressionBuilder;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.EmptyRecord;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.InsertObjectQuery;
import org.eclipse.persistence.queries.QueryRedirector;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.queries.UpdateObjectQuery;
import org.eclipse.persistence.queries.WriteObjectQuery;
import org.eclipse.persistence.sessions.Record;
import org.eclipse.persistence.sessions.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Manages the versioning of historized and timedependent entities.
*/
@SuppressWarnings("serial")
public class HistorizedQueryRedirector implements QueryRedirector {
protected static Logger logger = LoggerFactory.getLogger(HistorizedQueryRedirector.class);
@Override
public Object invokeQuery(DatabaseQuery query, Record arguments, Session session) {
WriteObjectQuery writeObjectQuery = (WriteObjectQuery) query;
logger.debug("historized changes {}", writeObjectQuery.getObjectChangeSet().getChanges());
if(writeObjectQuery instanceof UpdateObjectQuery) {
return writeObjectQuery.getObject();
}
Object persistedObj = writeObjectQuery.getObject();
// the object that was persisted / merged
//
HistorizedObjectWrapper persistedObjWrapper = new HistorizedObjectWrapper(writeObjectQuery.getDescriptor(),
persistedObj);
// if (persistedObjWrapper.getVersion() > 1) {
// throw new IllegalArgumentException(
// "Version must be 0. Changing historized records is not allowed: " + persistedObj.toString());
// }
Object current = getCurrent(persistedObjWrapper, (AbstractSession) session);
if (current == null) {
persistedObjWrapper.setId_ValidFrom(createNow(persistedObjWrapper));
persistedObjWrapper.setValidUntil(getMaxDate());
persistedObjWrapper.setCurrentHist(true);
persistedObjWrapper.applyHistorizedDomainKey();
writeObjectQuery.setDoNotRedirect(true);
return writeObjectQuery.execute((AbstractSession) session, (AbstractRecord) arguments);
} else {
// sleep 1ms for minimum time intervall between historized records
try {
Thread.sleep(1);
} catch (InterruptedException e) { // NOSONAR
}
// update the address to be historized
long now = createNow(persistedObjWrapper);
Object histCurrentObj = getCurrentManaged(
new HistorizedObjectWrapper(writeObjectQuery.getDescriptor(), current), (AbstractSession) session);
Object histCurrentObjClone = null;
try {
histCurrentObjClone = histCurrentObj.getClass().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
logger.error("{}", e);
}
query.getDescriptor().getObjectBuilder().copyInto(histCurrentObj, histCurrentObjClone);
// the current object in database with flag histCurrent = true
//
HistorizedObjectWrapper histCurrentObjWrapper = new HistorizedObjectWrapper(
writeObjectQuery.getDescriptor(), histCurrentObj);
if (query.getDescriptor().getObjectBuilder().compareObjects(persistedObj, histCurrentObj,
(AbstractSession) session)) {
return persistedObj;
}
// update the old record
//
histCurrentObjWrapper.setCurrentHist(false);
histCurrentObjWrapper.setValidUntil(now);
UpdateObjectQuery updateCurrent = new UpdateObjectQuery(histCurrentObj);
updateCurrent.setBackupClone(histCurrentObjClone);
updateCurrent.setDoNotRedirect(true);
updateCurrent.setIsUserDefined(true);
updateCurrent.execute((AbstractSession) session, (AbstractRecord) arguments);
// insert the new record
//
persistedObjWrapper.setId_ValidFrom(now);
persistedObjWrapper.setValidUntil(getMaxDate());
persistedObjWrapper.setCurrentHist(true);
persistedObjWrapper.setVersion((int) 0);
persistedObjWrapper.applyHistorizedDomainKey();
InsertObjectQuery insertObjectQ = new InsertObjectQuery(persistedObj);
insertObjectQ.setIsUserDefined(true);
insertObjectQ.setDoNotRedirect(true);
return insertObjectQ.execute((AbstractSession) session, (AbstractRecord) arguments);
}
}
private long createNow(HistorizedObjectWrapper wrapper) {
if (wrapper.isCustomVersion()) {
return wrapper.getId_ValidFrom();
}
return new Date().getTime();
}
private Object getCurrent(HistorizedObjectWrapper wrapper, AbstractSession session) {
UnitOfWorkImpl uow = session.acquireNonSynchronizedUnitOfWork();
ReadObjectQuery rq = new ReadObjectQuery(wrapper.getEntityClass());
ExpressionBuilder eb = rq.getExpressionBuilder();
Expression exp = eb.get(wrapper.getIdAttName()).get(wrapper.getId_IdAttName()).equal(wrapper.getID().id)
.and(eb.get(wrapper.getCurrentHistAttName()).equal(true));
rq.setSelectionCriteria(exp);
rq.dontCheckCache();
rq.dontMaintainCache();
Object current = rq.executeInUnitOfWork(uow, EmptyRecord.getEmptyRecord());
uow.clearForClose(true);
return current;
}
private Object getCurrentManaged(HistorizedObjectWrapper wrapper, AbstractSession session) {
ReadObjectQuery rq = new ReadObjectQuery(wrapper.getEntityClass());
rq.conformResultsInUnitOfWork();
ExpressionBuilder eb = rq.getExpressionBuilder();
Expression exp = eb.get(wrapper.getIdAttName()).equal(wrapper.getID());
rq.setSelectionCriteria(exp);
return rq.execute(session, EmptyRecord.getEmptyRecord());
}
private long getMaxDate() {
Calendar cal = Calendar.getInstance();
cal.set(2099, Calendar.DECEMBER, 31, 0, 0, 0);
cal.set(Calendar.MILLISECOND, 0);
Date maxDate = cal.getTime();
return maxDate.getTime();
}
}