From df89a3e60852d5c65112cbae095437fea9c1c887 Mon Sep 17 00:00:00 2001 From: Simon Barner <barner@fortiss.org> Date: Thu, 11 Dec 2014 09:24:54 +0000 Subject: [PATCH] - Add AnnotationInstantiationMigrationProvider that augments loaded models with annotations that have been added to the AF3 installation after the creation of the model. - Note that: - It is still required to use AnnotationUtils.getAnnotation() to obtain (and potentially instantiate) an annotation. This is because annotations are only instantiated for newly added model elements if the annotation view is visible. - IMigrationProviders that convert old attribute values into annotations cannot rely on the fact that the annotation instance already exists (since the execution order of the IMigrationProviders is not defined). Hence, the need to use AnnotationUtils.getAnnotation(modelElement, clazz, false) to obtain (and potentially instantiate) an annotation (without wrapping the model access into a command, see #2010). refs 1841 --- ...otationInstantiationMigrationProvider.java | 75 +++++++++++ .../ui/annotation/AnnotationValueService.java | 118 +++++++++++------- .../annotation/IAnnotationValueService.java | 26 +++- 3 files changed, 172 insertions(+), 47 deletions(-) create mode 100644 org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationInstantiationMigrationProvider.java diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationInstantiationMigrationProvider.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationInstantiationMigrationProvider.java new file mode 100644 index 000000000..70963c691 --- /dev/null +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationInstantiationMigrationProvider.java @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------+ +$Id$ +| | +| Copyright 2013 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.base.ui.annotation; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.xml.type.AnyType; +import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; +import org.fortiss.tooling.base.model.element.IModelElement; +import org.fortiss.tooling.kernel.extension.IMigrationProvider; +import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; + +/** + * {@link IMigrationProvider} that ensures that all {@link IAnnotatedSpecification}s that have been + * registered for model element types in the current model are actually instantiated. + * + * This is required for new {@link IAnnotatedSpecification}s that have been registered after the + * creation of the model. + * + * @author barner + * @author $Author$ + * @version $Rev$ + * @ConQAT.Rating YELLOW Hash: DB938B8077EEAFB9455F8A83BF92CD86 + */ +public class AnnotationInstantiationMigrationProvider implements IMigrationProvider { + + /** + * Set of models already processed during this run. The implementation of a predicate function + * if model migration is needed (for use in {@link #needMigration(ITopLevelElement, Map)} would + * be as complex as the migration itself. + */ + private Set<ITopLevelElement> processedModels = new HashSet<ITopLevelElement>(); + + /** {@inheritDoc} */ + @Override + public boolean needMigration(ITopLevelElement modelElement, + Map<EObject, AnyType> unknownFeatures) { + + return modelElement != null && modelElement.getRootModelElement() != null && + !processedModels.contains(modelElement); + } + + /** {@inheritDoc} */ + @Override + public void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures) { + processedModels.add(modelElement); + + for(Iterator<EObject> i = modelElement.getRootModelElement().eAllContents(); i.hasNext();) { + EObject eo = i.next(); + if(eo instanceof IModelElement) { + + // IAnnotationValueService.INSTANCE.instantiateAnnotations((IModelElement)eo); + } + } + } +} diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java index 297003e08..a7c2b4151 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/AnnotationValueService.java @@ -132,9 +132,66 @@ public class AnnotationValueService extends return valueProviderList; } + /** + * Prepares the {@link AnnotationEntry} for a given {@link IModelElement} and ensures that all + * {@link IAnnotatedSpecification}s are instantiated. + */ + private void prepareAnnotationEntry(final IModelElement element, AnnotationEntry entry, + final List<IAnnotationValueProvider<IAnnotatedSpecification>> registeredHandlers) { + for(IAnnotationValueProvider<IAnnotatedSpecification> annotationProvider : registeredHandlers) { + + IAnnotatedSpecification annotatedSpecification = + EcoreUtils.pickFirstInstanceOf(annotationProvider.getAnnotationClazz(), + element.getSpecifications()); + + // + // + // TODO: This is a bad design choice because that way annotations are + // instantiated from the GUI context. This will have the consequence that + // new annotations types will not have been instantiated for elements of + // legacy models (i.e., models that have been created before the the new + // annotation has been added) until the model is opened and the + // corresponding elements are displayed in a view that makes use of this + // getValues() method + // + // This problem typically arises in IMigrationProviders, which run before + // the GUI. Hence, the only safe way to acquire an annotation for a model + // element is org.fortiss.tooling.base.utils.AnnotationUtils.getAnnotation() + // which will take care of the instantiation (if required). + if(annotatedSpecification == null) { + try { + annotatedSpecification = + annotationProvider.getAnnotatedSpecificationForModelElement(element); + } catch(Exception ex) { + System.out + .println("Error instantating new annotation: createAnnotatedSpecificationForModelElement() failed for " + + annotationProvider.getAnnotationClazz() + "."); + return; + } + } + + // Register annotation provider <-> annotation specification mapping + entry.addNewSpecification(annotationProvider, annotatedSpecification); + } + + } + /** {@inheritDoc} */ @Override - public AnnotationEntry getAnnotationEntry(final IModelElement element) { + public void instantiateAnnotations(final IModelElement element) { + getAnnotationEntry(element, false); + } + + /** + * Helper method that performs the actual work of {@link #getAnnotationEntry(IModelElement)} and + * {@link #instantiateAnnotations(IModelElement)}, i.e. that acquires (and potentially + * instantiates) annotations for model elements. + * + * @return {@link AnnotationEntry} for all {@link IAnnotatedSpecification}s of the given + * {@link IModelElement}. + */ + private AnnotationEntry + getAnnotationEntry(final IModelElement element, boolean wrapIntoCommand) { AnnotationEntry cachedResult = annotationEntryCache.get(element); if(cachedResult != null) { @@ -150,50 +207,17 @@ public class AnnotationValueService extends final AnnotationEntry result = new AnnotationEntry(element); if(registeredHandlers != null && !registeredHandlers.isEmpty()) { - KernelModelElementUtils.runAsCommand(element, new Runnable() { - - @Override - public void run() { - - for(IAnnotationValueProvider<IAnnotatedSpecification> annotationProvider : registeredHandlers) { - - IAnnotatedSpecification annotatedSpecification = - EcoreUtils.pickFirstInstanceOf( - annotationProvider.getAnnotationClazz(), - element.getSpecifications()); - - // If required, instantiate annotation for the given model element. - // - // TODO: This is a bad design choice because that way annotations are - // instantiated from the GUI context. This will have the consequence that - // new annotations types will not have been instantiated for elements of - // legacy models (i.e., models that have been created before the the new - // annotation has been added) until the model is opened and the - // corresponding elements are displayed in a view that makes use of this - // getValues() method - // - // This problem typically arises in IMigrationProviders, which run before - // the GUI. Hence, the only safe way to acquire an annotation for a model - // element is org.fortiss.tooling.base.utils.AnnotationUtils.getAnnotation() - // which will take care of the instantiation (if required). - if(annotatedSpecification == null) { - try { - annotatedSpecification = - annotationProvider - .getAnnotatedSpecificationForModelElement(element); - } catch(Exception ex) { - System.out - .println("Error instantating new annotation: createAnnotatedSpecificationForModelElement() failed for " + - annotationProvider.getAnnotationClazz() + "."); - return; - } - } - - // Register annotation provider <-> annotation specification mapping - result.addNewSpecification(annotationProvider, annotatedSpecification); + if(wrapIntoCommand) { + KernelModelElementUtils.runAsCommand(element, new Runnable() { + + @Override + public void run() { + prepareAnnotationEntry(element, result, registeredHandlers); } - } - }); + }); + } else { + prepareAnnotationEntry(element, result, registeredHandlers); + } } annotationEntryCache.put(element, result); @@ -201,6 +225,12 @@ public class AnnotationValueService extends return result; } + /** {@inheritDoc} */ + @Override + public AnnotationEntry getAnnotationEntry(final IModelElement element) { + return getAnnotationEntry(element, true); + } + /** {@inheritDoc} */ @Override protected String getExtensionPointName() { diff --git a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/IAnnotationValueService.java b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/IAnnotationValueService.java index a9f4d7d46..f94234cea 100644 --- a/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/IAnnotationValueService.java +++ b/org.fortiss.tooling.base.ui/trunk/src/org/fortiss/tooling/base/ui/annotation/IAnnotationValueService.java @@ -19,6 +19,7 @@ package org.fortiss.tooling.base.ui.annotation; import org.fortiss.tooling.base.model.element.IAnnotatedSpecification; import org.fortiss.tooling.base.model.element.IModelElement; +import org.fortiss.tooling.kernel.utils.KernelModelElementUtils; /** * @@ -33,11 +34,30 @@ public interface IAnnotationValueService { public static final IAnnotationValueService INSTANCE = new AnnotationValueService(); /** + * <p> * Returns the {@link AnnotationEntry} for the given {@link IModelElement}. In case any of the * {@link IAnnotatedSpecification}s registered for the corresponding {@link IModelElement} - * specialization does not exist for the given {@code modelElement} yet, it instantiated by this - * method. + * specialization does not exist for the given {@code modelElement} yet, it instantiated. + * </p> + * + * <p> + * This method uses + * {@link KernelModelElementUtils#runAsCommand(org.eclipse.emf.ecore.EObject, Runnable)} and + * hence is safe to be called from the GUI context. + * </p> */ - AnnotationEntry getAnnotationEntry(IModelElement element); + public AnnotationEntry getAnnotationEntry(IModelElement element); + + /** + * <p> + * If required, instantiate annotation for the given model element. + * </p> + * + * <p> + * <b>CAVEAT: </b>This method must be called from a context that allows the modification of the + * model. + * </p> + */ + public void instantiateAnnotations(IModelElement element); } -- GitLab