Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force UUID unregistration at end of transaction #74

Merged
merged 4 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ public EChange<Uuid> assignIds(EChange<EObject> resolvedEChange) {
}

/**
* Ends a transactions such that all {@link EObject}s not being contained in a
* resource, which is contained in a resource set, are removed from the UUID
* mapping.
* Ends a transactions such that any registered {@link EObject} not being
* contained in a resource throws an error.
*
* @throws IllegalStateException if an uncontained element is registered in the
* {@link UuidResolver}.
*/
public void endTransaction() {
uuidResolver.endTransaction();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public default Uuid registerEObject(EObject eObject) throws IllegalStateExceptio
registerEObject(uuid, eObject);
return uuid;
}

public void unregisterEObject(Uuid uuid, EObject eObject) throws IllegalStateException;

/**
Expand All @@ -101,11 +101,12 @@ public default Uuid registerEObject(EObject eObject) throws IllegalStateExceptio
public Resource getResource(URI uri);

/**
* Ends a transactions such that all {@link EObject}s not being contained in a
* resource, which is contained in a resource set, are removed from the UUID
* mapping.
* Ends a transactions such that any registered {@link EObject} not being
* contained in a resource throws an error.
*
* @throws IllegalStateException if an uncontained element is registered.
*/
public void endTransaction();
public void endTransaction() throws IllegalStateException;

/**
* Resolves all {@link EObject}s contained in any resource of the given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void registerEObject(Uuid uuid, EObject eObject) throws IllegalStateExcep
public void unregisterEObject(Uuid uuid, EObject eObject) throws IllegalStateException {
checkState(uuid != null, "uuid must not be null");
checkState(eObject != null, "object must not be null");
checkState(eObjectToUuid.get(eObject).equals(uuid), "trying to unregister element %s but is not registered for uuid %s", eObject, uuid);
checkState(uuid.equals(eObjectToUuid.get(eObject)), "trying to unregister element %s but is not registered for uuid %s", eObject, uuid);
eObjectToUuid.remove(eObject);
}

Expand All @@ -104,7 +104,12 @@ public Resource getResource(URI uri) {

@Override
public void endTransaction() {
cleanupRemovedElements();
var iterator = eObjectToUuid.keySet().iterator();
while (iterator.hasNext()) {
EObject object = iterator.next();
checkState(object.eResource() != null, "dangling object %s detected", object);
checkState(object.eResource().getResourceSet() == resourceSet, "object %s is contained in wrong resource set", object);
}
}

@Override
Expand Down Expand Up @@ -200,18 +205,6 @@ private boolean isReadOnlyUuid(Uuid uuid) {
return !uuid.getRawValue().startsWith(NON_READONLY_PREFIX);
}

private void cleanupRemovedElements() {
var iterator = eObjectToUuid.keySet().iterator();
while (iterator.hasNext()) {
EObject object = iterator.next();
//TODO: Hard constraint for dangling elements is currently disabled as Reactions produce incomplete change sequence
// checkState(object.eResource() != null && object.eResource().getResourceSet() != null, "dangling object %s detected", object);
if (object.eResource() == null || object.eResource().getResourceSet() == null) {
iterator.remove();
}
}
}

/**
* Creates a mapping from UUIDs to hierarchical IDs. If a
* <code>resourcesFilter</code> is provided, only {@link EObject}s contained in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class DefaultChangeRecordingModelRepository implements PersistableChangeR
private final PersistableCorrespondenceModel correspondenceModel;
private final ChangeRecorder changeRecorder;
private final Path consistencyMetadataFolder;
private final UuidResolver uuidResolver;
private UuidResolver uuidResolver;
private final VitruviusChangeResolver<Uuid> changeResolver;

private boolean isLoading = false;
Expand Down Expand Up @@ -175,10 +175,10 @@ public VitruviusChange<EObject> applyChange(VitruviusChange<Uuid> change) {
@Override
public void close() throws Exception {
changeRecorder.close();
modelsResourceSet.getResources().stream().forEach((resource) -> resource.unload());
modelsResourceSet.getResources().forEach(Resource::unload);
modelsResourceSet.getResources().clear();
uuidResolver.endTransaction();
correspondenceModel.close();
uuidResolver = null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import tools.vitruv.testutils.TestUserInteraction

import static com.google.common.base.Preconditions.checkArgument
import static com.google.common.base.Preconditions.checkState
import static edu.kit.ipd.sdq.commons.util.org.eclipse.emf.common.util.URIUtil.isPathmap
import static tools.vitruv.testutils.TestModelRepositoryFactory.createTestChangeableModelRepository

import static extension edu.kit.ipd.sdq.commons.util.java.lang.IterableUtil.flatMapFixed
Expand Down Expand Up @@ -172,8 +173,16 @@ class ChangePublishingTestView implements NonTransactionalTestView {
}

override disposeViewResources() {
resourceSet.resources.forEach [ resource |
if (resource.URI === null || !isPathmap(resource.URI)) {
resource.allContents.forEach [
if (uuidResolver.hasUuid(it)) {
uuidResolver.unregisterEObject(uuidResolver.getUuid(it), it)
}
]
}
]
resourceSet.resources.clear()
uuidResolver.endTransaction()
}

override <T extends Notifier> T startRecordingChanges(T notifier) {
Expand Down Expand Up @@ -224,6 +233,6 @@ class ChangePublishingTestView implements NonTransactionalTestView {
val changeableModelRepository = createTestChangeableModelRepository(modelRepository,
changePropagationSpecificationProvider, userInteraction)
return new ChangePublishingTestView(persistenceDirectory, userInteraction, UriMode.FILE_URIS,
changeableModelRepository, modelRepository.uuidResolver) [ modelRepository.getModelResource(it) ]
changeableModelRepository, modelRepository.uuidResolver)[modelRepository.getModelResource(it)]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,16 @@ void elementDeletionDoesNotRemoveUuid() {
}

@Test
@DisplayName("cleanup resolver when saving after element removal")
void cleanupAfterElementRemovalRemovesUuid() {
@DisplayName("register dangling element")
void registerDanglingElement() {
var root = aet.Root();
Uuid uuid = uuidResolver.registerEObject(root);
uuidResolver.endTransaction();
assertThrows(IllegalStateException.class, () -> uuidResolver.getEObject(uuid));
assertThrows(IllegalStateException.class, () -> uuidResolver.getUuid(root));
assertFalse(uuidResolver.hasUuid(root));
assertFalse(uuidResolver.hasEObject(uuid));
uuidResolver.registerEObject(root);
assertThrows(IllegalStateException.class, () -> uuidResolver.endTransaction());
}

@Test
@DisplayName("cleanup resolver when saving resource after element removal")
void cleanupAfterElementRemovalRemovesUuidWithResource() {
@DisplayName("clear resource without unregistering elements")
void clearResourceWithoutUnregistration() {
var root = aet.Root();
URI resourceUri = URI.createFileURI(testProjectPath.resolve("root.aet").toString());
Resource rootResource = resourceSet.createResource(resourceUri);
Expand All @@ -170,10 +166,6 @@ void cleanupAfterElementRemovalRemovesUuidWithResource() {
assertEquals(root, uuidResolver.getEObject(uuid));

rootResource.getContents().clear();
uuidResolver.endTransaction();
assertThrows(IllegalStateException.class, () -> uuidResolver.getEObject(uuid));
assertThrows(IllegalStateException.class, () -> uuidResolver.getUuid(root));
assertFalse(uuidResolver.hasUuid(root));
assertFalse(uuidResolver.hasEObject(uuid));
assertThrows(IllegalStateException.class, () -> uuidResolver.endTransaction());
}
}