blob: 71048bfcfdca07d3ba0fdf284c4fe55369a4794a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.runtime.internal.evaluation;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.utilities.TreeIterable;
import org.eclipse.qvtd.runtime.evaluation.AbstractTransformer;
import org.eclipse.qvtd.runtime.evaluation.TransformationExecutor;
import org.eclipse.qvtd.runtime.evaluation.TypedModelInstance;
/**
* An adapter implementation for tracking resource modification.
*/
public class ModificationMonitor implements Adapter
{
public static @Nullable ModificationMonitor basicGetModificationMonitor(@NonNull Resource resource, @NonNull TransformationExecutor executor) {
for (Adapter eAdapter : resource.eAdapters()) {
if (eAdapter instanceof ModificationMonitor) {
ModificationMonitor monitor = (ModificationMonitor)eAdapter;
if (monitor.getExecutor() == executor) {
return monitor;
}
}
}
return null;
}
public static @NonNull ModificationMonitor getModificationMonitor(@NonNull TypedModelInstance typedModelInstance, @NonNull Resource resource, @NonNull TransformationExecutor executor) {
List<Adapter> eAdapters = resource.eAdapters();
for (Adapter eAdapter : eAdapters) {
if (eAdapter instanceof ModificationMonitor) {
ModificationMonitor monitor = (ModificationMonitor)eAdapter;
if (monitor.getExecutor() == executor) {
return monitor;
}
}
}
ModificationMonitor monitor = new ModificationMonitor(typedModelInstance, resource, executor);
for (@NonNull EObject eObject : new TreeIterable(resource)) {
eObject.eAdapters().add(monitor);
}
eAdapters.add(monitor);
return monitor;
}
private final AbstractTransformerInternal.Model.@NonNull Incremental typedModelInstance;
private final @NonNull Resource resource;
private final @NonNull TransformationExecutor executor;
private final AbstractTransformer.@NonNull Incremental transformer;
// private final @NonNull IncrementalInvocationManager invocationManager;
private final @NonNull IncrementalObjectManager objectManager;
private @Nullable Deque<@NonNull Notification> notifications = null;
private boolean isDisabled = false;
public ModificationMonitor(@NonNull TypedModelInstance typedModelInstance, @NonNull Resource resource, @NonNull TransformationExecutor executor) {
this.typedModelInstance = (AbstractTransformerInternal.Model.Incremental)typedModelInstance;
this.resource = resource;
this.executor = executor;
this.transformer = (AbstractTransformer.Incremental) executor.getTransformer();
// this.transformer = (AbstractTransformer.Incremental) typedModelInstance.getTransformer();
// this.invocationManager = (IncrementalInvocationManager) transformer.getInvocationManager();
this.objectManager = (IncrementalObjectManager) transformer.getObjectManager();
}
protected void addEObject(@NonNull EObject newValue) {
for (@NonNull EObject eObject : new TreeIterable(newValue, true)) {
eObject.eAdapters().add(this);
}
typedModelInstance.add(newValue, false);
for (@NonNull EObject eObject : new TreeIterable(newValue, false)) {
typedModelInstance.add(eObject, true);
}
}
public void dispose() {
isDisabled = true;
Deque<@NonNull Notification> notifications2 = notifications;
if (notifications2 != null) {
notifications2.clear();
}
}
public @NonNull TransformationExecutor getExecutor() {
return executor;
}
@Override
public @NonNull Resource getTarget() {
return resource;
}
@Override
public boolean isAdapterForType(Object type) {
return type == ModificationMonitor.class;
}
@Override
public void notifyChanged(Notification notification)
{
if (isDisabled) {
return;
}
assert notification != null;
if (notification.isTouch()) {
return;
}
Deque<@NonNull Notification> notifications2 = notifications;
// assert notifications2 != null;
if (notifications2 != null) {
notifications2.add(notification);
return;
}
notifications2 = notifications = new ArrayDeque<>();
do {
int eventType = notification.getEventType();
switch (eventType) {
case Notification.ADD: {
EObject object2 = (EObject) notification.getNewValue();
assert object2 != null;
addEObject(object2);
break;
}
case Notification.REMOVE: {
EObject object2 = (EObject) notification.getOldValue();
assert object2 != null;
removeEObject(object2);
break;
}
case Notification.ADD_MANY: {
for (Object object : (Iterable<?>)notification.getNewValue()) {
EObject object2 = (EObject) object;
assert object2 != null;
addEObject(object2);
}
break;
}
case Notification.REMOVE_MANY: {
for (Object object : (Iterable<?>)notification.getOldValue()) {
EObject object2 = (EObject) object;
assert object2 != null;
removeEObject(object2);
}
break;
}
case Notification.SET:
case Notification.UNSET: {
Object notifier = notification.getNotifier();
assert notifier != null;
Object feature = notification.getFeature();
if (feature instanceof EStructuralFeature) {
objectManager.modified(notifier, (EStructuralFeature)feature);
}
break;
}
}
notification = notifications2.peek() != null ? notifications2.pop() : null;
} while (notification != null);
notifications = null;
}
protected void removeEObject(@NonNull EObject oldValue) {
for (EObject eObject : new TreeIterable(oldValue, true)) {
eObject.eAdapters().remove(this);
}
// if (feature instanceof EReference) {
// EReference eReference = (EReference)feature;
// if (eReference.isContainment()) {
IncrementalObjectManager objectManager = (IncrementalObjectManager)executor.getTransformer().getObjectManager();
// }
// }
for (EObject eObject : new TreeIterable(oldValue, true)) {
typedModelInstance.remove(eObject);
objectManager.destroyed(eObject);
}
}
@Override
public void setTarget(Notifier newTarget) {}
}