diff --git a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/.ratings b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/.ratings index 5633daf969db8251bbf77fd7418a1c19bf30868a..9d0d7f8df1b322b3005d555d7552e4aa62d05156 100644 --- a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/.ratings +++ b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/.ratings @@ -1,3 +1,3 @@ -AddMissingAnnotationsMigrationProvider.java a3f2b3cbcd39f85e15bc998650f899f55d9f563e GREEN -RemoveDuplicatedAnnotationsMigrationProvider.java f1bdb4733d5b9c6003a2b7fee59b89240a0a3b61 GREEN -RemoveOutdatedAnnotationInstanceMigrationProvider.java 29c29f2bb7515cad1de45a30ffc185001b47a016 GREEN +AddMissingAnnotationsMigrationProvider.java ebc5b9348b61ffb23493942949ecccf1c1fa2ae1 GREEN +RemoveDuplicatedAnnotationsMigrationProvider.java 6920909f8f211b9c5b5990644b5abcd8c4abaa3a GREEN +RemoveOutdatedAnnotationInstanceMigrationProvider.java 245530d6026f9ff29ffc577983d9de03ae5e75e5 GREEN diff --git a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/AddMissingAnnotationsMigrationProvider.java b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/AddMissingAnnotationsMigrationProvider.java index a3f2b3cbcd39f85e15bc998650f899f55d9f563e..ebc5b9348b61ffb23493942949ecccf1c1fa2ae1 100644 --- a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/AddMissingAnnotationsMigrationProvider.java +++ b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/AddMissingAnnotationsMigrationProvider.java @@ -15,6 +15,7 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.migration; +import static java.util.Collections.emptyMap; import static org.fortiss.tooling.base.utils.AnnotationUtils.instantiateAnnotationsRecursive; import java.util.ArrayList; @@ -49,9 +50,11 @@ public class AddMissingAnnotationsMigrationProvider implements IMigrationProvide /** {@inheritDoc} */ @Override - public void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures) { + public Map<EObject, AnyType> migrate(ITopLevelElement modelElement, + Map<EObject, AnyType> unknownFeatures) { EObject rootElement = modelElement.getRootModelElement(); instantiateAnnotationsRecursive(rootElement); migratedProjects.add(modelElement); + return emptyMap(); } } diff --git a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveDuplicatedAnnotationsMigrationProvider.java b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveDuplicatedAnnotationsMigrationProvider.java index f1bdb4733d5b9c6003a2b7fee59b89240a0a3b61..6920909f8f211b9c5b5990644b5abcd8c4abaa3a 100644 --- a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveDuplicatedAnnotationsMigrationProvider.java +++ b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveDuplicatedAnnotationsMigrationProvider.java @@ -15,6 +15,7 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.migration; +import static java.util.Collections.emptyMap; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getChildrenWithType; import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf; import static org.fortiss.tooling.kernel.utils.LoggingUtils.error; @@ -87,7 +88,8 @@ public class RemoveDuplicatedAnnotationsMigrationProvider implements IMigrationP /** {@inheritDoc} */ @Override - public void migrate(ITopLevelElement topLevelElement, Map<EObject, AnyType> unknownFeatures) { + public Map<EObject, AnyType> migrate(ITopLevelElement topLevelElement, + Map<EObject, AnyType> unknownFeatures) { doInternal(topLevelElement, true); @@ -95,5 +97,6 @@ public class RemoveDuplicatedAnnotationsMigrationProvider implements IMigrationP error(ToolingBaseActivator.getDefault(), "Duplicate annotations have been removed from \"" + uri.lastSegment() + "\". Please report this incident since it indicates an internal problem."); + return emptyMap(); } } diff --git a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveOutdatedAnnotationInstanceMigrationProvider.java b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveOutdatedAnnotationInstanceMigrationProvider.java index 29c29f2bb7515cad1de45a30ffc185001b47a016..245530d6026f9ff29ffc577983d9de03ae5e75e5 100644 --- a/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveOutdatedAnnotationInstanceMigrationProvider.java +++ b/org.fortiss.tooling.base/src/org/fortiss/tooling/base/migration/RemoveOutdatedAnnotationInstanceMigrationProvider.java @@ -15,6 +15,7 @@ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.base.migration; +import static java.util.Collections.emptyMap; import static org.eclipse.emf.ecore.util.EcoreUtil.delete; import static org.fortiss.tooling.common.util.LambdaUtils.isAssignableFromAny; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getChildrenWithType; @@ -67,12 +68,14 @@ public abstract class RemoveOutdatedAnnotationInstanceMigrationProvider<T extend /** {@inheritDoc} */ @Override - public void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures) { + public Map<EObject, AnyType> migrate(ITopLevelElement modelElement, + Map<EObject, AnyType> unknownFeatures) { EObject rootModelElement = modelElement.getRootModelElement(); for(T annotation : getChildrenWithType(rootModelElement, annotationType)) { if(!isAssignableFromAny(modelElementTypes, annotation.getSpecificationOf())) { delete(annotation); } } + return emptyMap(); } } diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings index 0a98fb5c57e6ec70b3853c8145ec72ebe32eb99e..b2f23c1f28fd6be6f4cd785dfbd17d06d59c5604 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/.ratings @@ -6,7 +6,7 @@ IEclipseResourceStorageLocationProvider.java 0ab7f304d52a9d86f01f66e308e9a7ca420 IElementCompositor.java 5b0ab1732f71b3f8467e0276c844f0dd549e191f GREEN ILibraryElementHandler.java 00ef5b25c63b8570006e6f6748aed0da1f33a5f1 GREEN ILogMessageHandler.java 9ab53e836a095ef00fd84ecc0375167edf593b46 GREEN -IMigrationProvider.java fdb1078dfca10a82a18f79b862d7b8644e80e14e GREEN +IMigrationProvider.java 241bfd8594dfb86ce0f89dc95b43662f52d9e450 GREEN IPrototypeProvider.java d5e3dbae19b5654caf28b81da6b1609d3c12be12 GREEN IStorageProvider.java d9b14cdd254d0c956dc5715c1c4d4d955a705dd5 GREEN ITransformationProvider.java a4ee2ea08720bb2fce29806062eb01499bb5071e GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/IMigrationProvider.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/IMigrationProvider.java index fdb1078dfca10a82a18f79b862d7b8644e80e14e..241bfd8594dfb86ce0f89dc95b43662f52d9e450 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/IMigrationProvider.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/IMigrationProvider.java @@ -45,12 +45,12 @@ public interface IMigrationProvider extends IObjectAware<ITopLevelElement> { /** * Applies the provider to the given element. * - * The parameter "unknownFeatures" returns a map indicating the features that are not recognized + * The parameter "unknownFeatures" indicates the features that are not recognized * in the model. This can be useful to detect features coming from old models and can be then * translated to the new model by a migrator. * - * The migrator should remove from unknownFeatures the features that it dealt with. - * If one forgets to do so, the migrator will run into an infinite loop! + * @return all unknown features that have successfully been migrated. */ - void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures); + Map<EObject, AnyType> migrate(ITopLevelElement modelElement, + Map<EObject, AnyType> unknownFeatures); } diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/base/RemoveDeprecatedArtifactsMigrationProviderBase.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/base/RemoveDeprecatedArtifactsMigrationProviderBase.java deleted file mode 100644 index 4a1b676223b7ec53259a26d1a671b11ff2f911e2..0000000000000000000000000000000000000000 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/extension/base/RemoveDeprecatedArtifactsMigrationProviderBase.java +++ /dev/null @@ -1,95 +0,0 @@ -/*-------------------------------------------------------------------------+ -| Copyright 2018 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.kernel.extension.base; - -import static org.conqat.lib.commons.reflect.ReflectionUtils.isInstanceOfAny; -import static org.eclipse.emf.ecore.util.EcoreUtil.delete; -import static org.fortiss.tooling.common.util.LambdaUtils.asStream; - -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.xml.type.AnyType; -import org.fortiss.tooling.kernel.extension.IMigrationProvider; -import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; -import org.fortiss.tooling.kernel.model.INamedCommentedElement; - -/** - * Remove artificats related to deprecated use case model. - * - * @author barner - */ -public abstract class RemoveDeprecatedArtifactsMigrationProviderBase implements IMigrationProvider { // NO_UCD - // Migrators are retired after a release, but this base class should be available when needed. - // See https://af3-developer.fortiss.org/projects/autofocus3/wiki/Model_Migration - - /** Returns the {@link Collection} of deprecated artifact types to be removed from the model. */ - protected abstract Collection<Class<? extends EObject>> getDeprecatedArtifacts(); - - /** - * Returns the {@link Collection} of deprecated root artifact types (possibly empty subset of - * {@link #getDeprecatedArtifacts()}) for which a comment is added to the migrated model that - * deprecated artifacts have been removed. - */ - protected abstract Collection<Class<? extends EObject>> getDeprecatedRootArtifacts(); - - /** Returns the {@link Stream} of deprecated model elements to be removed. */ - private Stream<EObject> getDeprecatedModelElements(ITopLevelElement modelElement) { - Stream<EObject> root = asStream(modelElement.getRootModelElement().eAllContents()); - Collection<Class<? extends EObject>> deprArtifacts = getDeprecatedArtifacts(); - return root.filter( - e -> isInstanceOfAny(e, deprArtifacts.toArray(new Class[deprArtifacts.size()]))); - } - - /** {@inheritDoc} */ - - @Override - public boolean needMigration(ITopLevelElement modelElement, - Map<EObject, AnyType> unknownFeatures) { - - return getDeprecatedModelElements(modelElement).findAny().isPresent(); - } - - /** {@inheritDoc} */ - @Override - public void migrate(ITopLevelElement modelElement, Map<EObject, AnyType> unknownFeatures) { - EObject object; - do { - object = null; - Stream<EObject> deprecatedModelElements = getDeprecatedModelElements(modelElement); - Optional<EObject> anyObject = deprecatedModelElements.findAny(); - if(anyObject.isPresent()) { - object = anyObject.get(); - if(object.eContainer() instanceof INamedCommentedElement) { - INamedCommentedElement parent = (INamedCommentedElement)object.eContainer(); - if(parent.getComment() == null || parent.getComment().isEmpty()) { - for(Class<? extends EObject> rootType : getDeprecatedRootArtifacts()) { - if(rootType.isAssignableFrom(object.getClass())) { - parent.setComment(rootType.getSimpleName() + - " models are no longer supported. This sub-model has been removed automatically!"); - break; - } - } - } - } - delete(object); - } - } while(object != null); - } -} diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings index e6e117aec42749c55a27ff79b3607f3b914272f7..2f69b2046501b5917850e19477bc500f81ea116c 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/.ratings @@ -7,7 +7,7 @@ ElementCompositorService.java 98c5d27e09881e60aa4f87c1ac0c7787cdec9f7c GREEN LibraryPrototypeProvider.java b77eddbdca78f561ffb1233e98817be361c690ae GREEN LibraryService.java d22671ba820466062852c15873698adf28960d94 GREEN LoggingService.java da784259f7b456b54bf75c41ec268f64919ce78d GREEN -MigrationService.java 632c13563a3d69681e2a608023fcdadbe5340c4b GREEN +MigrationService.java 2f800eac9793aa736089a802bbfc2c4c1c09770d GREEN PersistencyService.java 103eef642c038ef63fa49b743d803aaa3fea2724 GREEN PrototypeService.java 18c3db05ab11f189a9711bf241c3c7f35c954a9e GREEN ToolingKernelInternal.java d624a5f6b237ce993e150e2b8d1b4390e3fc8f7a GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/MigrationService.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/MigrationService.java index 632c13563a3d69681e2a608023fcdadbe5340c4b..2f800eac9793aa736089a802bbfc2c4c1c09770d 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/MigrationService.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/MigrationService.java @@ -16,18 +16,21 @@ package org.fortiss.tooling.kernel.internal; import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toSet; import static org.fortiss.tooling.kernel.utils.EcoreUtils.getFirstChildWithType; import static org.fortiss.tooling.kernel.utils.LoggingUtils.error; +import static org.fortiss.tooling.kernel.utils.LoggingUtils.warning; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Stream; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.ecore.xml.type.AnyType; import org.fortiss.tooling.kernel.ToolingKernelActivator; import org.fortiss.tooling.kernel.extension.IMigrationProvider; @@ -97,19 +100,6 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider> return false; } - /** Extracts the list of feature names from a map of features. */ - private List<String> featuresToStrings(Map<EObject, AnyType> features) { - List<String> res = new BasicEList<String>(); - for(AnyType featuresPerKey : features.values()) { - FeatureMap actualFeatures = featuresPerKey.getMixed(); - actualFeatures.addAll(featuresPerKey.getAnyAttribute()); - for(FeatureMap.Entry feature : actualFeatures) { - res.add(feature.getEStructuralFeature().getName()); - } - } - return res; - } - /** {@inheritDoc} */ @Override public void migrate(final ITopLevelElement input, final Map<EObject, AnyType> unknownFeatures) { @@ -117,17 +107,12 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider> @Override public void run() { + Map<EObject, AnyType> migratedFeatures = new HashMap<EObject, AnyType>(); for(IMigrationProvider provider : getProviders(input)) { if(provider.needMigration(input, unknownFeatures)) { - provider.migrate(input, unknownFeatures); + migratedFeatures.putAll(provider.migrate(input, unknownFeatures)); } } - if(!unknownFeatures.isEmpty()) { - error(ToolingKernelActivator.getDefault(), - input.getSaveableName() + " contains one or more unknown feature(s): " + - featuresToStrings(unknownFeatures)); - } - for(IMigrationProvider provider : getProviders(input)) { if(provider.needMigration(input, unknownFeatures)) { error(ToolingKernelActivator.getDefault(), @@ -136,6 +121,19 @@ public class MigrationService extends ObjectAwareServiceBase<IMigrationProvider> "already performed. Please fix the migrator (or model)."); } } + unknownFeatures.entrySet().removeAll(migratedFeatures.entrySet()); + if(!unknownFeatures.isEmpty()) { + Stream<AnyType> anyTypes = unknownFeatures.values().stream() + .map(v -> v.getMixed()).flatMap(f -> f.stream()).map(e -> e.getValue()) + .filter(AnyType.class::isInstance).map(AnyType.class::cast); + String removedTypes = anyTypes.map(a -> a.eClass().getName()).collect(toSet()) + .stream().collect(joining(", ")); + warning(ToolingKernelActivator.getDefault(), input.getSaveableName() + + " contains one or more feature(s) of the following unkown types that will be deleted: " + + removedTypes + "."); + + unknownFeatures.clear(); + } } }); diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/.ratings index 4a4edee0b9b29c4f7e79c5026854886346e3d02a..605b741d853bf1e95bbf06c68ab9a477dea3beb5 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/.ratings @@ -1,5 +1,5 @@ AutoUndoCommandStack.java fc326adf66c6cea2354884cdc240da5f2f82689a GREEN EMFTransactionalCommand.java ba4b5bead9768b6ce6c955b9238cd96cb722533c GREEN EclipseResourceStorageService.java e29e32272286921c5e43963253902b3ba54490c7 GREEN -ModelContext.java 55de5f19c5d625f935fb8136ff72d80b3a54ff19 GREEN +ModelContext.java db1735834c85e7b508266f56463d011f2b72af0e GREEN NonDirtyingEMFTransactionalCommand.java d288ebe35d22442c603496b0c917fb99a8febeea GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java index 55de5f19c5d625f935fb8136ff72d80b3a54ff19..db1735834c85e7b508266f56463d011f2b72af0e 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java @@ -330,7 +330,9 @@ class ModelContext implements ITopLevelElement, CommandStackListener { // Step 3..n: Save resources not managed by kernel for(Resource currentResource : rset.getResources()) { - if(currentResource != resource && !editingDomain.isReadOnly(currentResource)) { + if(currentResource != resource && !editingDomain.isReadOnly(currentResource) && + !currentResource.getContents().isEmpty()) { + // do not save resources which are not contained (by a FileProject) try { currentResource.save(saveOptions); } catch(IOException e) { diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/.ratings b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/.ratings index d85861e2edafbeb32da7cbcff68cc64ad45f8ba9..a14d336f35b4b272093a2fc62dcf8c95d8cadab7 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/.ratings +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/.ratings @@ -10,6 +10,6 @@ JavaUtils.java 65cdadfb9137a240ad59992eacf53a15b7f20804 GREEN KernelModelElementUtils.java fded09befe7e543fc04ea5184ffc1c8a309d7a66 GREEN LoggingUtils.java 0e0aa5d466d80ea29cfc7e91178b23a5cdd4ddf7 GREEN PrototypesUtils.java ec75bed75cfc5103f1f38e3a29df86f729428775 GREEN -ResourceUtils.java 698c7db34acb4f1a258a1953e6afcca9823763a8 GREEN +ResourceUtils.java e31eda3fdbedd2e44c85d471f717b14f92a3c663 GREEN TransformationUtils.java 552d3a9d56d34450be781af828efe0b8aa5d359e GREEN UniqueIDUtils.java 665955b1790c1bd1c2087e23114da920bfec2265 GREEN diff --git a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/ResourceUtils.java b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/ResourceUtils.java index 698c7db34acb4f1a258a1953e6afcca9823763a8..e31eda3fdbedd2e44c85d471f717b14f92a3c663 100644 --- a/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/ResourceUtils.java +++ b/org.fortiss.tooling.kernel/src/org/fortiss/tooling/kernel/utils/ResourceUtils.java @@ -51,6 +51,11 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceFactoryImpl; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.xmi.PackageNotFoundException; +import org.eclipse.emf.ecore.xmi.XMLHelper; +import org.eclipse.emf.ecore.xmi.XMLLoad; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.emf.ecore.xmi.impl.SAXXMIHandler; +import org.eclipse.emf.ecore.xmi.impl.XMILoadImpl; import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; import org.eclipse.emf.ecore.xmi.impl.XMLResourceFactoryImpl; import org.eclipse.emf.ecore.xml.type.AnyType; @@ -58,6 +63,7 @@ import org.fortiss.tooling.kernel.ToolingKernelActivator; import org.fortiss.tooling.kernel.extension.data.ITopLevelElement; import org.fortiss.tooling.kernel.model.IIdLabeled; import org.fortiss.tooling.kernel.service.IPersistencyService; +import org.xml.sax.helpers.DefaultHandler; /** * Utility class for dealing with EMF {@link Resource}s. @@ -77,12 +83,79 @@ public final class ResourceUtils { */ public static class KernelResourceFactory extends ResourceFactoryImpl { + /** + * XMIHandler that cleans up dangling references when loading models with unknown types + * instead of throwing an exception. + */ + private final class DanglingReferencesCleanupXMIHandler extends SAXXMIHandler { + /** Constructor. */ + private DanglingReferencesCleanupXMIHandler(XMLResource xmiResource, XMLHelper helper, + Map<?, ?> options) { + super(xmiResource, helper, options); + } + + /** {@inheritDoc} */ + @Override + protected void handleForwardReferences(boolean isEndDocument) { + List<SingleReference> toRemoveFwdSingleRefs = new ArrayList<>(); + for(SingleReference ref : forwardSingleReferences) { + EObject obj; + try { + obj = xmlResource.getEObject((String)ref.getValue()); + } catch(RuntimeException exception) { + obj = null; + } + if(obj == null || obj instanceof AnyType) { + warnRefWithUnknownType((AnyType)obj, ref.getLineNumber(), + ref.getColumnNumber()); + toRemoveFwdSingleRefs.add(ref); + } + } + forwardSingleReferences.removeAll(toRemoveFwdSingleRefs); + + List<ManyReference> toRemoveFwdManyRefs = new ArrayList<>(); + for(ManyReference ref : forwardManyReferences) { + Object[] values = ref.getValues(); + + for(String id : (String[])values) { + + EObject obj; + try { + obj = xmlResource.getEObject(id); + } catch(RuntimeException exception) { + obj = null; + } + if(obj == null || obj instanceof AnyType) { + warnRefWithUnknownType((AnyType)obj, ref.getLineNumber(), + ref.getColumnNumber()); + toRemoveFwdManyRefs.add(ref); + break; + } + } + } + forwardManyReferences.removeAll(toRemoveFwdManyRefs); + + super.handleForwardReferences(isEndDocument); + } + + /** Issues a warning for a given {@link AnyType}d object. */ + private void warnRefWithUnknownType(AnyType obj, int line, int col) { + String message = "Removing reference to element with unknown type" + + (obj != null ? " \"" + obj.eClass().getName() + "\"" : "") + " in line " + + line + ", column " + col + "."; + + // Static inline not possible: name clash with XMLHandler::warning() + LoggingUtils.warning(ToolingKernelActivator.getDefault(), message); + } + } + /** * {@link XMIResourceImpl} used to persist models managed by the tooling kernel. * * @author barner */ private final class KernelXMIResource extends XMIResourceImpl { + /** Constructs a new {@link KernelXMIResource}. */ private KernelXMIResource(URI uri) { super(uri); @@ -99,7 +172,7 @@ public final class ResourceUtils { public String getID(EObject eObject) { String id = super.getID(eObject); if(id == null && eObject instanceof IIdLabeled) { - id = new Integer(((IIdLabeled)eObject).getId()).toString(); + id = String.valueOf(((IIdLabeled)eObject).getId()); setID(eObject, id); } return id; @@ -140,6 +213,18 @@ public final class ResourceUtils { } return eObjectToExtensionMap; } + + /** {@inheritDoc} */ + @Override + protected XMLLoad createXMLLoad() { + return new XMILoadImpl(createXMLHelper()) { + /** {@inheritDoc} */ + @Override + protected DefaultHandler makeDefaultHandler() { + return new DanglingReferencesCleanupXMIHandler(resource, helper, options); + } + }; + } } /** {@inheritDoc} */ @@ -196,13 +281,13 @@ public final class ResourceUtils { /** * <p> - * Determines the {@link ITopLevelElement} which shares the same {@link ResourceSet} as the a - * {@link Resource} with the specified {@link URI}. If no such {@link Resource} has been loaded, - * {@code null} is returned. + * Determines the {@link ITopLevelElement} which shares the same {@link ResourceSet} as the + * a {@link Resource} with the specified {@link URI}. If no such {@link Resource} has been + * loaded, {@code null} is returned. * </p> * <p> - * This is useful to determine to which model managed by the Kernel a given (external) model is - * linked. + * This is useful to determine to which model managed by the Kernel a given (external) model + * is linked. * </p> * * @param uri @@ -226,8 +311,8 @@ public final class ResourceUtils { } /** - * Obtains a model of a given type from a {@code resourceSet}, or {@code null} if it could not - * be found. + * Obtains a model of a given type from a {@code resourceSet}, or {@code null} if it could + * not be found. * * @param resourceSet * {@link ResourceSet} from which model of given type should be determined @@ -251,25 +336,30 @@ public final class ResourceUtils { } /** - * Obtains a model of a given type from a {@code resourceSet}, and creates the model if it does - * not exist yet (and adds it to the given {@code resourceSet}). Returns {@code null} if the - * model could not be created. + * Obtains a model of a given type from a {@code resourceSet}, and creates the model if it + * does not exist yet (and adds it to the given {@code resourceSet}). Returns {@code null} if + * the model could not be created. * * @param resourceSet * {@link ResourceSet} from which model of given type should be determined * @param clazz * Type of model to be returned. * @param factory - * {@link EFactory} to create root model element in case the model does not exist in + * {@link EFactory} to create root model element in case the model does not exist + * in * the {@code resourceSet} yet. * @param fileExtension - * File extension to be used in case a new resource has to be created and added to - * the given given {@code resourceSet}. In case this parameter is {@code null}, this + * File extension to be used in case a new resource has to be created and added + * to + * the given given {@code resourceSet}. In case this parameter is {@code null}, + * this * method effectively behaves like {@link #getModel(ResourceSet, Class)}. * @param referenceClazz - * Type of root model element whose {@link Resource} {@link URI} should be used to + * Type of root model element whose {@link Resource} {@link URI} should be used + * to * derive the base name in case a new {@link Resource} has to be created. In case - * this parameter is {@code null}, the {@link URI} of the first {@link Resource} in + * this parameter is {@code null}, the {@link URI} of the first {@link Resource} + * in * the given {@link ResourceSet} is used. * * @return Model of a given type, or {@code null} if it could not be created. @@ -368,12 +458,14 @@ public final class ResourceUtils { * {@link Resource} for which {@link URI}s of directly or indirectly referencing * resources should be determined. * @param includeSelf - * Flag if the {@link URI} of the given {@code resource} should be contained in the + * Flag if the {@link URI} of the given {@code resource} should be contained in + * the * result. * @param progressMonitor * {@link IProgressMonitor} (may be {@code null}). Loading all resources in a * directory may be a long-running operation. - * @return {@link URI}s of directly or indirectly referencing resources, possibly including the + * @return {@link URI}s of directly or indirectly referencing resources, possibly including + * the * {@link URI} of the given {@code resource} itself (see {@code includeSelf}). */ public static Collection<URI> getReferencingResourceURIs(Resource resource, boolean includeSelf,