blob: 9a5403e97880fe8d66e3959a1d90c6d95046725b [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2016 itemis 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:
* itemis - Initial API and implementation
*
* </copyright>
*/
package org.eclipse.sphinx.emf.workspace.referentialintegrity;
import static org.eclipse.sphinx.emf.util.URIExtensions.replaceBaseURI;
import static org.eclipse.sphinx.emf.util.URIExtensions.replaceLastFragmentSegment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.sphinx.emf.util.EcoreResourceUtil;
import org.eclipse.sphinx.emf.workspace.internal.referentialintegrity.IntermittentRemoveTracker;
/**
* An abstract {@link IURIChangeDetectorDelegate} implementation the detection of changes in URIs with
* {@link URI#isHierarchical() hierarchical} {@link URI#fragment() fragments}.
*
* @see IURIChangeDetectorDelegate
*/
public abstract class AbstractHierarchicalFragmentURIChangeDetectorDelegate implements IURIChangeDetectorDelegate {
// Used for tracking contents being removed and added back elsewhere later on
protected final IntermittentRemoveTracker removedContentsTracker;
public AbstractHierarchicalFragmentURIChangeDetectorDelegate() {
removedContentsTracker = createIntermittentRemoveTracker();
}
protected IntermittentRemoveTracker createIntermittentRemoveTracker() {
return new IntermittentRemoveTracker();
}
protected abstract boolean affectsURIFragmentSegmentOfChangedObject(Notification notification);
/*
* @see
* org.eclipse.sphinx.emf.workspace.referencialintegrity.IURIChangeDetectorDelegate#detectChangedURIs(org.eclipse
* .emf .common.notify.Notification)
*/
@Override
public List<URIChangeNotification> detectChangedURIs(Notification notification) {
List<URIChangeNotification> notifications = new ArrayList<URIChangeNotification>();
if (notification.getNotifier() instanceof EObject) {
EObject eObject = (EObject) notification.getNotifier();
EStructuralFeature feature = (EStructuralFeature) notification.getFeature();
// Detect object URI changes due to modifications that affect the URIs of the modified object and its
// contents
if (affectsURIFragmentSegmentOfChangedObject(notification)) {
URI newURI = EcoreResourceUtil.getURI(eObject);
URI oldURI = replaceLastFragmentSegment(newURI, notification.getNewStringValue(), notification.getOldStringValue());
if (oldURI != null && !oldURI.equals(newURI)) {
addURIChangeNotification(notifications, eObject, oldURI, newURI);
}
}
// Detect object URI changes due to contents being removed and added back elsewhere
else if (feature instanceof EReference && ((EReference) feature).isContainment()) {
removedContentsTracker.clearObsoleteEntries();
if (Notification.REMOVE == notification.getEventType()) {
URI containerURI = EcoreResourceUtil.getURI(eObject);
handleRemovedContent(eObject, containerURI, feature, (EObject) notification.getOldValue());
} else if (Notification.ADD == notification.getEventType()) {
handleAddedContent(notifications, (EObject) notification.getNewValue());
} else if (Notification.REMOVE_MANY == notification.getEventType()) {
URI containerURI = EcoreResourceUtil.getURI(eObject);
@SuppressWarnings("unchecked")
List<EObject> oldValues = (List<EObject>) notification.getOldValue();
for (EObject oldValue : oldValues) {
handleRemovedContent(eObject, containerURI, feature, oldValue);
}
} else if (Notification.ADD_MANY == notification.getEventType()) {
@SuppressWarnings("unchecked")
List<EObject> newValues = (List<EObject>) notification.getNewValue();
for (EObject newValue : newValues) {
handleAddedContent(notifications, newValue);
}
}
}
}
return notifications;
}
protected void handleRemovedContent(EObject oldContainer, URI oldContainerURI, EStructuralFeature oldFeature, EObject oldContent) {
URI oldContentURI = null;
// Old content just removed but not yet added back elsewhere?
if (oldContent.eResource() == null) {
// Restore old content URI using old container and old containing feature
oldContentURI = EcoreResourceUtil.getURI(oldContainer, oldFeature, oldContent);
} else {
// Restore old content URI by replacing the URI of the new container at the beginning of the old
// content's new URI with the URI of its old container
URI newContentURI = EcoreResourceUtil.getURI(oldContent);
URI newContainerURI = EcoreResourceUtil.getURI(oldContent.eContainer());
oldContentURI = replaceBaseURI(newContentURI, newContainerURI, oldContainerURI);
}
// Keep track of the removed object and its old URI so that we can issue an appropriately initialized URI
// change notification in case it will get or already has been added back somewhere else
if (oldContentURI != null) {
removedContentsTracker.put(oldContent, oldContentURI);
}
}
protected void handleAddedContent(List<URIChangeNotification> notifications, EObject newContent) {
URI oldContentURI = removedContentsTracker.get(newContent);
if (oldContentURI != null) {
URI newContentURI = EcoreResourceUtil.getURI(newContent);
if (!oldContentURI.equals(newContentURI)) {
addURIChangeNotification(notifications, newContent, oldContentURI, newContentURI);
}
}
}
protected void addURIChangeNotification(List<URIChangeNotification> notifications, EObject eObject, URI oldURI, URI newURI) {
// Add URI change notification for given EObject
notifications.add(new URIChangeNotification(eObject, oldURI));
// Add URI change notifications for all EObjects that are directly or indirectly contained by given EObject and
// have URIs that are affected by the change on given EObject
TreeIterator<EObject> eAllContents = eObject.eAllContents();
while (eAllContents.hasNext()) {
EObject contentObject = eAllContents.next();
URI newContentURI = EcoreResourceUtil.getURI(contentObject);
URI oldContentURI = replaceBaseURI(newContentURI, newURI, oldURI);
if (oldContentURI != null && !oldContentURI.equals(newContentURI)) {
notifications.add(new URIChangeNotification(contentObject, oldContentURI));
}
}
}
/*
* @see
* org.eclipse.sphinx.emf.workspace.referencialintegrity.IURIChangeDetectorDelegate#detectChangedURIs(org.eclipse
* .core .resources.IFile, org.eclipse.core.resources.IFile)
*/
@Override
public List<URIChangeNotification> detectChangedURIs(IFile oldFile, IFile newFile) {
return Collections.emptyList();
}
}