Skip to content

Commit

Permalink
Merge pull request #594 from vitruv-tools/change-generic
Browse files Browse the repository at this point in the history
Make `EChange` generic over its content type
  • Loading branch information
JanWittler authored Jul 10, 2023
2 parents 44590f1 + 9b88e9e commit 006fa78
Show file tree
Hide file tree
Showing 21 changed files with 250 additions and 233 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,15 @@ 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.description.VitruviusChangeResolver
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

/**
* This default strategy for diff based state changes uses EMFCompare to resolve a
Expand Down Expand Up @@ -99,21 +94,10 @@ class DefaultStateBasedChangeResolutionStrategy implements StateBasedChangeResol
changeRecorder.addToRecording(resource)
function.apply()
val recordedChanges = changeRecorder.endRecording
assignIds(recordedChanges, resource.resourceSet)
return recordedChanges.unresolve
val changeResolver = VitruviusChangeResolver.forHierarchicalIds(resource.resourceSet)
return changeResolver.assignIds(recordedChanges)
}
}

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.eclipse.emf.ecore.resource.Resource;

import tools.vitruv.change.atomic.hid.HierarchicalId;
import tools.vitruv.change.composite.description.VitruviusChange;

/**
Expand All @@ -24,7 +25,7 @@ public interface StateBasedChangeResolutionStrategy {
* @return a unresolved {@link VitruviusChange} that contains the individual
* change sequence.
*/
VitruviusChange getChangeSequenceBetween(Resource newState, Resource oldState);
VitruviusChange<HierarchicalId> getChangeSequenceBetween(Resource newState, Resource oldState);

/**
* Resolves the state-based delta for creating the given resource and returns
Expand All @@ -36,7 +37,7 @@ public interface StateBasedChangeResolutionStrategy {
* @return a unresolved {@link VitruviusChange} that contains the individual
* change sequence.
*/
VitruviusChange getChangeSequenceForCreated(Resource newState);
VitruviusChange<HierarchicalId> getChangeSequenceForCreated(Resource newState);

/**
* Resolves the state-based delta for deleting the given resource and returns
Expand All @@ -49,5 +50,5 @@ public interface StateBasedChangeResolutionStrategy {
* @return a unresolved {@link VitruviusChange} that contains the individual
* change sequence.
*/
VitruviusChange getChangeSequenceForDeleted(Resource oldState);
VitruviusChange<HierarchicalId> getChangeSequenceForDeleted(Resource oldState);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import tools.vitruv.framework.views.ViewSelector

import static com.google.common.base.Preconditions.checkArgument

abstract package class AbstractViewType<S extends ViewSelector> implements ViewCreatingViewType<S> {
abstract package class AbstractViewType<S extends ViewSelector, Id> implements ViewCreatingViewType<S, Id> {
@Accessors(PUBLIC_GETTER)
val String name

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ 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.xtend.lib.annotations.Accessors
import tools.vitruv.change.atomic.hid.HierarchicalId
import tools.vitruv.change.atomic.uuid.Uuid
import tools.vitruv.change.composite.description.PropagatedChange
import tools.vitruv.change.composite.description.VitruviusChange
import tools.vitruv.change.composite.propagation.ChangePropagationListener
Expand All @@ -26,7 +28,7 @@ package class BasicView implements ModifiableView, ChangePropagationListener {
@Accessors(PUBLIC_GETTER, PROTECTED_SETTER)
var ViewSelection selection
@Accessors(PUBLIC_GETTER, PROTECTED_SETTER)
var ViewCreatingViewType<? extends ViewSelector> viewType
var ViewCreatingViewType<? extends ViewSelector, HierarchicalId> viewType
@Accessors(PUBLIC_GETTER, PROTECTED_SETTER)
var ChangeableViewSource viewSource
@Accessors(PROTECTED_GETTER)
Expand All @@ -36,7 +38,7 @@ package class BasicView implements ModifiableView, ChangePropagationListener {
boolean viewChanged
boolean closed

protected new(ViewCreatingViewType<? extends ViewSelector> viewType, ChangeableViewSource viewSource,
protected new(ViewCreatingViewType<? extends ViewSelector, HierarchicalId> viewType, ChangeableViewSource viewSource,
ViewSelection selection) {
checkArgument(viewType !== null, "view type must not be null")
checkArgument(viewSource !== null, "view selection must not be null")
Expand Down Expand Up @@ -89,7 +91,7 @@ package class BasicView implements ModifiableView, ChangePropagationListener {
modelChanged = true
}

override startedChangePropagation(VitruviusChange changeToPropagate) {
override startedChangePropagation(VitruviusChange<Uuid> changeToPropagate) {
// do nothing
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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.xtend.lib.annotations.Delegate
import tools.vitruv.change.atomic.hid.HierarchicalId
import tools.vitruv.change.composite.description.VitruviusChange
import tools.vitruv.change.composite.description.VitruviusChangeFactory
import tools.vitruv.framework.views.CommittableView
Expand Down Expand Up @@ -75,7 +76,7 @@ class ChangeDerivingView implements ModifiableView, CommittableView {
view.close
}

private def VitruviusChange generateChange(Resource newState, Resource referenceState) {
private def VitruviusChange<HierarchicalId> generateChange(Resource newState, Resource referenceState) {
if (referenceState === null) {
return changeResolutionStrategy.getChangeSequenceForCreated(newState)
} else if (newState === null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package tools.vitruv.framework.views.impl

import java.util.List
import org.eclipse.xtend.lib.annotations.Delegate
import tools.vitruv.change.atomic.EChange
import tools.vitruv.change.atomic.EChangeIdManager
import tools.vitruv.change.atomic.id.IdResolver
import tools.vitruv.change.composite.description.VitruviusChangeResolver
import tools.vitruv.change.composite.recording.ChangeRecorder
import tools.vitruv.framework.views.CommittableView
import tools.vitruv.framework.views.View
Expand All @@ -13,9 +10,6 @@ import tools.vitruv.framework.views.changederivation.StateBasedChangeResolutionS
import static com.google.common.base.Preconditions.checkArgument
import static com.google.common.base.Preconditions.checkState

import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyBackward
import static extension tools.vitruv.change.atomic.resolve.EChangeIdResolverAndApplicator.applyForward

/**
* A {@link View} that records changes to its resources and allows to propagate them
* back to the underlying models using the {@link #commitChanges} method.
Expand Down Expand Up @@ -43,21 +37,13 @@ class ChangeRecordingView implements ModifiableView, CommittableView {
changeRecorder.addToRecording(view.viewResourceSet)
changeRecorder.beginRecording()
}
def private void assignIds(List<EChange> changes) {
val idResolver = IdResolver.create(view.viewResourceSet)
val idManager = new EChangeIdManager(idResolver)
changes.toList.reverseView.forEach[applyBackward]
changes.forEach[
idManager.setOrGenerateIds(it)
it.applyForward(idResolver)
]
}

override commitChanges() {
view.checkNotClosed()
val recordedChange = changeRecorder.endRecording()
assignIds(recordedChange.EChanges)
view.viewType.commitViewChanges(this, recordedChange)
val changeResolver = VitruviusChangeResolver.forHierarchicalIds(view.viewResourceSet)
val unresolvedChanges = changeResolver.assignIds(recordedChange)
view.viewType.commitViewChanges(this, unresolvedChanges)
view.viewChanged = false
changeRecorder.beginRecording()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
import java.util.function.Function;
import java.util.stream.Stream;

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.resource.impl.ResourceSetImpl;

import tools.vitruv.change.atomic.EChangeUuidManager;
import tools.vitruv.change.atomic.id.IdResolver;
import tools.vitruv.change.atomic.hid.HierarchicalId;
import tools.vitruv.change.atomic.uuid.Uuid;
import tools.vitruv.change.atomic.uuid.UuidResolver;
import tools.vitruv.change.composite.description.VitruviusChange;
import tools.vitruv.change.composite.description.VitruviusChangeResolver;
import tools.vitruv.framework.views.ChangeableViewSource;
import tools.vitruv.framework.views.View;
import tools.vitruv.framework.views.ViewSelection;
Expand All @@ -29,14 +31,14 @@
* selection mechanism and providing a one-to-one (identity) mapping of elements
* within the {@link ViewSource} to a created {@link View}.
*/
public class IdentityMappingViewType extends AbstractViewType<DirectViewElementSelector> {
public class IdentityMappingViewType extends AbstractViewType<DirectViewElementSelector<HierarchicalId>, HierarchicalId> {
public IdentityMappingViewType(String name) {
super(name);
}

@Override
public DirectViewElementSelector createSelector(ChangeableViewSource viewSource) {
return new DirectViewElementSelector(this, viewSource,
public DirectViewElementSelector<HierarchicalId> createSelector(ChangeableViewSource viewSource) {
return new DirectViewElementSelector<>(this, viewSource,
viewSource.getViewSourceModels().stream().map(resource -> {
if (!resource.getContents().isEmpty() && ResourceCopier.requiresFullCopy(resource)) {
// Some resources (like UML) can only be copied as a whole, so no option to select
Expand All @@ -48,7 +50,7 @@ public DirectViewElementSelector createSelector(ChangeableViewSource viewSource)
}

@Override
public ModifiableView createView(DirectViewElementSelector selector) {
public ModifiableView createView(DirectViewElementSelector<HierarchicalId> selector) {
checkArgument(selector.getViewType() == this, "cannot create view with selector for different view type");
return new BasicView(selector.getViewType(), selector.getViewSource(), selector.getSelection());
}
Expand All @@ -63,16 +65,17 @@ public void updateView(ModifiableView view) {
}

@Override
public void commitViewChanges(ModifiableView view, VitruviusChange viewChange) {
public void commitViewChanges(ModifiableView view, VitruviusChange<HierarchicalId> viewChange) {
ResourceSet viewSourceCopyResourceSet = withGlobalFactories(new ResourceSetImpl());
IdResolver viewSourceCopyIdResolver = IdResolver.create(viewSourceCopyResourceSet);
VitruviusChangeResolver<HierarchicalId> idChangeResolver = VitruviusChangeResolver.forHierarchicalIds(viewSourceCopyResourceSet);
UuidResolver viewSourceCopyUuidResolver = UuidResolver.create(viewSourceCopyResourceSet);
VitruviusChangeResolver<Uuid> uuidChangeResolver = VitruviusChangeResolver.forUuids(viewSourceCopyUuidResolver);
Map<Resource, Resource> mapping = createViewResources(view, viewSourceCopyResourceSet);
view.getViewSource().getUuidResolver().resolveResources(mapping, viewSourceCopyUuidResolver);

VitruviusChange resolvedChange = viewChange.unresolve().resolveAndApply(viewSourceCopyIdResolver);
EChangeUuidManager.setOrGenerateIds(resolvedChange.getEChanges(), viewSourceCopyUuidResolver);
view.getViewSource().propagateChange(resolvedChange.unresolve());
VitruviusChange<EObject> resolvedChange = idChangeResolver.resolveAndApply(viewChange);
VitruviusChange<Uuid> unresolvedChanges = uuidChangeResolver.assignIds(resolvedChange);
view.getViewSource().propagateChange(unresolvedChanges);
}

private Map<Resource, Resource> createViewResources(ModifiableView view, ResourceSet viewResourceSet) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
* A specific view type that is able to create and update views. This is not its
* public interface but only for internal usage by views and their selectors.
*
* @param <S> the type of view selector this view type uses
* @param <S> the type of view selector this view type uses.
* @param <Id> the type of Id the changes to commit must have.
*/
public interface ViewCreatingViewType<S extends ViewSelector> extends ViewType<S> {
public interface ViewCreatingViewType<S extends ViewSelector, Id> extends ViewType<S> {
/**
* Creates a view for the given {@link ViewSelector}. The selector must have
* been created by calling the {@link #createSelector} method of the same
Expand All @@ -35,11 +36,10 @@ public interface ViewCreatingViewType<S extends ViewSelector> extends ViewType<S
* underlying {@link ChangeableViewSource}. Since view elements do not
* necessarily correspond to elements of the underlying view source, the view
* type is responsible for transforming the given {@link VitruviusChange} such
* that the underlying view source can process it. The given changes must use
* hierarchical IDs and may be unresolved.
* that the underlying view source can process it.
*
* @param view is the modified view.
* @param viewChange are the changes performed to the view.
*/
void commitViewChanges(ModifiableView view, VitruviusChange viewChange);
void commitViewChanges(ModifiableView view, VitruviusChange<Id> viewChange);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import static com.google.common.base.Preconditions.checkState
* and view elements (such as selecting types but providing instances in the view),
* but a selection is performed on the view elements themselves.
*/
class DirectViewElementSelector implements ViewSelector {
class DirectViewElementSelector<Id> implements ViewSelector {
@Delegate
val ModifiableViewSelection viewSelection

@Accessors(PUBLIC_GETTER)
val ChangeableViewSource viewSource

@Accessors(PUBLIC_GETTER)
val ViewCreatingViewType<DirectViewElementSelector> viewType
val ViewCreatingViewType<DirectViewElementSelector<Id>, Id> viewType

/**
* Creates a new selector based on the given collection of selectable elements
Expand All @@ -43,7 +43,7 @@ class DirectViewElementSelector implements ViewSelector {
* @param selectableElements - the elements to select from to be used by the
* {@link ViewType} when creating a view
*/
new(ViewCreatingViewType<DirectViewElementSelector> viewType, ChangeableViewSource viewSource,
new(ViewCreatingViewType<DirectViewElementSelector<Id>, Id> viewType, ChangeableViewSource viewSource,
Collection<EObject> selectableElements) {
checkArgument(selectableElements !== null, "selectable elements must not be null")
checkArgument(viewType !== null, "view type must not be null")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;

import tools.vitruv.change.atomic.EChangeUuidManager;
import tools.vitruv.change.atomic.uuid.Uuid;
import tools.vitruv.change.atomic.uuid.UuidResolver;
import tools.vitruv.change.composite.description.TransactionalChange;
import tools.vitruv.change.composite.description.VitruviusChange;
import tools.vitruv.change.composite.description.VitruviusChangeResolver;
import tools.vitruv.change.composite.recording.ChangeRecorder;
import tools.vitruv.change.correspondence.Correspondence;
import tools.vitruv.change.correspondence.model.PersistableCorrespondenceModel;
Expand All @@ -42,6 +43,7 @@ class ResourceRepositoryImpl implements ModelRepository {
private final PersistableCorrespondenceModel correspondenceModel;
private final UuidResolver uuidResolver = UuidResolver.create(modelsResourceSet);
private final ChangeRecorder changeRecorder = new ChangeRecorder(modelsResourceSet);
private final VitruviusChangeResolver<Uuid> changeResolver = VitruviusChangeResolver.forUuids(uuidResolver);

private final VsumFileSystemLayout fileSystemLayout;

Expand Down Expand Up @@ -170,22 +172,22 @@ public void saveOrDeleteModels() {
}

@Override
public Iterable<TransactionalChange> recordChanges(Runnable changeApplicator) {
public Iterable<TransactionalChange<EObject>> recordChanges(Runnable changeApplicator) {
changeRecorder.beginRecording();
isRecording = true;
LOGGER.debug("Start recording virtual model");
changeApplicator.run();
LOGGER.debug("End recording virtual model");
isRecording = false;
changeRecorder.endRecording();
TransactionalChange change = changeRecorder.getChange();
EChangeUuidManager.setOrGenerateIds(change.getEChanges(), uuidResolver);
TransactionalChange<EObject> change = changeRecorder.getChange();
changeResolver.assignIds(change);
return change.containsConcreteChange() ? List.of(change) : List.of();
}

@Override
public VitruviusChange applyChange(VitruviusChange change) {
return change.resolveAndApply(uuidResolver);
public VitruviusChange<EObject> applyChange(VitruviusChange<Uuid> change) {
return changeResolver.resolveAndApply(change);
}

@Override
Expand Down
Loading

0 comments on commit 006fa78

Please sign in to comment.