From 172dfc5baf5ccf07c8cc6039f6653c84f320576f Mon Sep 17 00:00:00 2001
From: Simon Barner <barner@fortiss.org>
Date: Mon, 8 Sep 2014 15:21:17 +0000
Subject: [PATCH] - Avoid unbounded recursion in
 DynamicInstanceAnnotationValueProviderBase - Fix editing of dynamically
 instantiated annotations refs 1841

---
 ...iInstanceAnnotationTextEditingSupport.java | 17 ++++++-
 ...icInstanceAnnotationValueProviderBase.java | 26 ++++++----
 .../view/CreateAnnotationInstanceColumn.java  | 48 ++++++++++++++-----
 3 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java
index 5f2f22e10..725b23a29 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/editingsupport/MultiInstanceAnnotationTextEditingSupport.java
@@ -20,6 +20,7 @@ package org.fortiss.tooling.base.ui.annotation.editingsupport;
 import org.eclipse.jface.viewers.ColumnViewer;
 import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
 import org.fortiss.tooling.base.ui.annotation.AnnotationEntry;
+import org.fortiss.tooling.base.ui.annotation.IAnnotationValueService;
 import org.fortiss.tooling.base.ui.annotation.valueprovider.DynamicInstanceAnnotationValueProviderBase;
 
 /**
@@ -63,7 +64,21 @@ public class MultiInstanceAnnotationTextEditingSupport extends TextEditingSuppor
 	protected boolean canEdit(Object element) {
 		if(element instanceof AnnotationEntry) {
 			AnnotationEntry data = (AnnotationEntry)element;
-			return data.getSpecificationValue(specClass, instanceKey) != null;
+
+			// Check if a value already exists.
+			if(data.getSpecificationValue(specClass, instanceKey) != null) {
+				return true;
+			}
+
+			// For dynamically instantiated annotations, check if the key exists with at least one
+			// model element.
+			for(AnnotationEntry entry : IAnnotationValueService.INSTANCE.getValues(data
+					.getModelElement())) {
+
+				if(entry.getInstanceKeys(specClass).contains(instanceKey)) {
+					return true;
+				}
+			}
 		}
 
 		return true;
diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java
index 5b0be31cf..262aeaf67 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/valueprovider/DynamicInstanceAnnotationValueProviderBase.java
@@ -81,11 +81,12 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno
 	}
 
 	/** {@inheritDoc} */
-	@SuppressWarnings("unchecked")
 	@Override
-	public <V> V getAnnotationValue(T spec, String instanceKey) throws Exception {
+	public <V> V getAnnotationValue(T specification, String instanceKey) throws Exception {
 		// Return value of current instance (entry map containing all instances of the annotation)
-		return ((EMap<String, V>)getAnnotationValue(spec)).get(instanceKey);
+		EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY);
+
+		return map.get(instanceKey);
 
 	}
 
@@ -97,19 +98,28 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno
 	private <V> void
 			setAnnotationValueFromString(String value, T specification, String instanceKey)
 					throws Exception {
-		((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey,
-				(V)valueFactory.createFromString(valueDataType, value));
+		EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY);
+
+		V val = (V)valueFactory.createFromString(valueDataType, value);
+		if(val == null) {
+			val = (V)valueDataType.getDefaultValue();
+		}
+		if(val == null) {
+			val = (V)valueFactory.createFromString(valueDataType, "0");
+		}
+
+		map.put(instanceKey, val);
 	}
 
 	/** {@inheritDoc} */
-	@SuppressWarnings("unchecked")
 	@Override
 	public <V> void setAnnotationValue(V value, T specification, String instanceKey)
 			throws Exception {
 		if(value instanceof String) {
 			setAnnotationValueFromString((String)value, specification, instanceKey);
 		} else {
-			((EMap<String, V>)getAnnotationValue(specification)).put(instanceKey, value);
+			EMap<String, V> map = super.getAnnotationValue(specification, DEFAULT_KEY);
+			map.put(instanceKey, value);
 		}
 
 	}
@@ -136,7 +146,7 @@ public abstract class DynamicInstanceAnnotationValueProviderBase<T extends IAnno
 		EMap<String, ?> kVMap = null;
 
 		try {
-			kVMap = getAnnotationValue(specification);
+			kVMap = super.getAnnotationValue(specification, DEFAULT_KEY);
 		} catch(Exception e) {
 			// Ignore exception
 		}
diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java
index fff800606..43fc8bc79 100644
--- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java
+++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/view/CreateAnnotationInstanceColumn.java
@@ -20,6 +20,8 @@ package org.fortiss.tooling.base.ui.annotation.view;
 import org.eclipse.emf.common.notify.Notification;
 import org.eclipse.emf.common.notify.impl.NotificationImpl;
 import org.eclipse.emf.common.util.EMap;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
 import org.eclipse.jface.dialogs.IInputValidator;
 import org.eclipse.jface.dialogs.InputDialog;
 import org.eclipse.jface.dialogs.MessageDialog;
@@ -44,6 +46,7 @@ import org.eclipse.swt.widgets.TableColumn;
 import org.eclipse.swt.widgets.TableItem;
 import org.fortiss.tooling.base.model.element.IAnnotatedSpecification;
 import org.fortiss.tooling.base.ui.annotation.AnnotationEntry;
+import org.fortiss.tooling.base.ui.annotation.IAnnotationValueService;
 import org.fortiss.tooling.kernel.extension.data.ITopLevelElement;
 import org.fortiss.tooling.kernel.service.IPersistencyService;
 
@@ -224,21 +227,42 @@ public class CreateAnnotationInstanceColumn extends ViewerColumn {
 									.getModelElement());
 					modelContext.runAsCommand(new Runnable() {
 
-						@SuppressWarnings("unchecked")
 						@Override
 						public void run() {
 							try {
-								// Work around the fact that getSpecificationValue(null,
-								// columnSpec.getClass(), instanceKey) would resolve
-								// to the more specific getSpecificationValue(String, Class<?
-								// extends IAnnotatedSpecification>, String) overload of the method,
-								// and thus would not work for maps whose value type is not String.
-								//
-								// Hence, the entire instance map is retrieved here, and put() is
-								// called explicitly.
-								((EMap<String, ?>)columnSpecAnnEntry
-										.getSpecificationValue(columnSpec.getClass())).put(
-										instanceKey, null);
+								// Populate new instance (in order to make the corresponding cells
+								// editable
+								String value = "";
+								if(!columnSpec.eClass().getEStructuralFeatures().isEmpty()) {
+									EStructuralFeature dynamicInstanceFeature =
+											columnSpec.eClass().getEStructuralFeatures().get(0);
+
+									// Annotations that can be dynamically instantiated are
+									// implemented using an appropriate EMap.
+									if(dynamicInstanceFeature.getEType().getInstanceTypeName()
+											.equals("java.util.Map$Entry")) {
+
+										// Determine value type
+										EStructuralFeature valueFeature =
+												((EClass)dynamicInstanceFeature.getEType())
+														.getEStructuralFeature("value");
+										if(Number.class.isAssignableFrom(valueFeature.getEType()
+												.getInstanceClass())) {
+
+											// Initialize numbers with 0
+											// (initialization fails with "")
+											value = "0";
+										}
+									}
+
+								}
+
+								for(AnnotationEntry entry : IAnnotationValueService.INSTANCE
+										.getValues(columnSpecAnnEntry.getModelElement())) {
+
+									entry.setSpecificationValue(value, columnSpec.getClass(),
+											instanceKey);
+								}
 
 								// Inform others, e.g. the respective annotation view that a new
 								// instance of this annotation has been created.
-- 
GitLab