catch up with branch daily
Signed-off-by: Ralf Mollik <ramollik@compex-commerce.com>
diff --git a/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedDescriptorWrapper.java b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedDescriptorWrapper.java
new file mode 100644
index 0000000..744095f
--- /dev/null
+++ b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedDescriptorWrapper.java
@@ -0,0 +1,167 @@
+package org.eclipse.osbp.jpa.services.history;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+import javax.persistence.Version;
+
+import org.eclipse.osbp.runtime.common.annotations.HistIsCurrent;
+import org.eclipse.osbp.runtime.common.annotations.HistIsCustomVersion;
+import org.eclipse.osbp.runtime.common.annotations.HistValidUntil;
+import org.eclipse.osbp.runtime.common.historized.UUIDHist;
+import org.eclipse.osbp.runtime.common.util.BeanUtils;
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+import org.eclipse.persistence.internal.helper.DatabaseField;
+import org.eclipse.persistence.mappings.DatabaseMapping;
+
+public class HistorizedDescriptorWrapper {
+
+ private final Class<?> clazz;
+ private final ClassDescriptor descriptor;
+ private DatabaseMapping versionMapping;
+ private DatabaseMapping validUntilMapping;
+ private DatabaseMapping currentMapping;
+ private DatabaseMapping isCustomVersionMapping;
+
+ private DatabaseMapping idMapping;
+ private ClassDescriptor uuidHistDescriptor;
+ private DatabaseMapping id_idMapping;
+ private DatabaseMapping id_validFromMapping;
+
+ public HistorizedDescriptorWrapper(ClassDescriptor descriptor) {
+ this.clazz = descriptor.getJavaClass();
+ this.descriptor = descriptor;
+
+ // find the ID String field by the descriptor
+ List<DatabaseField> pk = descriptor.getPrimaryKeyFields();
+ for (DatabaseMapping mapping : descriptor.getMappings()) {
+ if (mapping.isPrimaryKeyMapping()) {
+ idMapping = mapping;
+ break;
+ }
+ }
+
+ uuidHistDescriptor = idMapping.getReferenceDescriptor();
+
+ Field versionField = BeanUtils.getField(clazz, Version.class);
+ Field validUntilField = BeanUtils.getField(clazz, HistValidUntil.class);
+ Field currentHist = BeanUtils.getField(clazz, HistIsCurrent.class);
+ Field isCustomVersion = BeanUtils.getField(clazz, HistIsCustomVersion.class);
+
+ id_idMapping = uuidHistDescriptor.getMappingForAttributeName("id");
+ id_validFromMapping = uuidHistDescriptor.getMappingForAttributeName("validFrom");
+ versionMapping = descriptor.getMappingForAttributeName(versionField.getName());
+ validUntilMapping = descriptor.getMappingForAttributeName(validUntilField.getName());
+ currentMapping = descriptor.getMappingForAttributeName(currentHist.getName());
+ isCustomVersionMapping = descriptor.getMappingForAttributeName(isCustomVersion.getName());
+ }
+
+ public String getIdAttName() {
+ return idMapping.getAttributeName();
+ }
+
+ public String getId_IdAttName() {
+ return id_idMapping.getAttributeName();
+ }
+
+ public String getId_ValidFromAttName() {
+ return id_validFromMapping.getAttributeName();
+ }
+
+ public String getVersionAttName() {
+ return versionMapping.getAttributeName();
+ }
+
+ public String getValidUntilAttName() {
+ return validUntilMapping.getAttributeName();
+ }
+
+ public String getCurrentHistAttName() {
+ return currentMapping.getAttributeName();
+ }
+
+ public String getIsCustomVersionAttName() {
+ return isCustomVersionMapping.getAttributeName();
+ }
+
+ public UUIDHist getID(Object obj) {
+ return (UUIDHist) idMapping.getAttributeValueFromObject(obj);
+ }
+
+ public int getVersion(Object obj) {
+ return (int) versionMapping.getAttributeValueFromObject(obj);
+ }
+
+ public long getId_ValidFrom(Object obj) {
+ if (obj instanceof UUIDHist) {
+ return ((UUIDHist) obj).getValidFrom();
+ }
+ UUIDHist idHist = (UUIDHist) idMapping.getAttributeValueFromObject(obj);
+ return idHist != null ? idHist.getValidFrom() : -1;
+ }
+
+ public String getId_IdFrom(Object obj) {
+ if (obj instanceof UUIDHist) {
+ return ((UUIDHist) obj).getId();
+ }
+ UUIDHist idHist = (UUIDHist) idMapping.getAttributeValueFromObject(obj);
+ return idHist != null ? idHist.getId() : null;
+ }
+
+ public long getValidUntil(Object obj) {
+ return (long) validUntilMapping.getAttributeValueFromObject(obj);
+ }
+
+ public boolean isCurrentHist(Object obj) {
+ return (boolean) currentMapping.getAttributeValueFromObject(obj);
+ }
+
+ public boolean isCustomVersion(Object obj) {
+ return (boolean) isCustomVersionMapping.getAttributeValueFromObject(obj);
+ }
+
+ public Class<?> getEntityClass() {
+ return descriptor.getJavaClass();
+ }
+
+ public void setID(Object obj, Object value) {
+ idMapping.setAttributeValueInObject(obj, value);
+ }
+
+ public void setVersion(Object obj, int value) {
+ versionMapping.setAttributeValueInObject(obj, value);
+ }
+
+ public void setId_ValidFrom(Object obj, long value) {
+ if (obj instanceof UUIDHist) {
+ ((UUIDHist) obj).setValidFrom(value);
+ }
+ UUIDHist idHist = (UUIDHist) idMapping.getAttributeValueFromObject(obj);
+ if (idHist != null) {
+ idHist.setValidFrom(value);
+ }
+ }
+
+ public void setId_IdFrom(Object obj, String value) {
+ if (obj instanceof UUIDHist) {
+ ((UUIDHist) obj).setId(value);
+ }
+ UUIDHist idHist = (UUIDHist) idMapping.getAttributeValueFromObject(obj);
+ if (idHist != null) {
+ idHist.setId(value);
+ }
+ }
+
+ public void setValidUntil(Object obj, long value) {
+ validUntilMapping.setAttributeValueInObject(obj, value);
+ }
+
+ public void setCurrentHist(Object obj, boolean value) {
+ currentMapping.setAttributeValueInObject(obj, value);
+ }
+
+ public void setCustomVersion(Object obj, boolean value) {
+ isCustomVersionMapping.setAttributeValueInObject(obj, value);
+ }
+
+}
diff --git a/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedObjectWrapper.java b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedObjectWrapper.java
new file mode 100644
index 0000000..a8173d9
--- /dev/null
+++ b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedObjectWrapper.java
@@ -0,0 +1,109 @@
+package org.eclipse.osbp.jpa.services.history;
+
+import org.eclipse.osbp.runtime.common.historized.UUIDHist;
+import org.eclipse.persistence.descriptors.ClassDescriptor;
+
+/**
+ * This class gives access to historized annotated fields in the given obj.
+ */
+public class HistorizedObjectWrapper {
+
+ private HistorizedDescriptorWrapper delegate;
+ private Object obj;
+
+ public HistorizedObjectWrapper(ClassDescriptor descriptor, Object obj) {
+ delegate = new HistorizedDescriptorWrapper(descriptor);
+ this.obj = obj;
+ }
+
+ public String getIdAttName() {
+ return delegate.getIdAttName();
+ }
+
+ public String getVersionAttName() {
+ return delegate.getVersionAttName();
+ }
+
+
+
+ public String getId_IdAttName() {
+ return delegate.getId_IdAttName();
+ }
+
+ public String getId_ValidFromAttName() {
+ return delegate.getId_ValidFromAttName();
+ }
+
+ public long getId_ValidFrom() {
+ return delegate.getId_ValidFrom(obj);
+ }
+
+ public String getId_IdFrom() {
+ return delegate.getId_IdFrom(obj);
+ }
+
+ public void setId_ValidFrom(long value) {
+ delegate.setId_ValidFrom(obj, value);
+ }
+
+ public void setId_IdFrom(String value) {
+ delegate.setId_IdFrom(obj, value);
+ }
+
+ public String getValidUntilAttName() {
+ return delegate.getValidUntilAttName();
+ }
+
+ public String getCurrentHistAttName() {
+ return delegate.getCurrentHistAttName();
+ }
+
+ public String getIsCustomVersionAttName() {
+ return delegate.getIsCustomVersionAttName();
+ }
+
+ public UUIDHist getID() {
+ return delegate.getID(obj);
+ }
+
+ public long getVersion() {
+ return delegate.getVersion(obj);
+ }
+
+ public long getValidUntil() {
+ return delegate.getValidUntil(obj);
+ }
+
+ public boolean isCurrentHist() {
+ return delegate.isCurrentHist(obj);
+ }
+
+ public boolean isCustomVersion() {
+ return delegate.isCustomVersion(obj);
+ }
+
+ public Class<?> getEntityClass() {
+ return delegate.getEntityClass();
+ }
+
+ public void setID(Object value) {
+ delegate.setID(obj, value);
+ }
+
+ public void setVersion(int value) {
+ delegate.setVersion(obj, value);
+ }
+
+ public void setValidUntil(long value) {
+ delegate.setValidUntil(obj, value);
+ }
+
+ public void setCurrentHist(boolean value) {
+ delegate.setCurrentHist(obj, value);
+ }
+
+ public void setCustomVersion(boolean value) {
+ delegate.setCustomVersion(obj, value);
+ }
+
+}
diff --git a/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedQueryRedirector.java b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedQueryRedirector.java
new file mode 100644
index 0000000..96168f5
--- /dev/null
+++ b/org.eclipse.osbp.jpa.services/src/org/eclipse/osbp/jpa/services/history/HistorizedQueryRedirector.java
@@ -0,0 +1,144 @@
+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;
+
+/**
+ * Manages the versioning of historized and timedependent entities.
+ */
+@SuppressWarnings("serial")
+public class HistorizedQueryRedirector implements QueryRedirector {
+
+ @Override
+ public Object invokeQuery(DatabaseQuery query, Record arguments, Session session) {
+ WriteObjectQuery writeObjectQuery = (WriteObjectQuery) query;
+
+ 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);
+
+ writeObjectQuery.setDoNotRedirect(true);
+ Object newAdr = writeObjectQuery.execute((AbstractSession) session, (AbstractRecord) arguments);
+ return newAdr;
+ } else {
+
+ // sleep 1ms for minimum time intervall between historized records
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+
+ // update the address to be historized
+ long now = createNow(persistedObjWrapper);
+ Object histCurrentObj = getCurrentManaged(
+ new HistorizedObjectWrapper(writeObjectQuery.getDescriptor(), current), (AbstractSession) session);
+
+ // 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;
+ }
+
+ histCurrentObjWrapper.setCurrentHist(false);
+ histCurrentObjWrapper.setValidUntil(now);
+ UpdateObjectQuery updateCurrent = new UpdateObjectQuery(histCurrentObj);
+ updateCurrent.setDoNotRedirect(true);
+ updateCurrent.setIsUserDefined(true);
+ updateCurrent.execute((AbstractSession) session, (AbstractRecord) arguments);
+
+ persistedObjWrapper.setId_ValidFrom(now);
+ persistedObjWrapper.setValidUntil(getMaxDate());
+ persistedObjWrapper.setCurrentHist(true);
+ persistedObjWrapper.setVersion((int) 0);
+
+ InsertObjectQuery insertObjectQ = new InsertObjectQuery(persistedObj);
+ insertObjectQ.setIsUserDefined(true);
+ insertObjectQ.setDoNotRedirect(true);
+
+ Object newAdr = insertObjectQ.execute((AbstractSession) session, (AbstractRecord) arguments);
+ return newAdr;
+ }
+
+ }
+
+ 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 = (Object) rq.executeInUnitOfWork(uow, EmptyRecord.getEmptyRecord());
+
+ uow.clearForClose(true);
+ return current;
+ }
+
+ private Object getCurrentManaged(HistorizedObjectWrapper wrapper, AbstractSession session) {
+
+ ReadObjectQuery rq = new ReadObjectQuery(wrapper.getEntityClass());
+
+ ExpressionBuilder eb = rq.getExpressionBuilder();
+ Expression exp = eb.get(wrapper.getIdAttName()).equal(wrapper.getID());
+ rq.setSelectionCriteria(exp);
+
+ Object current = rq.execute(session, EmptyRecord.getEmptyRecord());
+
+ return current;
+ }
+
+ 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();
+ }
+
+}