Commit ee8e1dff authored by Andras Janko's avatar Andras Janko Committed by Balazs Grill
Browse files

Bug 577073 URI change detector delegate extension



Change-Id: I011d20c8e752ef51bab6afd8c0c30ecfff908630
Signed-off-by: default avatarAndras Janko <andras.janko@incquerylabs.com>
Signed-off-by: default avatarBalazs Varnai <balazs_varnai@mentor.com>
parent 86feea43
Loading
Loading
Loading
Loading
+106 −42
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2016 itemis and others.
 * Copyright (c) 2016-2021 itemis, Siemens 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
@@ -9,6 +9,7 @@
 *
 * Contributors:
 *     itemis - Initial API and implementation
 *     Siemens - [577073] URI change detector delegate extension
 *
 * </copyright>
 */
@@ -19,7 +20,10 @@ import static org.eclipse.sphinx.emf.util.URIExtensions.replaceLastFragmentSegme

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.notify.Notification;
@@ -28,6 +32,7 @@ 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.emf.ecore.resource.Resource;
import org.eclipse.sphinx.emf.util.EcoreResourceUtil;
import org.eclipse.sphinx.emf.workspace.internal.referentialintegrity.IntermittentRemoveTracker;

@@ -54,53 +59,107 @@ public abstract class AbstractHierarchicalFragmentURIChangeDetectorDelegate impl

	/*
	 * @see
	 * org.eclipse.sphinx.emf.workspace.referencialintegrity.IURIChangeDetectorDelegate#detectChangedURIs(org.eclipse
	 * .emf .common.notify.Notification)
	 * org.eclipse.sphinx.emf.workspace.referentialintegrity.IURIChangeDetectorDelegate#detectChangedURIs(java.util.
	 * List)
	 */
	@Override
	public Map<Resource, List<URIChangeNotification>> detectChangedURIs(List<Notification> notifications) {
		if (notifications != null) {
			Map<Resource, List<URIChangeNotification>> resourceToUriChangeNotification = new HashMap<>(notifications.size());

			for (Notification notification : notifications) {
				Object notifierObj = notification.getNotifier();
				if (notifierObj instanceof EObject) {
					EObject notifier = (EObject) notifierObj;
					Resource resource = notifier.eResource();

					List<URIChangeNotification> uriNotifications = handleNotification(notification, notifier);

					if (uriNotifications != null && !uriNotifications.isEmpty()) {
						if (resourceToUriChangeNotification.get(resource) == null) {
							resourceToUriChangeNotification.put(resource, uriNotifications);
						} else {
							resourceToUriChangeNotification.get(resource).addAll(uriNotifications);
						}
					}
				}
			}
			return resourceToUriChangeNotification;
		}
		return Collections.emptyMap();
	}

	/*
	 * @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();
		if (notification != null) {
			Object notifierObj = notification.getNotifier();
			if (notifierObj instanceof EObject) {
				return handleNotification(notification, (EObject) notifierObj);
			}
		}
		return Collections.emptyList();
	}

	protected List<URIChangeNotification> handleNotification(Notification notification, EObject notifier) {
		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)) {
			return handleURIFragmentSegmentChange(notification, notifier);
		}
		// Detect object URI changes due to contents being removed and added back elsewhere
		else if (feature instanceof EReference && ((EReference) feature).isContainment()) {
			return handleContainmentChange(notification, notifier, feature);
		}

		return Collections.emptyList();
	}

	protected List<URIChangeNotification> handleURIFragmentSegmentChange(Notification notification, EObject eObject) {
		URI newURI = EcoreResourceUtil.getURI(eObject);
		URI oldURI = replaceLastFragmentSegment(newURI, notification.getNewStringValue(), notification.getOldStringValue());
		if (oldURI != null && !oldURI.equals(newURI)) {
					addURIChangeNotification(notifications, eObject, oldURI, newURI);
			return addURIChangeNotification(eObject, oldURI, newURI);
		}
		return Collections.emptyList();
	}

			// Detect object URI changes due to contents being removed and added back elsewhere
			else if (feature instanceof EReference && ((EReference) feature).isContainment()) {
	protected List<URIChangeNotification> handleContainmentChange(Notification notification, EObject eObject, EStructuralFeature feature) {
		removedContentsTracker.clearObsoleteEntries();

		if (Notification.REMOVE == notification.getEventType()) {
			URI containerURI = EcoreResourceUtil.getURI(eObject);
			if (notification.getOldValue() instanceof EObject) {
				handleRemovedContent(eObject, containerURI, feature, (EObject) notification.getOldValue());
			}
		} else if (Notification.ADD == notification.getEventType()) {
					handleAddedContent(notifications, (EObject) notification.getNewValue());
			return handleAddedContent((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);
			List<?> oldValues = (List<?>) notification.getOldValue();
			for (Object oldValue : oldValues) {
				if (oldValue instanceof EObject) {
					handleRemovedContent(eObject, containerURI, feature, (EObject) oldValue);
				}
			}
		} else if (Notification.ADD_MANY == notification.getEventType()) {
			List<?> newValues = (List<?>) notification.getNewValue();
			List<URIChangeNotification> notifications = new ArrayList<>(newValues.size());
			for (Object newValue : newValues) {
				if (newValue instanceof EObject) {
					notifications.addAll(handleAddedContent((EObject) newValue));
				}
			}
			return notifications;
		}
		return Collections.emptyList();
	}

	protected void handleRemovedContent(EObject oldContainer, URI oldContainerURI, EStructuralFeature oldFeature, EObject oldContent) {
		URI oldContentURI = null;
@@ -124,17 +183,20 @@ public abstract class AbstractHierarchicalFragmentURIChangeDetectorDelegate impl
		}
	}

	protected void handleAddedContent(List<URIChangeNotification> notifications, EObject newContent) {
	protected List<URIChangeNotification> handleAddedContent(EObject newContent) {
		URI oldContentURI = removedContentsTracker.get(newContent);
		if (oldContentURI != null) {
			URI newContentURI = EcoreResourceUtil.getURI(newContent);
			if (!oldContentURI.equals(newContentURI)) {
				addURIChangeNotification(notifications, newContent, oldContentURI, newContentURI);
				return addURIChangeNotification(newContent, oldContentURI, newContentURI);
			}
		}
		return Collections.emptyList();
	}

	protected void addURIChangeNotification(List<URIChangeNotification> notifications, EObject eObject, URI oldURI, URI newURI) {
	protected List<URIChangeNotification> addURIChangeNotification(EObject eObject, URI oldURI, URI newURI) {
		List<URIChangeNotification> notifications = new LinkedList<>();

		// Add URI change notification for given EObject
		notifications.add(new URIChangeNotification(eObject, oldURI));

@@ -149,6 +211,8 @@ public abstract class AbstractHierarchicalFragmentURIChangeDetectorDelegate impl
				notifications.add(new URIChangeNotification(contentObject, oldContentURI));
			}
		}

		return notifications;
	}

	/*
+24 −6
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2010 See4sys and others.
 * Copyright (c) 2008-2021 See4sys, Siemens 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
@@ -9,17 +9,20 @@
 *
 * Contributors:
 *     See4sys - Initial API and implementation
 *     Siemens - [577073] URI change detector delegate extension
 *
 * </copyright>
 */
package org.eclipse.sphinx.emf.workspace.referentialintegrity;

import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;

/**
 * Interface that determines URIChangeDetectorDelegate API.see also {@link URIChangeDetectorDelegateRegistry}
@@ -27,12 +30,28 @@ import org.eclipse.emf.ecore.EObject;
public interface IURIChangeDetectorDelegate {

	/**
	 * Detects all the model changed {@link URI}s from a given resource set event {@link Notification}
	 * Detects all the model changed {@link URI}s from the given resource set events {@link Notification}. This method
	 * deprecates the {@link IURIChangeDetectorDelegate#detectChangedURIs(Notification)}.
	 *
	 * @param notification
	 *            The notification from the resource set event to use for computing the changed {@link URI}s
	 * @return A map containing new {@link EObject new EObject} , {@link URI old URI} pairs.
	 * @return A map containing entries of {@link Resource} to new {@link EObject new EObject} and {@link URI old URI}
	 *         pairs. Null return value is interpreted by the caller as this method is not implemented. Empty map return
	 *         value shall be used to signal that there were no changed {@link URI}s.
	 */
	public Map<Resource, List<URIChangeNotification>> detectChangedURIs(List<Notification> notifications);

	/**
	 * Detects all the model changed {@link URI}s from a given resource set event {@link Notification}.
	 *
	 * @deprecated Use {@link IURIChangeDetectorDelegate#detectChangedURIs(List)} instead. However, if that method
	 *             returns null value, this method is called to detect {@link URI} changes. This behavior is kept until
	 *             this method is completely removed from the API.
	 * @param notification
	 *            The notification from the resource set event to use for computing the changed {@link URI}s
	 * @return A list containing new {@link EObject new EObject} , {@link URI old URI} pairs.
	 */
	@Deprecated
	public List<URIChangeNotification> detectChangedURIs(Notification notification);

	/**
@@ -45,5 +64,4 @@ public interface IURIChangeDetectorDelegate {
	 * @return A map containing {@link EObject new EObject} , {@link URI old URI} pairs.
	 */
	public List<URIChangeNotification> detectChangedURIs(IFile oldFile, IFile newFile);

}
+36 −7
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2013 See4sys, BMW Car IT, itemis and others.
 * Copyright (c) 2008-2021 See4sys, BMW Car IT, itemis, Siemens 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
@@ -11,12 +11,16 @@
 *     See4sys - Initial API and implementation
 *     BMW Car IT - Avoid usage of Object.finalize
 *     itemis - [409014] Listener URIChangeDetector registered for all transactional editing domains
 *     Siemens - [577073] URI change detector delegate extension
 *
 * </copyright>
 */
package org.eclipse.sphinx.emf.workspace.referentialintegrity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResourceChangeEvent;
@@ -71,27 +75,52 @@ public class URIChangeDetector extends ResourceSetListenerImpl implements IResou
	}

	/*
	 * @see
	 * org.eclipse.emf.transaction.ResourceSetListener#resourceSetChanged(org.eclipse.emf.transaction.ResourceSetChangeEvent
	 * )
	 * @see org.eclipse.emf.transaction.ResourceSetListener#resourceSetChanged(org.eclipse.emf.transaction.
	 * ResourceSetChangeEvent )
	 */
	@Override
	public void resourceSetChanged(ResourceSetChangeEvent event) {
		List<?> notifications = event.getNotifications();

		// Split the notifications based on their delegate handler into smaller lists
		Map<IURIChangeDetectorDelegate, List<Notification>> delegateToNotifications = new HashMap<>();
		for (Object o : notifications) {
			if (o instanceof Notification) {
				Notification notification = (Notification) o;
				if (notification.getNotifier() instanceof EObject) {
					EObject newEObject = (EObject) notification.getNotifier();
					Resource resource = newEObject.eResource();
					Resource resource = ((EObject) notification.getNotifier()).eResource();
					IURIChangeDetectorDelegate delegate = URIChangeDetectorDelegateRegistry.INSTANCE.getDetectorDelegate(resource);

					if (delegate != null) {
						delegateToNotifications.computeIfAbsent(delegate, d -> new ArrayList<Notification>()).add(notification);
					}
				}
			}
		}

		for (IURIChangeDetectorDelegate delegate : delegateToNotifications.keySet()) {

			List<Notification> delegateNotifications = delegateToNotifications.get(delegate);
			Map<Resource, List<URIChangeNotification>> resourceToUriNotifications = delegate.detectChangedURIs(delegateNotifications);

			if (resourceToUriNotifications == null) {
				/** assume that the new API is not implemented, call the deprecated API */
				for (Notification notification : delegateNotifications) {
					if (notification.getNotifier() instanceof EObject) {
						EObject newEObject = (EObject) notification.getNotifier();
						Resource resource = newEObject.eResource();

						@SuppressWarnings("deprecation")
						List<URIChangeNotification> uriNotifications = delegate.detectChangedURIs(notification);
						if (!uriNotifications.isEmpty()) {
						if (uriNotifications != null && !uriNotifications.isEmpty()) {
							fireURIChanged(createURIChangeEvent(resource, uriNotifications));
						}
					}
				}
			} else if (!resourceToUriNotifications.isEmpty()) {
				for (Resource resource : resourceToUriNotifications.keySet()) {
					fireURIChanged(createURIChangeEvent(resource, resourceToUriNotifications.get(resource)));
				}
			}
		}
	}
+13 −14
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2010 See4sys and others.
 * Copyright (c) 2008-2021 See4sys, Siemens 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
@@ -9,15 +9,16 @@
 *
 * Contributors:
 *     See4sys - Initial API and implementation
 *     Siemens - [577073] URI change detector delegate extension
 *
 * </copyright>
 */
package org.eclipse.sphinx.emf.workspace.referentialintegrity;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -45,9 +46,9 @@ public class URIChangeDetectorDelegateRegistry {
	private static final String ATTR_OVERRIDE = "override"; //$NON-NLS-1$
	private static final String ATTR_RESOURCE_TYPE = "resourceType";//$NON-NLS-1$

	public static URIChangeDetectorDelegateRegistry INSTANCE = new URIChangeDetectorDelegateRegistry();
	public static final URIChangeDetectorDelegateRegistry INSTANCE = new URIChangeDetectorDelegateRegistry();

	private Map<Class<? extends Resource>, IURIChangeDetectorDelegate> fContributedURIChangeDetectorDelegates = new HashMap<Class<? extends Resource>, IURIChangeDetectorDelegate>();
	private final Map<Class<? extends Resource>, IURIChangeDetectorDelegate> fContributedURIChangeDetectorDelegates = new ConcurrentHashMap<Class<? extends Resource>, IURIChangeDetectorDelegate>();

	private URIChangeDetectorDelegateRegistry() {
		readContributedURIChangeDetectors();
@@ -188,10 +189,8 @@ public class URIChangeDetectorDelegateRegistry {
					if (!overriddenIds.contains(overriddenURIChangeDetectorDelegateId)) {
						overriddenIds.add(overriddenURIChangeDetectorDelegateId);
					} else {
						PlatformLogUtil.logAsWarning(
								Activator.getPlugin(),
								new RuntimeException(NLS.bind(Messages.warning_multipleOverridesForSameURIChangeDetectorDelegate,
										overriddenURIChangeDetectorDelegateId)));
						PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(
								NLS.bind(Messages.warning_multipleOverridesForSameURIChangeDetectorDelegate, overriddenURIChangeDetectorDelegateId)));
					}
				}
			}
+11 −11
Original line number Diff line number Diff line
/**
 * <copyright>
 *
 * Copyright (c) 2008-2012 See4sys, BMW Car IT and others.
 * Copyright (c) 2008-2021 See4sys, BMW Car IT, Siemens 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
@@ -10,6 +10,7 @@
 * Contributors:
 *     See4sys - Initial API and implementation
 *     BMW Car IT - Avoid usage of Object.finalize
 *     Siemens - [577073] URI change detector delegate extension
 *
 * </copyright>
 */
@@ -17,6 +18,7 @@ package org.eclipse.sphinx.emf.workspace.referentialintegrity;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IConfigurationElement;
@@ -34,7 +36,7 @@ import org.eclipse.sphinx.platform.util.PlatformLogUtil;
public class URIChangeListenerRegistry {
	public static URIChangeListenerRegistry INSTANCE = new URIChangeListenerRegistry();

	private Set<IURIChangeListener> fURIChangeListeners = new HashSet<IURIChangeListener>();
	private Set<IURIChangeListener> fURIChangeListeners = ConcurrentHashMap.newKeySet();

	private static final String EXTP_URI_CHANGE_LISTENERS = "org.eclipse.sphinx.emf.workspace.uriChangeListeners"; //$NON-NLS-1$

@@ -124,10 +126,8 @@ public class URIChangeListenerRegistry {
					if (!overriddenIds.contains(overriddenURIChangeDetectorDelegateId)) {
						overriddenIds.add(overriddenURIChangeDetectorDelegateId);
					} else {
						PlatformLogUtil.logAsWarning(
								Activator.getPlugin(),
								new RuntimeException(NLS.bind(Messages.warning_multipleOverridesForSameURIChangeListener,
										overriddenURIChangeDetectorDelegateId)));
						PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(
								NLS.bind(Messages.warning_multipleOverridesForSameURIChangeListener, overriddenURIChangeDetectorDelegateId)));
					}
				}
			}
Loading