catch up with branch daily

Signed-off-by: Ralf Mollik <ramollik@compex-commerce.com>
diff --git a/org.eclipse.osbp.runtime.common/META-INF/MANIFEST.MF b/org.eclipse.osbp.runtime.common/META-INF/MANIFEST.MF
index 01b12e2..329f734 100644
--- a/org.eclipse.osbp.runtime.common/META-INF/MANIFEST.MF
+++ b/org.eclipse.osbp.runtime.common/META-INF/MANIFEST.MF
@@ -17,6 +17,7 @@
  org.eclipse.osbp.runtime.common.filter;version="0.9.0",
  org.eclipse.osbp.runtime.common.hash;version="0.9.0",
  org.eclipse.osbp.runtime.common.help;version="0.9.0",
+ org.eclipse.osbp.runtime.common.historized;version="0.9.0",
  org.eclipse.osbp.runtime.common.i18n;version="0.9.0";uses:="org.eclipse.osbp.runtime.common.dispose",
  org.eclipse.osbp.runtime.common.keystroke;version="0.9.0",
  org.eclipse.osbp.runtime.common.layouting,
@@ -51,4 +52,5 @@
  org.eclipse.core.runtime;bundle-version="3.10.0",
  org.slf4j.api;bundle-version="1.7.2",
  org.eclipse.core.databinding.observable,
- org.eclipse.e4.core.contexts;bundle-version="1.5.1"
+ org.eclipse.e4.core.contexts;bundle-version="1.5.1",
+ org.eclipse.e4.ui.model.workbench
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/DtoUtils.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/DtoUtils.java
index c3864cf..3895173 100644
--- a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/DtoUtils.java
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/DtoUtils.java
@@ -29,9 +29,9 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.reflect.MethodUtils;
 import org.apache.commons.lang3.ClassUtils;
+import org.eclipse.osbp.runtime.common.historized.UUIDHist;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -94,6 +94,19 @@
 		return info.getIdField();
 	}
 
+	/**
+	 * Returns the idValidFrom field for historized objects. Field annotated
+	 * with {@link IdValidFrom}.
+	 *
+	 * @param clazz
+	 *            the clazz
+	 * @return the idValidFrom field
+	 */
+	public static Field getIdValidFromField(Class<?> clazz) {
+		Info info = getInfo(clazz);
+		return info.getIdValidFromField();
+	}
+
 	public static boolean isUUID(Class<?> clazz) {
 		Info info = getInfo(clazz);
 		Field field = info.getIdField();
@@ -130,6 +143,21 @@
 		return cloneDto;
 	}
 	
+	
+	/**
+	 * Creates a copy of the given dto and sets a new historized uuid version.
+	 * @param dto
+	 * @return
+	 */
+	public static <T> T newHistorizedVersionCopy(T dto){
+		@SuppressWarnings("unchecked")
+		T copy = (T) copyDto(dto);
+		UUIDHist id = (UUIDHist) getIdValue(copy);
+		setIdValue(copy, id.newVersion());
+		return copy;
+	}
+	
+
 	public static Object copyDto(Object dto) {
 		Object copyDto = null;
 		try {
@@ -139,7 +167,8 @@
 			BeanInfo beanInfo = Introspector.getBeanInfo(dto.getClass());
 			for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
 				Field field = fields.get(pd.getName());
-				if (field == null || field.isAnnotationPresent(Id.class) || field.isAnnotationPresent(Version.class) || field.isAnnotationPresent(Dispose.class)) {
+				if (field == null || field.isAnnotationPresent(Id.class) || field.isAnnotationPresent(Version.class)
+						|| field.isAnnotationPresent(Dispose.class)) {
 					continue;
 				}
 
@@ -390,7 +419,8 @@
 		try {
 			BeanInfo beanInfo = Introspector.getBeanInfo(dto.getClass());
 			for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
-				if (pd.getName().equals(idProperty) && (value == null || ClassUtils.isAssignable(pd.getPropertyType(),value.getClass(), true))) {
+				if (pd.getName().equals(idProperty)
+						&& (value == null || ClassUtils.isAssignable(pd.getPropertyType(), value.getClass(), true))) {
 					pd.getWriteMethod().invoke(dto, value);
 					break;
 				}
@@ -746,6 +776,16 @@
 	}
 
 	/**
+	 * Returns true, if the given id is a {@link UUIDHist}.
+	 * 
+	 * @param id
+	 * @return
+	 */
+	public static boolean isHistorizedId(Object id) {
+		return id instanceof UUIDHist;
+	}
+
+	/**
 	 * Unregisters the adapter as a property changed listener.
 	 *
 	 * @param adapter
@@ -800,6 +840,11 @@
 	 */
 	private static void applyFieldInfo(Class<?> clazz, Info info) {
 		try {
+
+			info.historized = clazz.isAnnotationPresent(HistorizedObject.class);
+			info.timedependent = clazz.isAnnotationPresent(TimedependentObject.class);
+			info.compoundHistKey = info.historized || info.timedependent;
+
 			for (Field field : clazz.getDeclaredFields()) {
 				if (field.getAnnotation(Dispose.class) != null) {
 					info.disposeField = field;
@@ -812,6 +857,10 @@
 				}
 				if (field.getAnnotation(Id.class) != null) {
 					info.idField = field;
+					if (info.compoundHistKey) {
+						Class<?> idType = field.getType();
+						info.histIdInfo = toHistIdInfo(idType);
+					}
 				}
 				if (field.getAnnotation(Version.class) != null) {
 					info.versionField = field;
@@ -876,6 +925,33 @@
 	}
 
 	/**
+	 * Creates an info object for historized and timedependent objects.
+	 * 
+	 * @param idType
+	 * @return
+	 */
+	private static CompoundHistIdInfo toHistIdInfo(Class<?> idType) {
+		CompoundHistIdInfo histInfo = new CompoundHistIdInfo();
+		for (Field field : idType.getDeclaredFields()) {
+			if (field.getAnnotation(HistUUID.class) != null) {
+				histInfo.rawUUIDField = field;
+			} else if (field.getAnnotation(HistValidFrom.class) != null) {
+				histInfo.rawVersionFromField = field;
+			}
+			if (histInfo.rawUUIDField != null && histInfo.rawVersionFromField != null) {
+				break;
+			}
+		}
+
+		if (histInfo.rawUUIDField == null || histInfo.rawVersionFromField == null) {
+			throw new IllegalStateException(
+					"rawUUID and rawVersionFrom must be present for historized and timedependet objects");
+		}
+
+		return histInfo;
+	}
+
+	/**
 	 * Applies all required field infos to the info object.
 	 *
 	 * @param clazz
@@ -932,6 +1008,16 @@
 	 */
 	private static class Info {
 
+		public boolean historized;
+		public boolean timedependent;
+
+		/**
+		 * Is true, if {@link #historized} or {@link #timedependent} is true.
+		 */
+		public boolean compoundHistKey;
+
+		public CompoundHistIdInfo histIdInfo;
+
 		public Field updateByField;
 
 		public Field updateAtField;
@@ -952,6 +1038,8 @@
 		/** The id field. */
 		private Field idField;
 
+		private Field idValidFromField;
+
 		/** The dirty field. */
 		private Field dirtyField;
 
@@ -1082,6 +1170,10 @@
 			return idField;
 		}
 
+		public Field getIdValidFromField() {
+			return idValidFromField;
+		}
+
 		public Field getUpdateByField() {
 			return updateByField;
 		}
@@ -1097,6 +1189,11 @@
 		public Field getCreateAtField() {
 			return createAtField;
 		}
+	}
+
+	public static class CompoundHistIdInfo {
+		public Field rawUUIDField;
+		public Field rawVersionFromField;
 
 	}
 }
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistGetHistCompoundKey.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistGetHistCompoundKey.java
new file mode 100644
index 0000000..803d602
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistGetHistCompoundKey.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+* Marks a method to be the method to access the historized compound key.
+*/
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistGetHistCompoundKey {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCurrent.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCurrent.java
new file mode 100644
index 0000000..5215d88
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCurrent.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * If true, then the object is the current history record.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistIsCurrent {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCustomVersion.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCustomVersion.java
new file mode 100644
index 0000000..7f77ff5
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistIsCustomVersion.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+* If true, then a custom version should be created by validFrom.
+*/
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistIsCustomVersion {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistUUID.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistUUID.java
new file mode 100644
index 0000000..94d6024
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistUUID.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The field is the field uuid of the history record.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistUUID {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidFrom.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidFrom.java
new file mode 100644
index 0000000..a6da4d5
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidFrom.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+* The validFrom attribute. Is party of primary key.
+*/
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistValidFrom {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidUntil.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidUntil.java
new file mode 100644
index 0000000..e3ecaf9
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistValidUntil.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+* The validUntil attribute. Is NOT party of primary key.
+*/
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistValidUntil {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistorizedObject.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistorizedObject.java
new file mode 100644
index 0000000..276d919
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/HistorizedObject.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Types an entity to be historized.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HistorizedObject {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/TimedependentObject.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/TimedependentObject.java
new file mode 100644
index 0000000..8d264a5
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/annotations/TimedependentObject.java
@@ -0,0 +1,15 @@
+package org.eclipse.osbp.runtime.common.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Types an entity to be historized.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TimedependentObject {
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/event/SelectionStore.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/event/SelectionStore.java
new file mode 100644
index 0000000..2f8e5d2
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/event/SelectionStore.java
@@ -0,0 +1,71 @@
+package org.eclipse.osbp.runtime.common.event;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.ui.model.application.ui.MUIElement;
+import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
+import org.eclipse.e4.ui.model.application.ui.basic.MPart;
+
+public class SelectionStore {
+	private Map<String, Object> selections = new HashMap<>();
+	
+	public void setSelection(String fqn, Object id) {
+		if(id != null) {
+			selections.put(fqn, id);
+		} else {
+			selections.remove(fqn);
+		}
+	}
+	
+	public Object getSelection(String fqn) {
+		if(selections.containsKey(fqn)) {
+			return selections.get(fqn);
+		}
+		return null;
+	}
+
+	/**
+	 * Store a selection by id to perspective context.
+	 *
+	 * @param key the fully qualified name of the id field
+	 * @param value the id object
+	 * @return true, if successful
+	 */
+	public static boolean putSelectionToPerspectiveContext(MPart part, String key, Object value) {
+		MUIElement element = part;
+		while(element != null && !(element instanceof MPerspective)) {
+			element = element.getParent();
+		}
+		if(element != null) {
+			IEclipseContext context = ((MPerspective)element).getContext(); 
+			if(context.get(SelectionStore.class) == null) {
+				context.set(SelectionStore.class, new SelectionStore());
+			}
+			context.get(SelectionStore.class).setSelection(key, value);
+			return true;
+		}
+		return false;
+	}
+	
+	/**
+	 * Gets a selection by id from perspective context.
+	 *
+	 * @param key the fully qualified name of the id field
+	 * @return the selected id object from perspective context
+	 */
+	public static Object getSelectionFromPerspectiveContext(MPart part, String key) {
+		MUIElement element = part;
+		while(element != null && !(element instanceof MPerspective)) {
+			element = element.getParent();
+		}
+		if(element != null) {
+			IEclipseContext context = ((MPerspective)element).getContext(); 
+			if(context.get(SelectionStore.class) != null) {
+				return context.get(SelectionStore.class).getSelection(key);
+			}
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/historized/UUIDHist.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/historized/UUIDHist.java
new file mode 100644
index 0000000..280c081
--- /dev/null
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/historized/UUIDHist.java
@@ -0,0 +1,132 @@
+package org.eclipse.osbp.runtime.common.historized;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.UUID;
+
+import javax.persistence.Embeddable;
+
+import org.eclipse.osbp.runtime.common.annotations.HistUUID;
+import org.eclipse.osbp.runtime.common.annotations.HistValidFrom;
+
+/**
+ * Compound id specifying a historized entity
+ */
+@Embeddable
+public class UUIDHist implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	@HistUUID
+	public String id = UUID.randomUUID().toString();
+
+	@HistValidFrom
+	public long validFrom = new Date().getTime();
+
+	public UUIDHist() {
+	}
+
+	public UUIDHist(String id, long validFrom) {
+		this.id = id;
+		this.validFrom = validFrom;
+	}
+
+	/**
+	 * Returns the uuid of the historized key.
+	 * 
+	 * @return
+	 */
+	public String getId() {
+		return id;
+	}
+
+	/**
+	 * Sets the uuid of the historized key.
+	 * 
+	 * @param id
+	 */
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	/**
+	 * Returns the valid from of the historized key.
+	 * 
+	 * @return
+	 */
+	public long getValidFrom() {
+		return validFrom;
+	}
+
+	/**
+	 * Sets the valid from of the historized key.
+	 * 
+	 * @param validFrom
+	 */
+	public void setValidFrom(long validFrom) {
+		this.validFrom = validFrom;
+	}
+
+	/**
+	 * Creates a copy of the id.
+	 * 
+	 * @return
+	 */
+	public UUIDHist copy() {
+		return new UUIDHist(id, validFrom);
+	}
+
+	/**
+	 * Creates a new version of this id by setting the validFrom to current
+	 * timestamp.
+	 * 
+	 * @return a copy of the id with new validFrom
+	 */
+	public UUIDHist newVersion() {
+		long newValidFrom = new Date().getTime();
+
+		// if we crate the new version in the same ms as the old version, lets
+		// wait 1ms.
+		if (newValidFrom == validFrom) {
+			try {
+				Thread.sleep(1);
+			} catch (InterruptedException e) {
+			}
+			newValidFrom = new Date().getTime();
+		}
+		return new UUIDHist(id, newValidFrom);
+	}
+
+	@Override
+	public String toString() {
+		return "UUIDHist [id=" + id + ", validFrom=" + new Date(validFrom) + "]";
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((id == null) ? 0 : id.hashCode());
+		result = prime * result + (int) (validFrom ^ (validFrom >>> 32));
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		UUIDHist other = (UUIDHist) obj;
+		if (id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!id.equals(other.id))
+			return false;
+		if (validFrom != other.validFrom)
+			return false;
+		return true;
+	}
+
+}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/ISession.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/ISession.java
index 192a353..96db123 100644
--- a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/ISession.java
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/ISession.java
@@ -44,6 +44,7 @@
 
 	String HOSTNAME = "hostname";
 	String IS_SLAVE = "slave";
+	String DTO_SEPARATOR = "§";
 
 	/**
 	 * Registers this session instance in a ThreadLocal variable.
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/SessionUtil.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/SessionUtil.java
index 4bd4091..a0e13ca 100644
--- a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/SessionUtil.java
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/session/SessionUtil.java
@@ -20,7 +20,7 @@
 	}
 	
 	/**
-	 * Splits the fragment by "," and returns the encoded info. Returns null, if no fragment available.
+	 * Splits the fragment by ISession.DTO_SEPARATOR and returns the encoded info. Returns null, if no fragment available.
 	 * @param fragment
 	 * @return
 	 */
@@ -28,7 +28,7 @@
 		if(fragment == null){
 			return null;
 		}
-		String[] tokens = fragment.split("-");
+		String[] tokens = fragment.split(ISession.DTO_SEPARATOR);
 		if(tokens.length == 1) {
 			return null;
 		}
diff --git a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/util/BeanUtils.java b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/util/BeanUtils.java
index 60d8c2c..b7834bd 100644
--- a/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/util/BeanUtils.java
+++ b/org.eclipse.osbp.runtime.common/src/org/eclipse/osbp/runtime/common/util/BeanUtils.java
@@ -13,12 +13,22 @@
 
 package org.eclipse.osbp.runtime.common.util;
 
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import org.eclipse.osbp.runtime.common.annotations.AsKanbanState;
@@ -62,6 +72,31 @@
 
 		return result;
 	}
+	
+	/**
+	 * Returns a single field for the class and annotation.
+	 * 
+	 * @param clazz
+	 * @param annotation
+	 * @return
+	 *
+	 *@throws IllegalStateException if more then 1 field found
+	 */
+	public static Field getField(Class<?> clazz, Class<? extends Annotation> annotation) {
+		List<Field> result = new ArrayList<>();
+
+		for (Field field : getAllFields(clazz)) {
+			if (field.isAnnotationPresent(annotation)) {
+				result.add(field);
+			}
+		}
+		
+		if(result.size() > 1) {
+			throw new IllegalStateException("More then one field found with given annotation " + annotation);
+		}
+
+		return result.isEmpty() ? null : result.get(0);
+	}
 
 	/**
 	 * Returns all filtering fields recurse to the defined depth.
@@ -288,48 +323,43 @@
 	public static void setCreateUser(Object bean, String user){
 		List<Field> fields = getAllFields(bean.getClass(), CreateBy.class);
 		for(Field field : fields) {
-			try {
-				field.setAccessible(true);
-				field.set(bean, user);
-			} catch (IllegalArgumentException | IllegalAccessException e) {
-				LOGGER.error("{}", e);
-			}
+			setter(bean, user, field);
 		}
 	}
 	
 	public static void setUpdateUser(Object bean, String user){
 		List<Field> fields = getAllFields(bean.getClass(), UpdateBy.class);
 		for(Field field : fields) {
-			try {
-				field.setAccessible(true);
-				field.set(bean, user);
-			} catch (IllegalArgumentException | IllegalAccessException e) {
-				LOGGER.error("{}", e);
+			setter(bean, user, field);
+		}
+	}
+
+	private static void setter(Object bean, Object obj, Field field) {
+		try {
+			BeanInfo info = Introspector.getBeanInfo(bean.getClass());
+			for (PropertyDescriptor desc : info.getPropertyDescriptors()) {
+				if (desc.getName().equalsIgnoreCase(field.getName())) {
+					Method method = desc.getWriteMethod();
+					method.invoke(bean, obj);
+					break;
+				}
 			}
+		} catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+			LOGGER.error("{}", e);
 		}
 	}
 	
 	public static void setCreateAt(Object bean, Date date){
 		List<Field> fields = getAllFields(bean.getClass(), CreateAt.class);
 		for(Field field : fields) {
-			try {
-				field.setAccessible(true);
-				field.set(bean, date);
-			} catch (IllegalArgumentException | IllegalAccessException e) {
-				LOGGER.error("{}", e);
-			}
+			setter(bean, date, field);
 		}
 	}
 	
 	public static void setUpdateAt(Object bean, Date date){
 		List<Field> fields = getAllFields(bean.getClass(), UpdateAt.class);
 		for(Field field : fields) {
-			try {
-				field.setAccessible(true);
-				field.set(bean, date);
-			} catch (IllegalArgumentException | IllegalAccessException e) {
-				LOGGER.error("{}", e);
-			}
+			setter(bean, date, field);
 		}
 	}