From f08e00ecc9ec9ef950f45d4b35c656bbd0174351 Mon Sep 17 00:00:00 2001 From: Simon Haug Date: Wed, 19 Apr 2023 15:09:54 +0200 Subject: [PATCH 1/5] Save ModelInstances delta-based - make ModelInstance a Resource (with delta based (de)serialization) - add new entry for ModelInstances in ResourceFactoryRegistry of models resource set --- .../vsum/internal/ModelInstance.xtend | 93 ++++++++++--------- .../vsum/internal/ModelInstanceFactory.java | 11 +++ .../vsum/internal/ResourceRepositoryImpl.java | 40 +++++--- .../DefaultVirtualModelBasedTestView.xtend | 2 +- .../LegacyVitruvApplicationTest.xtend | 2 +- .../framework/vsum/VirtualModelTest.xtend | 17 ++-- 6 files changed, 94 insertions(+), 71 deletions(-) create mode 100644 bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstanceFactory.java diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend index 0475e803c0..b258e812f3 100644 --- a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend @@ -1,65 +1,68 @@ package tools.vitruv.framework.vsum.internal import java.io.IOException +import java.io.InputStream +import java.io.OutputStream +import java.util.Collections +import java.util.List +import java.util.Map import org.apache.log4j.Logger import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.emf.ecore.resource.impl.ResourceImpl +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl +import tools.vitruv.change.atomic.EChange +import tools.vitruv.change.atomic.id.IdResolver +import tools.vitruv.change.composite.description.VitruviusChangeFactory +import tools.vitruv.framework.views.changederivation.DefaultStateBasedChangeResolutionStrategy -import static com.google.common.base.Preconditions.checkArgument - -class ModelInstance { +class ModelInstance extends ResourceImpl { static val LOGGER = Logger.getLogger(ModelInstance) - @Accessors(PUBLIC_GETTER) - Resource resource - - new(Resource resource) { - checkArgument(resource !== null, "cannot create a model instance for a null resource") - this.resource = resource - LOGGER.debug('''Create model instance for resource with URI: «URI»''') - } - def URI getURI() { - return resource.URI + new(URI uri) { + this.URI = uri + LOGGER.debug('''Create model instance for resource with URI: «uri»''') } def void addRoot(EObject root) { - resource.contents += root - resource.modified = true - LOGGER.debug('''Add root to resource: «resource»''') + this.contents += root + this.modified = true + LOGGER.debug('''Add root to model instance: «this»''') } - - def void markModified() { - resource.modified = true - } - + def boolean isEmpty() { - resource.contents.isEmpty + this.contents.isEmpty } - - def void save() { - if (!resource.modified) { + + private static def List loadDeltas(URI modelUri) { + val resSet = new ResourceSetImpl(); + val resource = resSet.getResource(modelUri, true); + return resource.getContents().map[it as EChange].toList + } + + override doLoad(InputStream inputStream, Map options) throws IOException { + val deltas = loadDeltas(this.URI) + VitruviusChangeFactory.getInstance().createTransactionalChange(deltas).resolveAndApply(IdResolver.create(this.resourceSet)) + } + + override doSave(OutputStream outputStream, Map options) throws IOException { + if (!this.modified) { return } - LOGGER.debug('''Save resource: «resource»''') - try { - resource.save(null) - resource.modified = false - } catch (IOException e) { - LOGGER.error('''Model could not be saved: «URI»''', e) - throw new IllegalStateException('''Could not save URI «URI»''', e) + + val deltaChanges = new DefaultStateBasedChangeResolutionStrategy().getChangeSequenceForCreated(this).EChanges; + val resSet = new ResourceSetImpl(); + val resource = resSet.createResource(this.URI); + resource.getContents().addAll(deltaChanges) + try (val out = outputStream){ + resource.save(out, Collections.EMPTY_MAP) } + + resource.modified = false } - - def void delete() { - LOGGER.debug('''Delete resource: «resource»''') - try { - resource.delete(null) - } catch (IOException e) { - LOGGER.error('''Deletion of resource «resource» did not work.''', e) - throw new IllegalStateException('''Could not delete URI «URI»''', e) - } + + override delete(Map options) throws IOException { + LOGGER.debug('''Delete model instance: «this»''') + super.delete(null) } - -} +} \ No newline at end of file diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstanceFactory.java b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstanceFactory.java new file mode 100644 index 0000000000..899dbb7e7f --- /dev/null +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstanceFactory.java @@ -0,0 +1,11 @@ +package tools.vitruv.framework.vsum.internal; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; + +public class ModelInstanceFactory implements Resource.Factory { + @Override + public Resource createResource(URI uri) { + return new ModelInstance(uri); + } +} diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java index f34d8a4c5d..aa5fb201fd 100644 --- a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java @@ -51,6 +51,7 @@ class ResourceRepositoryImpl implements ModelRepository { ResourceRepositoryImpl(VsumFileSystemLayout fileSystemLayout) { this.fileSystemLayout = fileSystemLayout; this.correspondenceModel = createPersistableCorrespondenceModel(fileSystemLayout.getCorrespondencesURI()); + modelsResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new ModelInstanceFactory()); modelsResourceSet.eAdapters() .add(new ResourceRegistrationAdapter(resource -> getCreateOrLoadModelUnlessLoading(resource.getURI()))); } @@ -71,13 +72,12 @@ private void writeModelsFile() throws IOException { Files.write(fileSystemLayout.getModelsNamesFilesPath(), modelsResourceSet.getResources().stream() .map(Resource::getURI).map(URI::toString).toList()); } - + private void readModelsFile() throws IOException { List modelUris; try { modelUris = Files.readAllLines(fileSystemLayout.getModelsNamesFilesPath()).stream().map(URI::createURI) .toList(); - } catch (NoSuchFileException e) { // There are no existing models, so don't do anything return; @@ -118,13 +118,13 @@ private ModelInstance getCreateOrLoadModel(URI modelUri) { } private ModelInstance createOrLoadModel(URI modelUri) { - Resource resource; + ModelInstance modelInstance; if (modelUri.isFile() || modelUri.isPlatform()) { - resource = getOrCreateResource(modelsResourceSet, modelUri); + modelInstance = (ModelInstance) getOrCreateResource(modelsResourceSet, modelUri); } else { - resource = loadOrCreateResource(modelsResourceSet, modelUri); + modelInstance = (ModelInstance) loadOrCreateResource(modelsResourceSet, modelUri); } - ModelInstance modelInstance = new ModelInstance(resource); + modelInstances.put(modelUri, modelInstance); registerRecorder(modelInstance); return modelInstance; @@ -133,7 +133,7 @@ private ModelInstance createOrLoadModel(URI modelUri) { private void registerRecorder(ModelInstance modelInstance) { // Only monitor modifiable models (file / platform URIs, not pathmap URIs) if (modelInstance.getURI().isFile() || modelInstance.getURI().isPlatform()) { - changeRecorder.addToRecording(modelInstance.getResource()); + changeRecorder.addToRecording(modelInstance); if (isRecording && !changeRecorder.isRecording()) { changeRecorder.beginRecording(); } @@ -154,10 +154,20 @@ public void saveOrDeleteModels() { while (modelInstancesIterator.hasNext()) { ModelInstance modelInstance = modelInstancesIterator.next().getValue(); if (modelInstance.isEmpty()) { - modelInstance.delete(); + try { + modelInstance.delete(null); + } catch (IOException e) { + LOGGER.error("Model could not be deleted: " + modelInstance.getURI(), e); + throw new IllegalStateException("Could not delete URI " + modelInstance.getURI(), e); + } modelInstancesIterator.remove(); } else { - modelInstance.save(); + try { + modelInstance.save(null); + } catch (IOException e) { + LOGGER.error("Model could not be saved: "+ modelInstance.getURI(), e); + throw new IllegalStateException("Could not save URI " + modelInstance.getURI(), e); + } } } correspondenceModel.save(); @@ -168,7 +178,7 @@ public void saveOrDeleteModels() { throw new IllegalStateException(e); } } - + @Override public Iterable recordChanges(Runnable changeApplicator) { changeRecorder.beginRecording(); @@ -187,22 +197,22 @@ public Iterable recordChanges(Runnable changeApplicator) { public VitruviusChange applyChange(VitruviusChange change) { return change.resolveAndApply(uuidResolver); } - + @Override public URI getMetadataModelURI(String... metadataKey) { return fileSystemLayout.getConsistencyMetadataModelURI(metadataKey); } - + @Override public Resource getModelResource(URI uri) { - return getCreateOrLoadModel(uri).getResource(); + return getCreateOrLoadModel(uri); } @Override public Collection getModelResources() { return modelsResourceSet.getResources(); } - + @Override public void close() { changeRecorder.close(); @@ -210,4 +220,4 @@ public void close() { modelsResourceSet.getResources().clear(); uuidResolver.endTransaction(); } -} +} \ No newline at end of file diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend index 21b0c31a11..b8c09d134f 100644 --- a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend @@ -39,7 +39,7 @@ class DefaultVirtualModelBasedTestView implements VirtualModelBasedTestView, Non private def NonTransactionalTestView generateTestView(Path testProjectPath, TestUserInteraction userInteraction) { new ChangePublishingTestView(testProjectPath, userInteraction, this.uriMode, virtualModel, - virtualModel.uuidResolver)[virtualModel.getModelInstance(it)?.resource] + virtualModel.uuidResolver)[virtualModel.getModelInstance(it)] } override getVirtualModel() { diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/LegacyVitruvApplicationTest.xtend b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/LegacyVitruvApplicationTest.xtend index a8eac4e23c..d8b686fe4a 100644 --- a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/LegacyVitruvApplicationTest.xtend +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/LegacyVitruvApplicationTest.xtend @@ -52,7 +52,7 @@ abstract class LegacyVitruvApplicationTest extends VitruvApplicationTest impleme private def dispatch EObject resolveInVirtualModel(EObject object) { if (object.eResource !== null) { - internalVirtualModel.getModelInstance(object.eResource.URI).resource.getEObject( + internalVirtualModel.getModelInstance(object.eResource.URI).getEObject( object.hierarchicUriFragment) } } diff --git a/tests/tools.vitruv.framework.vsum.tests/src/tools/vitruv/framework/vsum/VirtualModelTest.xtend b/tests/tools.vitruv.framework.vsum.tests/src/tools/vitruv/framework/vsum/VirtualModelTest.xtend index d505b0b25c..7391a84684 100644 --- a/tests/tools.vitruv.framework.vsum.tests/src/tools/vitruv/framework/vsum/VirtualModelTest.xtend +++ b/tests/tools.vitruv.framework.vsum.tests/src/tools/vitruv/framework/vsum/VirtualModelTest.xtend @@ -65,7 +65,7 @@ class VirtualModelTest { val recordedChange = changeRecorder.endRecording(uuidResolver) virtualModel.propagateChange(recordedChange) val vsumModel = virtualModel.getModelInstance(createTestModelResourceUri("")) - assertThat(vsumModel.resource, containsModelOf(monitoredResource)) + assertThat(vsumModel, containsModelOf(monitoredResource)) } @Test @@ -87,9 +87,9 @@ class VirtualModelTest { val sorceModel = virtualModel.getModelInstance(createTestModelResourceUri("")) val targetModel = virtualModel.getModelInstance( RedundancyChangePropagationSpecification.getTargetResourceUri(createTestModelResourceUri(""))) - assertThat(targetModel.resource, containsModelOf(monitoredResource)) + assertThat(targetModel, containsModelOf(monitoredResource)) assertEquals(1, - virtualModel.correspondenceModel.getCorrespondingEObjects(sorceModel.resource.contents.get(0)).size) + virtualModel.correspondenceModel.getCorrespondingEObjects(sorceModel.contents.get(0)).size) } @Test @@ -177,8 +177,7 @@ class VirtualModelTest { ] val recordedChange = changeRecorder.endRecording(uuidResolver) virtualModel.propagateChange(recordedChange) - val reloadedResource = new ResourceSetImpl().withGlobalFactories.getResource(createTestModelResourceUri(""), - true) + val reloadedResource = createAndLoadTestVirtualModelWithConsistencyPreservation(pathToVirtualModelProjectFolder).getModelInstance(createTestModelResourceUri("")) assertThat(reloadedResource, containsModelOf(monitoredResource)) } @@ -202,7 +201,7 @@ class VirtualModelTest { val originalModel = virtualModel.getModelInstance(createTestModelResourceUri("")) val reloadedVirtualModel = createAndLoadTestVirtualModel(pathToVirtualModelProjectFolder) val reloadedModel = reloadedVirtualModel.getModelInstance(createTestModelResourceUri("")) - assertThat(reloadedModel.resource, containsModelOf(monitoredResource)) + assertThat(reloadedModel, containsModelOf(monitoredResource)) assertNotEquals(originalModel, reloadedModel) // Propagate another change to reloaded virtual model to ensure that everything is loaded correctly changeRecorder.beginRecording @@ -232,13 +231,13 @@ class VirtualModelTest { val originalModel = virtualModel.getModelInstance(createTestModelResourceUri("")) val reloadedVirtualModel = createAndLoadTestVirtualModel(pathToVirtualModelProjectFolder) val reloadedModel = reloadedVirtualModel.getModelInstance(createTestModelResourceUri("")) - assertThat(reloadedModel.resource, containsModelOf(monitoredResource)) + assertThat(reloadedModel, containsModelOf(monitoredResource)) assertNotEquals(originalModel, reloadedModel) val reloadedTargetModel = reloadedVirtualModel.getModelInstance( RedundancyChangePropagationSpecification.getTargetResourceUri(createTestModelResourceUri(""))) - assertThat(reloadedTargetModel.resource, containsModelOf(monitoredResource)) + assertThat(reloadedTargetModel, containsModelOf(monitoredResource)) assertEquals(1, - reloadedVirtualModel.correspondenceModel.getCorrespondingEObjects(reloadedModel.resource.contents.get(0)). + reloadedVirtualModel.correspondenceModel.getCorrespondingEObjects(reloadedModel.contents.get(0)). size) } From 8f5a75461a87951e60af01e902560182795278ad Mon Sep 17 00:00:00 2001 From: Simon Haug Date: Thu, 20 Apr 2023 10:22:22 +0200 Subject: [PATCH 2/5] move ResourceCopier to SDQ-Commons - requires approval of https://github.com/kit-sdq/SDQ-Commons/pull/38 --- ...ltStateBasedChangeResolutionStrategy.xtend | 2 +- .../views/impl/ChangeDerivingView.xtend | 2 +- .../views/impl/IdentityMappingViewType.java | 2 +- .../framework/views/util/ResourceCopier.xtend | 192 ------------------ .../views/util/XmiIdEdgeCaseTest.java | 1 + 5 files changed, 4 insertions(+), 195 deletions(-) delete mode 100644 bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/util/ResourceCopier.xtend diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend index 9d1fcb7269..b05b679bdc 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend @@ -17,13 +17,13 @@ import tools.vitruv.change.atomic.EChangeIdManager import tools.vitruv.change.atomic.id.IdResolver import tools.vitruv.change.composite.description.VitruviusChange import tools.vitruv.change.composite.recording.ChangeRecorder -import tools.vitruv.framework.views.util.ResourceCopier import static com.google.common.base.Preconditions.checkArgument import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceUtil.getReferencedProxies import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyBackward import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyForward +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceCopier /** * This default strategy for diff based state changes uses EMFCompare to resolve a diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend index cd49ae4d48..ee6827a59e 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend @@ -12,12 +12,12 @@ import tools.vitruv.change.composite.description.VitruviusChangeFactory import tools.vitruv.framework.views.CommittableView import tools.vitruv.framework.views.View import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy -import tools.vitruv.framework.views.util.ResourceCopier import static com.google.common.base.Preconditions.checkArgument import static com.google.common.base.Preconditions.checkState import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.common.util.URIUtil.isPathmap +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceCopier /** * A {@link View} that derives changes based on the changed state of its resources and allows to propagate them diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java index 21af16be71..9ec672a7a4 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java @@ -13,6 +13,7 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceCopier; import tools.vitruv.change.atomic.EChangeUuidManager; import tools.vitruv.change.atomic.id.IdResolver; import tools.vitruv.change.atomic.uuid.UuidResolver; @@ -22,7 +23,6 @@ import tools.vitruv.framework.views.ViewSelection; import tools.vitruv.framework.views.ViewSource; import tools.vitruv.framework.views.selectors.DirectViewElementSelector; -import tools.vitruv.framework.views.util.ResourceCopier; /** * A view type that allows creating views based on a basic element-wise diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/util/ResourceCopier.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/util/ResourceCopier.xtend deleted file mode 100644 index 67fd5aa12a..0000000000 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/util/ResourceCopier.xtend +++ /dev/null @@ -1,192 +0,0 @@ -package tools.vitruv.framework.views.util - -import edu.kit.ipd.sdq.activextendannotations.Utility -import java.nio.file.Files -import java.util.HashMap -import java.util.Map -import org.eclipse.emf.common.util.URI -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.emf.ecore.resource.ResourceSet -import org.eclipse.emf.ecore.util.EcoreUtil -import org.eclipse.emf.ecore.util.EcoreUtil.Copier -import org.eclipse.emf.ecore.xmi.XMLResource - -import static extension com.google.common.base.Preconditions.checkNotNull -import static extension com.google.common.base.Preconditions.checkState -import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.common.util.URIUtil.isPathmap - -/** - * A utility class to create copies of resources. - */ -@Utility -class ResourceCopier { - /** - * Indicates whether the given resource requires a full copy. - * If false is returned, the resource supports a partial copy, - * i.e. not all root elements need to be contained in the copy. - */ - static def boolean requiresFullCopy(Resource resource) { - resource.isWritableUmlResource - } - - /** - * Copies some or all of the elements and references in the given view source resources to the given new resource set. - * The copied root elements can be restricted with the rootElementPredicate. - * - * @param originalResources The view source resources to copy - * @param newResourceSet The resource set to which the copies are attached - * @param rootElementPredicate A predicate to include only a subset of the root elements of the originalResources - * @returns A mapping from each original resource to its copy - */ - static def Map copyViewSourceResources(Iterable originalResources, - ResourceSet newResourceSet, (EObject)=>Boolean rootElementPredicate) { - // do not copy xmi:id for view source resources as the change recorder does not record them - // and thus the information will be lost when propagating changes back to the view source - copyResources(originalResources, newResourceSet, false, rootElementPredicate) - } - - /** - * Copies all elements and references in the given view resources to the given new resource set. - * - * @param originalResources The view resources to copy - * @param newResourceSet The resource set to which the copies are attached - * @returns A mapping from each original resource to its copy - */ - static def Map copyViewResources(Iterable originalResources, - ResourceSet newResourceSet) { - // copy xmi:id for view resources such that an exact copy is created - // this is e.g. necessary for change deriving strategies that rely on identifiers - copyResources(originalResources, newResourceSet, true)[true] - } - - /** - * Copies all elements and references in the give view resource to the given new resource set. - * - * @param originalResource The view resource to copy - * @param newResourceSet The resource set to which the copy is attached - * @returns The newly created copy of the resource - */ - static def Resource copyViewResource(Resource originalResource, ResourceSet newResourceSet) { - val mapping = copyViewResources(#[originalResource], newResourceSet) - return mapping.get(originalResource) - } - - private static def Map copyResources(Iterable originalResources, - ResourceSet newResourceSet, Boolean copyXmlIds, (EObject)=>Boolean rootElementPredicate) { - val resourceMapping = new HashMap() - for (umlResource : originalResources.filter[isWritableUmlResource].toList) { - val copy = copyUmlResource(umlResource, newResourceSet) - if (copyXmlIds) { - if (umlResource instanceof XMLResource && copy instanceof XMLResource) { - copyUmlIds(umlResource as XMLResource, copy as XMLResource) - } - } - resourceMapping.put(umlResource, copy) - } - val otherMapping = originalResources.filter[!isWritableUmlResource].toList.copyResourcesInternal(newResourceSet, - copyXmlIds, rootElementPredicate) - otherMapping.keySet.forEach[resourceMapping.put(it, otherMapping.get(it))] - return resourceMapping - } - - /** - * NOTE: This is a hack, because {@link EcoreUtil#copyAll} does not work for UML models. - * This is due to the fact that the UML metamodel uses some weird manually and partly derived - * collections, which are not properly handled by the ordinary {@link EcoreUtil.Copier}. - * For example, the {@linkplain InterfaceRealization.clients} are a set of manually added - * elements combined with the {@linkplain InterfaceRealization.implementingClassifier}, which, - * in turn, is just the {@code eContainer} of the interface realization. The copier copies - * this implementing classifier reference although it is automatically inferred by the metamodel - * implementation, such that after the copy process the {@linkplain InterfaceRelization.clients} - * reference contains the according element twice. This happens at different places in the - * UML models. - * To circumvent the issue, we store the UML model to a temporary resource and reload it, - * because save/load properly handles the situation not covered by the copier. - */ - private static def Resource copyUmlResource(Resource originalResource, ResourceSet newResourceSet) { - val originalURI = originalResource.URI - val tempFilePath = Files.createTempFile(null, "." + originalURI.fileExtension) - val tempURI = URI.createFileURI(tempFilePath.toString) - originalResource.URI = tempURI - originalResource.save(null) - originalResource.URI = originalURI - val copiedResource = newResourceSet.getResource(tempURI, true) - copiedResource.URI = originalURI - Files.delete(tempFilePath) - EcoreUtil.resolveAll(copiedResource) - return copiedResource - } - - /** - * Copies the selected elements in the given resources to the given new resource set. - * It is necessary to process all resources together, because there may be elements that are root - * elements of one resource but have a container in another resource (e.g. a Java CompilationUnit - * is root of a resource but can be contained in a package persisted in another resource). - * We must NOT copy these elements but only copy the containing element and then resolve it to avoid - * element duplication. - */ - private static def Map copyResourcesInternal(Iterable originalResources, - ResourceSet newResourceSet, Boolean copyXmlIds, (EObject)=>Boolean rootElementPredicate) { - val copier = new Copier(true) - var resourceMapping = new HashMap() - for (originalResource : originalResources) { - val elementsContainedInResource = originalResource.contents.filter [ - !isContainedInOtherThanOwnResource(originalResources) - ].toList - copier.copyAll(elementsContainedInResource) - } - copier.copyReferences() - for (originalResource : originalResources) { - val copiedResource = newResourceSet.resourceFactoryRegistry?.getFactory(originalResource.URI)?. - createResource(originalResource.URI).checkNotNull("Cannot create resource copy: %s", - originalResource.URI) - val selectedRootElements = originalResource.contents.filter[rootElementPredicate.apply(it)] - val mappedRootElements = selectedRootElements.map [ - checkNotNull(copier.get(it), "corresponding object for %s is null", it) - ] - copiedResource.contents.addAll(mappedRootElements) - newResourceSet.resources += copiedResource - resourceMapping.put(originalResource, copiedResource) - } - - if (copyXmlIds) { - for (entry: copier.entrySet) { - val sourceElement = entry.key - val targetElement = entry.value - if (sourceElement.eResource instanceof XMLResource && targetElement.eResource instanceof XMLResource) { - val id = (sourceElement.eResource as XMLResource).getID(sourceElement) - (targetElement.eResource as XMLResource).setID(targetElement, id) - } - } - } - return resourceMapping - } - - private static def boolean isContainedInOtherThanOwnResource(EObject eObject, Iterable resources) { - val rootContainerResource = EcoreUtil.getRootContainer(eObject).eResource - return rootContainerResource !== eObject.eResource && resources.contains(rootContainerResource) - } - - private static def boolean isWritableUmlResource(Resource resource) { - resource.URI.fileExtension == "uml" && !resource.URI.isPathmap - } - - /** - * Copies the IDs of the source's elements to the target. - * It is expected that both resources are in an identical state. - */ - private static def void copyUmlIds(XMLResource source, XMLResource target) { - val sourceIterator = source.allContents - val targetIterator = target.allContents - while (sourceIterator.hasNext && targetIterator.hasNext) { - val sourceObject = sourceIterator.next - val targetObject = targetIterator.next - checkState(sourceObject.eClass === targetObject.eClass, "non matching elements %s and %s", sourceObject, - targetObject) - target.setID(targetObject, source.getID(sourceObject)) - } - checkState(!sourceIterator.hasNext, "source uml resource has too many elements") - checkState(!targetIterator.hasNext, "target uml resource has too many elements") - } -} diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/util/XmiIdEdgeCaseTest.java b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/util/XmiIdEdgeCaseTest.java index ce2cf79b28..b5ea0cf865 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/util/XmiIdEdgeCaseTest.java +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/util/XmiIdEdgeCaseTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import edu.kit.ipd.sdq.commons.util.java.Pair; +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceCopier; import tools.vitruv.testutils.RegisterMetamodelsInStandalone; import tools.vitruv.testutils.TestLogging; import tools.vitruv.testutils.TestProject; From 13c9d3926a287c540e4ddbbb431b75c5d02c5e89 Mon Sep 17 00:00:00 2001 From: Simon Haug Date: Tue, 25 Apr 2023 10:11:20 +0200 Subject: [PATCH 3/5] move changederivation into Vitruv-Change project - depends on commit to Vitruv-Change project --- .../META-INF/MANIFEST.MF | 1 + .../tools/vitruv/framework/views/View.java | 4 +- ...ltStateBasedChangeResolutionStrategy.xtend | 134 ------------------ .../StateBasedChangeResolutionStrategy.java | 53 ------- .../framework/views/impl/BasicView.xtend | 2 +- .../views/impl/ChangeDerivingView.xtend | 2 +- .../views/impl/ChangeRecordingView.xtend | 2 +- .../META-INF/MANIFEST.MF | 3 +- .../vsum/internal/ModelInstance.xtend | 2 +- .../META-INF/MANIFEST.MF | 3 +- .../vitruv/testutils/TestViewFactory.java | 2 +- .../META-INF/MANIFEST.MF | 3 +- .../BasicStateChangePropagationTest.xtend | 2 + .../EdgeCaseStateChangeTest.xtend | 1 + .../changederivation/PcmStateChangeTest.xtend | 1 + .../StateChangePropagationTest.xtend | 2 + .../changederivation/UmlStateChangeTest.xtend | 2 + .../views/impl/ChangeDerivingViewTest.java | 2 +- 18 files changed, 23 insertions(+), 198 deletions(-) delete mode 100644 bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend delete mode 100644 bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/StateBasedChangeResolutionStrategy.java diff --git a/bundles/tools.vitruv.framework.views/META-INF/MANIFEST.MF b/bundles/tools.vitruv.framework.views/META-INF/MANIFEST.MF index e96ea43e07..8865f6a331 100644 --- a/bundles/tools.vitruv.framework.views/META-INF/MANIFEST.MF +++ b/bundles/tools.vitruv.framework.views/META-INF/MANIFEST.MF @@ -15,3 +15,4 @@ Require-Bundle: org.apache.log4j, Export-Package: tools.vitruv.framework.views, tools.vitruv.framework.views.changederivation Bundle-Vendor: vitruv.tools +Import-Package: tools.vitruv.change.changederivation diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/View.java b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/View.java index 210fa714f1..cf0b784f24 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/View.java +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/View.java @@ -8,8 +8,8 @@ import com.google.common.annotations.Beta; import com.google.common.collect.FluentIterable; -import tools.vitruv.framework.views.changederivation.DefaultStateBasedChangeResolutionStrategy; -import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy; +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy; +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy; /** * A Vitruv view on an underlying {@link ChangeableViewSource}. diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend deleted file mode 100644 index b05b679bdc..0000000000 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/DefaultStateBasedChangeResolutionStrategy.xtend +++ /dev/null @@ -1,134 +0,0 @@ -package tools.vitruv.framework.views.changederivation - -import org.eclipse.emf.common.notify.Notifier -import org.eclipse.emf.common.util.BasicMonitor -import org.eclipse.emf.compare.EMFCompare -import org.eclipse.emf.compare.match.impl.MatchEngineFactoryImpl -import org.eclipse.emf.compare.match.impl.MatchEngineFactoryRegistryImpl -import org.eclipse.emf.compare.merge.BatchMerger -import org.eclipse.emf.compare.merge.IMerger -import org.eclipse.emf.compare.scope.DefaultComparisonScope -import org.eclipse.emf.compare.utils.UseIdentifiers -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.emf.ecore.resource.ResourceSet -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl -import org.eclipse.emf.ecore.util.EcoreUtil -import tools.vitruv.change.atomic.EChangeIdManager -import tools.vitruv.change.atomic.id.IdResolver -import tools.vitruv.change.composite.description.VitruviusChange -import tools.vitruv.change.composite.recording.ChangeRecorder - -import static com.google.common.base.Preconditions.checkArgument - -import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceUtil.getReferencedProxies -import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyBackward -import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyForward -import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceCopier - -/** - * This default strategy for diff based state changes uses EMFCompare to resolve a - * diff to a sequence of individual changes. - */ -class DefaultStateBasedChangeResolutionStrategy implements StateBasedChangeResolutionStrategy { - /** The identifier matching behavior used by this strategy */ - public val UseIdentifiers useIdentifiers - - /** - * Creates a new instance with the default identifier matching behavior - * which is match by identifier when available. - */ - new() { - this(UseIdentifiers.WHEN_AVAILABLE) - } - - /** - * Creates a new instance with the provided identifier matching behavior. - * @param useIdentifiers The identifier matching behavior to use. - */ - new(UseIdentifiers useIdentifiers) { - this.useIdentifiers = useIdentifiers - } - - private def checkNoProxies(Resource resource, String stateNotice) { - val proxies = resource.referencedProxies - checkArgument(proxies.empty, "%s '%s' should not contain proxies, but contains the following: %s", stateNotice, - resource.URI, String.join(", ", proxies.map[toString])) - } - - override getChangeSequenceBetween(Resource newState, Resource oldState) { - checkArgument(oldState !== null && newState !== null, "old state or new state must not be null!") - newState.checkNoProxies("new state") - oldState.checkNoProxies("old state") - val monitoredResourceSet = new ResourceSetImpl() - val currentStateCopy = ResourceCopier.copyViewResource(oldState, monitoredResourceSet) - return currentStateCopy.record [ - if (oldState.URI != newState.URI) { - currentStateCopy.URI = newState.URI - } - compareStatesAndReplayChanges(newState, currentStateCopy) - ] - } - - override getChangeSequenceForCreated(Resource newState) { - checkArgument(newState !== null, "new state must not be null!") - newState.checkNoProxies("new state") - // It is possible that root elements are automatically generated during resource creation (e.g., Java packages). - // Thus, we create the resource and then monitor the re-insertion of the elements - val monitoredResourceSet = new ResourceSetImpl() - val newResource = monitoredResourceSet.createResource(newState.URI) - newResource.contents.clear() - return newResource.record [ - newResource.contents += EcoreUtil.copyAll(newState.contents) - ] - } - - override getChangeSequenceForDeleted(Resource oldState) { - checkArgument(oldState !== null, "old state must not be null!") - oldState.checkNoProxies("old state") - // Setup resolver and copy state: - val monitoredResourceSet = new ResourceSetImpl() - val currentStateCopy = ResourceCopier.copyViewResource(oldState, monitoredResourceSet) - return currentStateCopy.record [ - currentStateCopy.contents.clear() - ] - } - - private def record(Resource resource, ()=>void function) { - try (val changeRecorder = new ChangeRecorder(resource.resourceSet)) { - changeRecorder.beginRecording - changeRecorder.addToRecording(resource) - function.apply() - val recordedChanges = changeRecorder.endRecording - assignIds(recordedChanges, resource.resourceSet) - return recordedChanges.unresolve - } - } - - private def void assignIds(VitruviusChange recordedChange, ResourceSet resourceSet) { - val changes = recordedChange.EChanges - val idResolver = IdResolver.create(resourceSet) - val eChangeIdManager = new EChangeIdManager(idResolver) - changes.toList.reverseView.forEach[applyBackward] - changes.forEach[ change | - eChangeIdManager.setOrGenerateIds(change) - change.applyForward(idResolver) - ] - } - - /** - * Compares states using EMFCompare and replays the changes to the current state. - */ - private def compareStatesAndReplayChanges(Notifier newState, Notifier currentState) { - val scope = new DefaultComparisonScope(newState, currentState, null) - val emfCompare = (EMFCompare.builder => [ - matchEngineFactoryRegistry = MatchEngineFactoryRegistryImpl.createStandaloneInstance => [ - add(new MatchEngineFactoryImpl(useIdentifiers)) - ] - ]).build - val differences = emfCompare.compare(scope).differences - // Replay the EMF compare differences - val mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance() - val merger = new BatchMerger(mergerRegistry) - merger.copyAllLeftToRight(differences, new BasicMonitor) - } -} diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/StateBasedChangeResolutionStrategy.java b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/StateBasedChangeResolutionStrategy.java deleted file mode 100644 index a0cbe75393..0000000000 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/changederivation/StateBasedChangeResolutionStrategy.java +++ /dev/null @@ -1,53 +0,0 @@ -package tools.vitruv.framework.views.changederivation; - -import org.eclipse.emf.ecore.resource.Resource; - -import tools.vitruv.change.composite.description.VitruviusChange; - -/** - * Strategy for resolving state-based changes to individual change sequences. - * This strategy is used by the domains when there are no change sequences - * available and changes need to be propagated based on the difference between - * the old and new state. - */ -public interface StateBasedChangeResolutionStrategy { - - /** - * Resolves the state-based delta of two resources and returns the correlating - * change sequences. Changes must use hierarchical IDs and are returned - * unresolved. The {@code oldState} remains unmodified from calling this method. - * - * @param newState is the new state of the resource, must not be - * null and must not contain proxies. - * @param oldState is the current or old state of the resource, must not be - * null and must not contain proxies. - * @return a unresolved {@link VitruviusChange} that contains the individual - * change sequence. - */ - VitruviusChange getChangeSequenceBetween(Resource newState, Resource oldState); - - /** - * Resolves the state-based delta for creating the given resource and returns - * the correlating change sequences. Changes must use hierarchical IDs and are - * returned unresolved. - * - * @param newState is the new state of the resource, must not be - * null and must not contain proxies. - * @return a unresolved {@link VitruviusChange} that contains the individual - * change sequence. - */ - VitruviusChange getChangeSequenceForCreated(Resource newState); - - /** - * Resolves the state-based delta for deleting the given resource and returns - * the correlating change sequences. Changes must use hierarchical IDs and are - * returned unresolved. The {@code oldState} remains unmodified from calling - * this method. - * - * @param oldState is the new state of the resource, must not be - * null and must not contain proxies. - * @return a unresolved {@link VitruviusChange} that contains the individual - * change sequence. - */ - VitruviusChange getChangeSequenceForDeleted(Resource oldState); -} diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend index a73a0c50d5..eb7f3fc8d6 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend @@ -15,7 +15,7 @@ import tools.vitruv.change.composite.propagation.ChangePropagationListener import tools.vitruv.framework.views.ChangeableViewSource import tools.vitruv.framework.views.ViewSelection import tools.vitruv.framework.views.ViewSelector -import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy import static com.google.common.base.Preconditions.checkArgument import static com.google.common.base.Preconditions.checkState diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend index ee6827a59e..d6c5de859d 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeDerivingView.xtend @@ -11,7 +11,7 @@ import tools.vitruv.change.composite.description.VitruviusChange import tools.vitruv.change.composite.description.VitruviusChangeFactory import tools.vitruv.framework.views.CommittableView import tools.vitruv.framework.views.View -import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy import static com.google.common.base.Preconditions.checkArgument import static com.google.common.base.Preconditions.checkState diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeRecordingView.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeRecordingView.xtend index d8c0938d6e..6366e715b7 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeRecordingView.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/ChangeRecordingView.xtend @@ -8,7 +8,7 @@ import tools.vitruv.change.atomic.id.IdResolver import tools.vitruv.change.composite.recording.ChangeRecorder import tools.vitruv.framework.views.CommittableView import tools.vitruv.framework.views.View -import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy import static com.google.common.base.Preconditions.checkArgument import static com.google.common.base.Preconditions.checkState diff --git a/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF b/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF index 4abb89d0e1..fab623be6e 100644 --- a/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF +++ b/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF @@ -13,7 +13,8 @@ Require-Bundle: org.apache.log4j, org.eclipse.emf.ecore.xmi, edu.kit.ipd.sdq.activextendannotations, edu.kit.ipd.sdq.commons.util.emf, - edu.kit.ipd.sdq.commons.util.java + edu.kit.ipd.sdq.commons.util.java, + tools.vitruv.change.changederivation Export-Package: tools.vitruv.framework.vsum, tools.vitruv.framework.vsum.internal;x-internal:=true Bundle-Vendor: vitruv.tools diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend index b258e812f3..e8bca0e4da 100644 --- a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend @@ -14,7 +14,7 @@ import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl import tools.vitruv.change.atomic.EChange import tools.vitruv.change.atomic.id.IdResolver import tools.vitruv.change.composite.description.VitruviusChangeFactory -import tools.vitruv.framework.views.changederivation.DefaultStateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy class ModelInstance extends ResourceImpl { static val LOGGER = Logger.getLogger(ModelInstance) diff --git a/bundles/tools.vitruv.testutils.vsum/META-INF/MANIFEST.MF b/bundles/tools.vitruv.testutils.vsum/META-INF/MANIFEST.MF index 6d62fbad54..7cd757162b 100644 --- a/bundles/tools.vitruv.testutils.vsum/META-INF/MANIFEST.MF +++ b/bundles/tools.vitruv.testutils.vsum/META-INF/MANIFEST.MF @@ -7,7 +7,8 @@ Bundle-Vendor: tools.vitruv Automatic-Module-Name: tools.vitruv.testutils.vsum Bundle-RequiredExecutionEnvironment: JavaSE-17 Import-Package: org.junit.jupiter.api, - org.junit.jupiter.api.extension + org.junit.jupiter.api.extension, + tools.vitruv.change.changederivation Require-Bundle: com.google.guava, org.eclipse.xtext.xbase.lib, org.eclipse.xtend.lib, diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestViewFactory.java b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestViewFactory.java index 42854a80a8..9fb0a36b06 100644 --- a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestViewFactory.java +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestViewFactory.java @@ -7,12 +7,12 @@ import java.util.Collection; import java.util.function.Consumer; +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy; import tools.vitruv.framework.views.CommittableView; import tools.vitruv.framework.views.View; import tools.vitruv.framework.views.ViewProvider; import tools.vitruv.framework.views.ViewSelector; import tools.vitruv.framework.views.ViewTypeFactory; -import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionStrategy; public class TestViewFactory { private final ViewProvider viewProvider; diff --git a/tests/tools.vitruv.framework.views.tests/META-INF/MANIFEST.MF b/tests/tools.vitruv.framework.views.tests/META-INF/MANIFEST.MF index 7c13bd456e..c0ee65e382 100644 --- a/tests/tools.vitruv.framework.views.tests/META-INF/MANIFEST.MF +++ b/tests/tools.vitruv.framework.views.tests/META-INF/MANIFEST.MF @@ -10,7 +10,8 @@ Import-Package: org.junit.jupiter.api, org.junit.jupiter.api.extension, org.junit.jupiter.api.function, org.junit.jupiter.params, - org.junit.jupiter.params.provider + org.junit.jupiter.params.provider, + tools.vitruv.change.changederivation Require-Bundle: org.apache.log4j, tools.vitruv.testutils.vsum, tools.vitruv.testutils.metamodels, diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/BasicStateChangePropagationTest.xtend b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/BasicStateChangePropagationTest.xtend index 72de3cdc17..071e6c6f0e 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/BasicStateChangePropagationTest.xtend +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/BasicStateChangePropagationTest.xtend @@ -23,6 +23,8 @@ import static tools.vitruv.testutils.metamodels.AllElementTypesCreators.aet import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.withGlobalFactories import static extension tools.vitruv.testutils.Capture.operator_doubleGreaterThan +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy class BasicStateChangePropagationTest extends StateChangePropagationTest { private def getTestUri() { diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/EdgeCaseStateChangeTest.xtend b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/EdgeCaseStateChangeTest.xtend index e5d30778eb..46b8086c0c 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/EdgeCaseStateChangeTest.xtend +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/EdgeCaseStateChangeTest.xtend @@ -5,6 +5,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import static org.junit.jupiter.api.Assertions.assertThrows +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy class EdgeCaseStateChangeTest extends StateChangePropagationTest { diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/PcmStateChangeTest.xtend b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/PcmStateChangeTest.xtend index 64ac2d08d9..a0d7d8a6b2 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/PcmStateChangeTest.xtend +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/PcmStateChangeTest.xtend @@ -4,6 +4,7 @@ import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import static tools.vitruv.testutils.metamodels.PcmMockupCreators.pcm +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy class PcmStateChangeTest extends StateChangePropagationTest { @ParameterizedTest() diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/StateChangePropagationTest.xtend b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/StateChangePropagationTest.xtend index a03126e8f9..ce1bab8555 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/StateChangePropagationTest.xtend +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/StateChangePropagationTest.xtend @@ -30,6 +30,8 @@ import static tools.vitruv.testutils.metamodels.UmlMockupCreators.uml import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.common.util.URIUtil.createFileURI import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.withGlobalFactories +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy @ExtendWith(TestProjectManager, TestLogging, RegisterMetamodelsInStandalone) abstract class StateChangePropagationTest { diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/UmlStateChangeTest.xtend b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/UmlStateChangeTest.xtend index c21e11d991..01cc780c30 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/UmlStateChangeTest.xtend +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/changederivation/UmlStateChangeTest.xtend @@ -6,6 +6,8 @@ import org.junit.jupiter.params.provider.EnumSource import org.junit.jupiter.params.provider.MethodSource import static tools.vitruv.testutils.metamodels.UmlMockupCreators.uml +import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy class UmlStateChangeTest extends StateChangePropagationTest { @ParameterizedTest() diff --git a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/impl/ChangeDerivingViewTest.java b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/impl/ChangeDerivingViewTest.java index d51d20b8d0..f9ab130c0b 100644 --- a/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/impl/ChangeDerivingViewTest.java +++ b/tests/tools.vitruv.framework.views.tests/src/tools/vitruv/framework/views/impl/ChangeDerivingViewTest.java @@ -35,10 +35,10 @@ import tools.vitruv.change.atomic.root.InsertRootEObject; import tools.vitruv.change.atomic.root.RootFactory; import tools.vitruv.change.atomic.root.RootPackage; +import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy; import tools.vitruv.change.composite.description.VitruviusChange; import tools.vitruv.framework.views.ChangeableViewSource; import tools.vitruv.framework.views.ModifiableViewSelection; -import tools.vitruv.framework.views.changederivation.DefaultStateBasedChangeResolutionStrategy; import tools.vitruv.testutils.RegisterMetamodelsInStandalone; import tools.vitruv.testutils.TestLogging; From e430ed0c813bed13287b8ec1d05965c077aa447d Mon Sep 17 00:00:00 2001 From: Simon Haug Date: Tue, 25 Apr 2023 11:50:41 +0200 Subject: [PATCH 4/5] add DeltaBasedResource - added DeltaBasedResource in Vitruv-Change, based ModelInstance on this DeltaBasedResource --- .../vsum/internal/ModelInstance.xtend | 42 ++----------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend index e8bca0e4da..e3be249e11 100644 --- a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ModelInstance.xtend @@ -1,26 +1,17 @@ package tools.vitruv.framework.vsum.internal import java.io.IOException -import java.io.InputStream -import java.io.OutputStream -import java.util.Collections -import java.util.List import java.util.Map import org.apache.log4j.Logger import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.impl.ResourceImpl -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl -import tools.vitruv.change.atomic.EChange -import tools.vitruv.change.atomic.id.IdResolver -import tools.vitruv.change.composite.description.VitruviusChangeFactory -import tools.vitruv.change.changederivation.DefaultStateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.DeltaBasedResource -class ModelInstance extends ResourceImpl { +class ModelInstance extends DeltaBasedResource { static val LOGGER = Logger.getLogger(ModelInstance) new(URI uri) { - this.URI = uri + super(uri) LOGGER.debug('''Create model instance for resource with URI: «uri»''') } @@ -34,33 +25,6 @@ class ModelInstance extends ResourceImpl { this.contents.isEmpty } - private static def List loadDeltas(URI modelUri) { - val resSet = new ResourceSetImpl(); - val resource = resSet.getResource(modelUri, true); - return resource.getContents().map[it as EChange].toList - } - - override doLoad(InputStream inputStream, Map options) throws IOException { - val deltas = loadDeltas(this.URI) - VitruviusChangeFactory.getInstance().createTransactionalChange(deltas).resolveAndApply(IdResolver.create(this.resourceSet)) - } - - override doSave(OutputStream outputStream, Map options) throws IOException { - if (!this.modified) { - return - } - - val deltaChanges = new DefaultStateBasedChangeResolutionStrategy().getChangeSequenceForCreated(this).EChanges; - val resSet = new ResourceSetImpl(); - val resource = resSet.createResource(this.URI); - resource.getContents().addAll(deltaChanges) - try (val out = outputStream){ - resource.save(out, Collections.EMPTY_MAP) - } - - resource.modified = false - } - override delete(Map options) throws IOException { LOGGER.debug('''Delete model instance: «this»''') super.delete(null) From 53202ceb6f4654d35267c5146dc1a9e951b38da0 Mon Sep 17 00:00:00 2001 From: Simon Haug Date: Fri, 16 Jun 2023 11:38:32 +0200 Subject: [PATCH 5/5] add TestDeltaMigrator + continue work - handle loading of aware of state based representations and pathmap-mechanism - work in progress --- .../framework/views/impl/BasicView.xtend | 5 +- .../views/impl/IdentityMappingViewType.java | 3 +- .../META-INF/MANIFEST.MF | 1 + .../PathmapAwareModelInstanceFactory.java | 27 +++++++++ .../vsum/internal/ResourceRepositoryImpl.java | 40 +++++++++---- .../DefaultVirtualModelBasedTestView.xtend | 2 + .../vitruv/testutils/TestDeltaMigrator.java | 59 +++++++++++++++++++ .../ViewBasedVitruvApplicationTest.xtend | 7 ++- 8 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/PathmapAwareModelInstanceFactory.java create mode 100644 bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestDeltaMigrator.java diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend index eb7f3fc8d6..7636ed0358 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/BasicView.xtend @@ -16,12 +16,11 @@ import tools.vitruv.framework.views.ChangeableViewSource import tools.vitruv.framework.views.ViewSelection import tools.vitruv.framework.views.ViewSelector import tools.vitruv.change.changederivation.StateBasedChangeResolutionStrategy +import tools.vitruv.change.changederivation.DeltaBasedResourceUtil import static com.google.common.base.Preconditions.checkArgument import static com.google.common.base.Preconditions.checkState -import static extension edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.withGlobalFactories - package class BasicView implements ModifiableView, ChangePropagationListener { @Accessors(PUBLIC_GETTER, PROTECTED_SETTER) var ViewSelection selection @@ -45,7 +44,7 @@ package class BasicView implements ModifiableView, ChangePropagationListener { this.viewSource = viewSource this.selection = selection viewSource.addChangePropagationListener(this) - viewResourceSet = new ResourceSetImpl().withGlobalFactories + viewResourceSet = DeltaBasedResourceUtil.withDeltaFactory(new ResourceSetImpl()) update } diff --git a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java index 9ec672a7a4..4d9d4f10cf 100644 --- a/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java +++ b/bundles/tools.vitruv.framework.views/src/tools/vitruv/framework/views/impl/IdentityMappingViewType.java @@ -17,6 +17,7 @@ import tools.vitruv.change.atomic.EChangeUuidManager; import tools.vitruv.change.atomic.id.IdResolver; import tools.vitruv.change.atomic.uuid.UuidResolver; +import tools.vitruv.change.changederivation.DeltaBasedResourceUtil; import tools.vitruv.change.composite.description.VitruviusChange; import tools.vitruv.framework.views.ChangeableViewSource; import tools.vitruv.framework.views.View; @@ -64,7 +65,7 @@ public void updateView(ModifiableView view) { @Override public void commitViewChanges(ModifiableView view, VitruviusChange viewChange) { - ResourceSet viewSourceCopyResourceSet = withGlobalFactories(new ResourceSetImpl()); + ResourceSet viewSourceCopyResourceSet = DeltaBasedResourceUtil.withDeltaFactory(new ResourceSetImpl()); IdResolver viewSourceCopyIdResolver = IdResolver.create(viewSourceCopyResourceSet); UuidResolver viewSourceCopyUuidResolver = UuidResolver.create(viewSourceCopyResourceSet); Map mapping = createViewResources(view, viewSourceCopyResourceSet); diff --git a/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF b/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF index fab623be6e..311a33da04 100644 --- a/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF +++ b/bundles/tools.vitruv.framework.vsum/META-INF/MANIFEST.MF @@ -16,5 +16,6 @@ Require-Bundle: org.apache.log4j, edu.kit.ipd.sdq.commons.util.java, tools.vitruv.change.changederivation Export-Package: tools.vitruv.framework.vsum, + tools.vitruv.framework.vsum.helper, tools.vitruv.framework.vsum.internal;x-internal:=true Bundle-Vendor: vitruv.tools diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/PathmapAwareModelInstanceFactory.java b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/PathmapAwareModelInstanceFactory.java new file mode 100644 index 0000000000..9b4946d7ee --- /dev/null +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/PathmapAwareModelInstanceFactory.java @@ -0,0 +1,27 @@ +package tools.vitruv.framework.vsum.internal; + +import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.loadOrCreateResource; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; + +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil; + +public class PathmapAwareModelInstanceFactory implements Resource.Factory { + @Override + public Resource createResource(URI uri) { + if (uri.toString().contains("pathmap")) { + ResourceSet stateBasedResourceSet = ResourceSetUtil.withGlobalFactories(new ResourceSetImpl()); + loadOrCreateResource(stateBasedResourceSet, uri); + ModelInstance modelInstance = new ModelInstance(uri); + Resource stateBasedResource = stateBasedResourceSet.getResource(uri, false); + modelInstance.getContents().addAll(EcoreUtil.copyAll(stateBasedResource.getContents())); + modelInstance.setModified(false); + return modelInstance; + } + return new ModelInstance(uri); + } +} \ No newline at end of file diff --git a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java index aa5fb201fd..b33fcdd8bd 100644 --- a/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java +++ b/bundles/tools.vitruv.framework.vsum/src/tools/vitruv/framework/vsum/internal/ResourceRepositoryImpl.java @@ -2,7 +2,6 @@ import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.getOrCreateResource; import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.loadOrCreateResource; -import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.withGlobalFactories; import static tools.vitruv.change.correspondence.model.CorrespondenceModelFactory.createPersistableCorrespondenceModel; import java.io.IOException; @@ -21,7 +20,9 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil; import tools.vitruv.change.atomic.EChangeUuidManager; import tools.vitruv.change.atomic.uuid.UuidResolver; import tools.vitruv.change.composite.description.TransactionalChange; @@ -36,8 +37,8 @@ class ResourceRepositoryImpl implements ModelRepository { private static final Logger LOGGER = Logger.getLogger(ResourceRepositoryImpl.class); - - private final ResourceSet modelsResourceSet = withGlobalFactories(new ResourceSetImpl()); + + private final ResourceSet modelsResourceSet = new ResourceSetImpl(); private final Map modelInstances = new HashMap<>(); private final PersistableCorrespondenceModel correspondenceModel; private final UuidResolver uuidResolver = UuidResolver.create(modelsResourceSet); @@ -51,9 +52,11 @@ class ResourceRepositoryImpl implements ModelRepository { ResourceRepositoryImpl(VsumFileSystemLayout fileSystemLayout) { this.fileSystemLayout = fileSystemLayout; this.correspondenceModel = createPersistableCorrespondenceModel(fileSystemLayout.getCorrespondencesURI()); - modelsResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new ModelInstanceFactory()); - modelsResourceSet.eAdapters() - .add(new ResourceRegistrationAdapter(resource -> getCreateOrLoadModelUnlessLoading(resource.getURI()))); + modelsResourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", + new PathmapAwareModelInstanceFactory()); + modelsResourceSet.eAdapters().add(new ResourceRegistrationAdapter(resource -> { + getCreateOrLoadModelUnlessLoading(resource.getURI()); + })); } @Override @@ -69,8 +72,8 @@ public void loadExistingModels() { } private void writeModelsFile() throws IOException { - Files.write(fileSystemLayout.getModelsNamesFilesPath(), modelsResourceSet.getResources().stream() - .map(Resource::getURI).map(URI::toString).toList()); + Files.write(fileSystemLayout.getModelsNamesFilesPath(), + modelsResourceSet.getResources().stream().map(Resource::getURI).map(URI::toString).toList()); } private void readModelsFile() throws IOException { @@ -119,7 +122,18 @@ private ModelInstance getCreateOrLoadModel(URI modelUri) { private ModelInstance createOrLoadModel(URI modelUri) { ModelInstance modelInstance; - if (modelUri.isFile() || modelUri.isPlatform()) { + if (modelUri.toString().contains("pathmap")) { + // loadOrCreateResource + if(modelsResourceSet.getResources().stream().anyMatch(resource -> resource.getURI().equals(modelUri))) { + modelInstance = (ModelInstance) modelsResourceSet.getResource(modelUri, false); + } else { + ResourceSet stdResourceSet = ResourceSetUtil.withGlobalFactories(new ResourceSetImpl()); + Resource pathMapResource = getOrCreateResource(stdResourceSet, modelUri); + modelInstance = new ModelInstance(modelUri); + modelInstance.getContents().addAll(EcoreUtil.copyAll(pathMapResource.getContents())); + modelsResourceSet.getResources().add(modelInstance); + } + } else if (modelUri.isFile() || modelUri.isPlatform()) { modelInstance = (ModelInstance) getOrCreateResource(modelsResourceSet, modelUri); } else { modelInstance = (ModelInstance) loadOrCreateResource(modelsResourceSet, modelUri); @@ -127,6 +141,7 @@ private ModelInstance createOrLoadModel(URI modelUri) { modelInstances.put(modelUri, modelInstance); registerRecorder(modelInstance); + modelInstance.setModified(false); return modelInstance; } @@ -163,9 +178,12 @@ public void saveOrDeleteModels() { modelInstancesIterator.remove(); } else { try { - modelInstance.save(null); + // move to modelInstance? + if(modelInstance.isModified()) { + modelInstance.save(null); + } } catch (IOException e) { - LOGGER.error("Model could not be saved: "+ modelInstance.getURI(), e); + LOGGER.error("Model could not be saved: " + modelInstance.getURI(), e); throw new IllegalStateException("Could not save URI " + modelInstance.getURI(), e); } } diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend index b8c09d134f..f61504afbe 100644 --- a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/DefaultVirtualModelBasedTestView.xtend @@ -31,6 +31,8 @@ class DefaultVirtualModelBasedTestView implements VirtualModelBasedTestView, Non private def InternalVirtualModel generateVirtualModel(Path testProjectPath, Path vsumPath, TestUserInteraction userInteraction) { + TestDeltaMigrator.makeVsumModelsDeltaBased(vsumPath.resolve("models.models")) + new VirtualModelBuilder() // .withStorageFolder(vsumPath) // .withUserInteractorForResultProvider(new TestUserInteraction.ResultProvider(userInteraction)) // diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestDeltaMigrator.java b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestDeltaMigrator.java new file mode 100644 index 0000000000..afcd8315f1 --- /dev/null +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/TestDeltaMigrator.java @@ -0,0 +1,59 @@ +package tools.vitruv.testutils; + +import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.getOrCreateResource; +import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil.loadOrCreateResource; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.EcoreUtil; + +import edu.kit.ipd.sdq.commons.util.org.eclipse.emf.ecore.resource.ResourceSetUtil; +import tools.vitruv.change.changederivation.DeltaBasedResourceFactory; + +public class TestDeltaMigrator { + + private TestDeltaMigrator() {}; + + public static void makeVsumModelsDeltaBased(Path modelsNamesFilesPath) throws IllegalStateException, IOException { + ResourceSet stateBasedResourceSet = ResourceSetUtil.withGlobalFactories(new ResourceSetImpl()); + List modelUris; + try { + modelUris = Files.readAllLines(modelsNamesFilesPath).stream().map(URI::createURI).toList(); + } catch (NoSuchFileException e) { + // There are no existing models, so don't do anything + return; + } + modelUris.forEach(uri -> createOrLoadResourceStateBased(stateBasedResourceSet, uri)); + modelUris.forEach(uri -> { + try { + saveResourceDeltaBased(stateBasedResourceSet, uri); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + } + + private static void createOrLoadResourceStateBased(ResourceSet stateBasedResourceSet, URI resourceUri) { + if (resourceUri.isFile() || resourceUri.isPlatform()) { + getOrCreateResource(stateBasedResourceSet, resourceUri); + } else { + loadOrCreateResource(stateBasedResourceSet, resourceUri); + } + } + + private static void saveResourceDeltaBased(ResourceSet stateBasedResourceSet, URI uri) throws IOException { + Resource deltaBasedResource = new DeltaBasedResourceFactory().createResource(uri); + Resource stateBasedResource = stateBasedResourceSet.getResource(uri, false); + deltaBasedResource.getContents().addAll(EcoreUtil.copyAll(stateBasedResource.getContents())); + deltaBasedResource.save(null); + } +} diff --git a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/ViewBasedVitruvApplicationTest.xtend b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/ViewBasedVitruvApplicationTest.xtend index 9e50da0a83..9d33f3874b 100644 --- a/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/ViewBasedVitruvApplicationTest.xtend +++ b/bundles/tools.vitruv.testutils.vsum/src/tools/vitruv/testutils/ViewBasedVitruvApplicationTest.xtend @@ -40,7 +40,9 @@ abstract class ViewBasedVitruvApplicationTest { /** * Determines which {@link UriMode} should be used for this test. */ - def protected UriMode getUriMode() { UriMode.FILE_URIS } + def protected UriMode getUriMode() { + UriMode.FILE_URIS + } @BeforeEach def final package void prepareVirtualModel(TestInfo testInfo, @TestProject Path testProjectPath, @@ -48,6 +50,9 @@ abstract class ViewBasedVitruvApplicationTest { val changePropagationSpecifications = this.changePropagationSpecifications val changePropagationMode = enableTransitiveCyclicChangePropagation ? ChangePropagationMode.TRANSITIVE_CYCLIC : ChangePropagationMode.SINGLE_STEP userInteraction = new TestUserInteraction + + TestDeltaMigrator.makeVsumModelsDeltaBased(vsumPath.resolve("models.models")) + virtualModel = new VirtualModelBuilder() // .withStorageFolder(vsumPath) // .withUserInteractorForResultProvider(new TestUserInteraction.ResultProvider(userInteraction)) //