| /******************************************************************************* |
| * Copyright (c) 2011, 2018 Obeo 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: |
| * Obeo - initial API and implementation |
| * Michael Borkowski - public visibility |
| *******************************************************************************/ |
| package org.eclipse.emf.compare.ide.ui.internal.logical.resolver; |
| |
| import com.google.common.collect.Sets; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.locks.ReentrantLock; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.NotificationChain; |
| import org.eclipse.emf.common.util.AbstractEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.compare.ide.internal.utils.DisposableResourceSet; |
| import org.eclipse.emf.compare.ide.internal.utils.INamespaceDeclarationListener; |
| import org.eclipse.emf.compare.ide.internal.utils.IProxyCreationListener; |
| import org.eclipse.emf.compare.ide.internal.utils.NoNotificationParserPool; |
| import org.eclipse.emf.compare.rcp.EMFCompareLogger; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.resource.ContentHandler; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| |
| /** |
| * A thread-safe implementation of a ResourceSet that will prevent loading of resources unless explicitly |
| * demanded through {@link #loadResource(URI)}. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| // Visible for testing |
| public class SynchronizedResourceSet extends ResourceSetImpl implements DisposableResourceSet { |
| /** The logger. */ |
| private static final EMFCompareLogger LOGGER = new EMFCompareLogger(SynchronizedResourceSet.class); |
| |
| /** Associates URIs with their resources. */ |
| private final ConcurrentHashMap<URI, Resource> uriCache; |
| |
| /** |
| * The list of URIs corresponding to namespaces as declared in the xml files ("xmlns:"). These must not go |
| * through our usual xml parser as they have to be properly (and completely) loaded. They also need to be |
| * kept in this resource set and made available for other resources to find as they might have associated |
| * factories to create objects. |
| */ |
| private final Set<URI> namespaceURIs; |
| |
| /** Keeps track of the packages manually loaded for some of this resource set's resources. */ |
| private final Set<Resource> loadedPackages; |
| |
| /** Never try and load the same package twice. We'll use this lock to prevent that from happening. */ |
| private final ReentrantLock packageLoadingLock; |
| |
| /** |
| * Constructor. |
| * |
| * @param proxyListener |
| * The listener to notify of proxy creations. |
| */ |
| public SynchronizedResourceSet(IProxyCreationListener proxyListener) { |
| this.uriCache = new ConcurrentHashMap<URI, Resource>(); |
| this.resources = new SynchronizedResourcesEList<Resource>(); |
| this.namespaceURIs = Sets.newSetFromMap(new ConcurrentHashMap<URI, Boolean>()); |
| this.loadedPackages = Sets.newSetFromMap(new ConcurrentHashMap<Resource, Boolean>()); |
| this.packageLoadingLock = new ReentrantLock(true); |
| this.loadOptions = super.getLoadOptions(); |
| /* |
| * This resource set is specifically designed to resolve cross resources links, it thus spends a lot |
| * of time loading resources. The following set of options is what seems to give the most significant |
| * boost in loading performances, though I did not fine-tune what's really needed here. |
| */ |
| final NoNotificationParserPool parserPool = new NoNotificationParserPool(true); |
| parserPool.addProxyListener(proxyListener); |
| parserPool.addNamespaceDeclarationListener(new INamespaceDeclarationListener() { |
| public void schemaLocationDeclared(String key, URI uri) { |
| namespaceURIs.add(uri.trimFragment()); |
| } |
| }); |
| loadOptions.put(XMLResource.OPTION_USE_PARSER_POOL, parserPool); |
| loadOptions.put(XMLResource.OPTION_USE_DEPRECATED_METHODS, Boolean.FALSE); |
| loadOptions.put(XTEXT_SCOPING_LIVE_SCOPE_OPTION, Boolean.TRUE); |
| |
| /* |
| * We don't use XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP whereas it could bring performance |
| * improvements because we are loading the resources concurrently and this map could be used (put and |
| * get) by several threads. Passing a ConcurrentMap here is not an option either as EMF sometimes |
| * needs to put "null" values in there. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=403425 for |
| * more details. |
| */ |
| /* |
| * Most of the existing options we are not using from here, since none of them seems to have a single |
| * effect on loading performance, whether we're looking at time or memory. See also |
| * https://www.eclipse.org/forums/index.php/t/929918/ |
| */ |
| } |
| |
| /** |
| * This will load the given URI as an EMF Resource. |
| * <p> |
| * This is the only entry point within this resource set to load an EMF resource, and it will _only_ load |
| * the resource pointed at by <code>uri</code>, ignoring all cross-referenced resources (including |
| * containment proxies). |
| * </p> |
| * |
| * @param uri |
| * The URI to load as a resource. |
| * @return The loaded Resource. |
| */ |
| public Resource loadResource(URI uri) { |
| /* |
| * Don't use super.getResource : we know the resource does not exist yet as there will only be one |
| * "load" call for each given URI. The super implementation iterates over loaded resources before |
| * doing any actual work. That causes some minimal overhead but, more importantly, it can generate |
| * concurrent modification exceptions. |
| */ |
| final URIConverter theURIConverter = getURIConverter(); |
| final URI normalizedURI = theURIConverter.normalize(uri); |
| |
| Resource result = null; |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".loadResource for " + normalizedURI); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| result = uriCache.get(normalizedURI); |
| if (result == null) { |
| result = delegatedGetResource(uri, true); |
| if (result != null) { |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".loadResource - caching " //$NON-NLS-1$ //$NON-NLS-2$ |
| + normalizedURI); |
| } |
| Resource former = uriCache.putIfAbsent(normalizedURI, result); |
| if (former != null) { |
| result = former; |
| } |
| } else if (namespaceURIs.contains(uri)) { |
| // This uri points to an EPackage (or profile) that needs to be loaded completely and |
| // normally for its factory to be useable. |
| result = demandPackageLoad(uri); |
| } |
| } |
| |
| if (result == null) { |
| result = demandCreateResource(uri); |
| if (getURIConverter() instanceof RevisionedURIConverter) { |
| try { |
| if (!((RevisionedURIConverter)getURIConverter()).prefetchStream(uri, getLoadOptions())) { |
| // Don't try and load. This resource doesn't exist on that side |
| return result; |
| } |
| } catch (IOException e) { |
| // Let EMF handle this one. |
| } |
| } |
| if (result == null) { |
| // copy/pasted from super.getResource |
| throw new RuntimeException("Cannot create a resource for '" + uri //$NON-NLS-1$ |
| + "'; a registered resource factory is needed"); //$NON-NLS-1$ |
| } |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".loadResource - No caching for " //$NON-NLS-1$ //$NON-NLS-2$ |
| + normalizedURI); |
| } |
| demandLoadHelper(result); |
| } |
| return result; |
| } |
| |
| /** |
| * Loads the given URI as an EMF EPackage. We will disable our custom parser pool for this one as it need |
| * to be loaded properly for its factory to be functional. |
| * |
| * @param uri |
| * The uri to load. |
| * @param normalized |
| * the normalized form of this URI. |
| * @return The loaded resource. |
| */ |
| private Resource loadPackage(URI uri, URI normalized) { |
| final URI trimmed = uri.trimFragment(); |
| final Resource resource = createResource(trimmed, ContentHandler.UNSPECIFIED_CONTENT_TYPE); |
| if (resource == null) { |
| return null; |
| } |
| |
| // cache this asap. there might be recursive calls to "getResource" with this package URI (as can be |
| // observed with the UML Ecore profile for example) during the loading itself; in which case we need |
| // to return that same "currently loading" instance. |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".getResource - caching package " + uri); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| Resource former = uriCache.putIfAbsent(normalized, resource); |
| if (former != null) { |
| // There was already a resource cached (multi-threading makes it possible) |
| return former; |
| } |
| |
| try (InputStream stream = getURIConverter().createInputStream(trimmed, null)) { |
| resource.load(stream, Collections.emptyMap()); |
| } catch (IOException e) { |
| handleDemandLoadException(resource, e); |
| } |
| loadedPackages.add(resource); |
| return resource; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#handleDemandLoadException(org.eclipse.emf.ecore.resource.Resource, |
| * java.io.IOException) |
| */ |
| @Override |
| protected void handleDemandLoadException(Resource resource, IOException exception) { |
| try { |
| super.handleDemandLoadException(resource, exception); |
| } catch (RuntimeException e) { |
| // do nothing, continue with loading, the exception has been added to the diagnostics of the |
| // resource |
| } |
| } |
| |
| /** |
| * Unload the given resource. |
| * |
| * @param resource |
| * Resource to unlod |
| * @param monitor |
| * Progress monito to use (currently unused) |
| */ |
| public void unload(Resource resource, IProgressMonitor monitor) { |
| final URI uri = resource.getURI(); |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".unload " + uri); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| uriCache.remove(uri); |
| getResources().remove(resource); |
| resource.eAdapters().clear(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#getResource(org.eclipse.emf.common.util.URI, |
| * boolean) |
| */ |
| @Override |
| public Resource getResource(URI uri, boolean loadOnDemand) { |
| // Never load resources from here, we only care for the EPackages to prevent the XMLHandler from going |
| // into a stackoverflow |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".getResource for " + uri); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| final URI normalized = getURIConverter().normalize(uri); |
| Resource demanded = uriCache.get(normalized); |
| if (namespaceURIs.contains(uri) && demanded != null) { |
| ensurePackageLoaded(demanded); |
| } |
| |
| if (demanded == null) { |
| final EPackage ePackage = getPackageRegistry().getEPackage(uri.toString()); |
| if (ePackage != null) { |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) //$NON-NLS-1$ |
| + ".getResource - found in package registry : " + uri); //$NON-NLS-1$ |
| } |
| demanded = ePackage.eResource(); |
| if (demanded != null) { |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".getResource - caching " //$NON-NLS-1$ //$NON-NLS-2$ |
| + uri); |
| } |
| Resource former = uriCache.putIfAbsent(normalized, demanded); |
| if (former != null) { |
| demanded = former; |
| } |
| } |
| } else if (namespaceURIs.contains(uri)) { |
| // This uri points to an EPackage (or profile) that needs to be loaded completely and |
| // normally. |
| demanded = demandPackageLoad(uri); |
| } |
| } else if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".getResource - FOUND in cache " + uri); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| return demanded; |
| } |
| |
| /** |
| * This will be used to load the uris matching those from {@link #namespaceURIs} normally. |
| * |
| * @param uri |
| * The uri of the package to load. |
| * @return The loaded package's resource. |
| */ |
| private Resource demandPackageLoad(URI uri) { |
| final URI normalized = getURIConverter().normalize(uri); |
| |
| packageLoadingLock.lock(); |
| try { |
| Resource demanded = uriCache.get(normalized); |
| if (demanded == null) { |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) //$NON-NLS-1$ |
| + ".getResource - loaded package normally : " + uri); //$NON-NLS-1$ |
| } |
| demanded = loadPackage(uri, normalized); |
| } |
| return demanded; |
| } finally { |
| packageLoadingLock.unlock(); |
| } |
| } |
| |
| /** |
| * {@link #loadPackage(URI, URI)} will push the packages' resource in {@link #uriCache cache} before the |
| * package is actually loaded in order to avoid multi-threading issues. However, multi-threading can also |
| * make it so that another thread asks for a resource in cache and return it before the actual loading |
| * ends. This will lock that latter thread until the package is finished loading. |
| */ |
| private void ensurePackageLoaded(Resource packageResource) { |
| if (!packageResource.isLoaded() || ((Resource.Internal)packageResource).isLoading()) { |
| packageLoadingLock.lock(); |
| try { |
| ensurePackageLoaded(packageResource); |
| } finally { |
| packageLoadingLock.unlock(); |
| } |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#createResource(org.eclipse.emf.common.util.URI) |
| */ |
| @Override |
| public synchronized Resource createResource(URI uri) { |
| return super.createResource(uri); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#createResource(org.eclipse.emf.common.util.URI, |
| * java.lang.String) |
| */ |
| @Override |
| public synchronized Resource createResource(URI uri, String contentType) { |
| return super.createResource(uri, contentType); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#getResources() |
| */ |
| @Override |
| public EList<Resource> getResources() { |
| return resources; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl#getLoadOptions() |
| */ |
| @Override |
| public Map<Object, Object> getLoadOptions() { |
| return loadOptions; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void dispose() { |
| // unload these completely instead of using #unload(Resource) |
| for (Resource resource : loadedPackages) { |
| final URI uri = resource.getURI(); |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("SRS@" + Integer.toHexString(hashCode()) + ".unload " + uri); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| uriCache.remove(uri); |
| resource.unload(); |
| getResources().remove(resource); |
| } |
| } |
| |
| /** |
| * A synchronized implementation of {@link ResourcesEList}. |
| * <p> |
| * Note that this cannot be extracted out of the {@link SynchronizedResourceSet} since the |
| * {@link ResourcesEList} type is not visible. |
| * </p> |
| * |
| * @param <E> |
| * Type of this list's contents. |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| private class SynchronizedResourcesEList<E extends Resource> extends ResourcesEList<E> { |
| /** Generated SUID. */ |
| private static final long serialVersionUID = 7371376112881960414L; |
| |
| /** The lock we'll use for synchronization of the resources list. */ |
| private final Object lock = new Object(); |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.util.AbstractCollection#containsAll(java.util.Collection) |
| */ |
| @Override |
| public boolean containsAll(Collection<?> c) { |
| synchronized(lock) { |
| return super.containsAll(c); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#set(int, java.lang.Object) |
| */ |
| @Override |
| public E set(int index, E object) { |
| synchronized(lock) { |
| return super.set(index, object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#dispatchNotification(org.eclipse.emf.common.notify.Notification) |
| */ |
| @Override |
| protected void dispatchNotification(Notification notification) { |
| // do nothing |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#add(java.lang.Object) |
| */ |
| @Override |
| public boolean add(E object) { |
| synchronized(lock) { |
| return super.add(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#add(int, java.lang.Object) |
| */ |
| @Override |
| public void add(int index, E object) { |
| synchronized(lock) { |
| super.add(index, object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#addAll(java.util.Collection) |
| */ |
| @Override |
| public boolean addAll(Collection<? extends E> collection) { |
| synchronized(lock) { |
| return super.addAll(collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#addAll(int, java.util.Collection) |
| */ |
| @Override |
| public boolean addAll(int index, Collection<? extends E> collection) { |
| synchronized(lock) { |
| return super.addAll(index, collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#remove(java.lang.Object) |
| */ |
| @Override |
| public boolean remove(Object object) { |
| synchronized(lock) { |
| return super.remove(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#retainAll(java.util.Collection) |
| */ |
| @Override |
| public boolean retainAll(Collection<?> collection) { |
| synchronized(lock) { |
| return super.retainAll(collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#move(int, java.lang.Object) |
| */ |
| @Override |
| public void move(int index, E object) { |
| synchronized(lock) { |
| super.move(index, object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object object) { |
| synchronized(lock) { |
| return super.equals(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| synchronized(lock) { |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#toString() |
| */ |
| @Override |
| public String toString() { |
| synchronized(lock) { |
| return super.toString(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#iterator() |
| */ |
| @Override |
| public Iterator<E> iterator() { |
| return new SynchronizedEIterator(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#listIterator() |
| */ |
| @Override |
| public ListIterator<E> listIterator() { |
| return new SynchronizedEListIterator(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList#listIterator(int) |
| */ |
| @Override |
| public ListIterator<E> listIterator(int index) { |
| synchronized(lock) { |
| int curSize = size(); |
| if (index < 0 || index > curSize) { |
| throw new BasicIndexOutOfBoundsException(index, curSize); |
| } |
| return new SynchronizedEListIterator(index); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#indexOf(java.lang.Object) |
| */ |
| @Override |
| public int indexOf(Object object) { |
| synchronized(lock) { |
| return super.indexOf(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#lastIndexOf(java.lang.Object) |
| */ |
| @Override |
| public int lastIndexOf(Object object) { |
| synchronized(lock) { |
| return super.lastIndexOf(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#toArray() |
| */ |
| @Override |
| public Object[] toArray() { |
| synchronized(lock) { |
| return super.toArray(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#toArray(T[]) |
| */ |
| @Override |
| public <T> T[] toArray(T[] array) { |
| synchronized(lock) { |
| return super.toArray(array); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#setData(int, java.lang.Object[]) |
| */ |
| @Override |
| public void setData(int size, Object[] data) { |
| synchronized(lock) { |
| super.setData(size, data); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#get(int) |
| */ |
| @Override |
| public E get(int index) { |
| synchronized(lock) { |
| return super.get(index); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#basicGet(int) |
| */ |
| @Override |
| public E basicGet(int index) { |
| synchronized(lock) { |
| return super.basicGet(index); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#shrink() |
| */ |
| @Override |
| public void shrink() { |
| synchronized(lock) { |
| super.shrink(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#grow(int) |
| */ |
| @Override |
| public void grow(int minimumCapacity) { |
| synchronized(lock) { |
| super.grow(minimumCapacity); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#clone() |
| */ |
| // CHECKSTYLE:OFF we're overriding... |
| @Override |
| public Object clone() { |
| // CHECKSTYLE:ON |
| synchronized(lock) { |
| return super.clone(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addUnique(java.lang.Object) |
| */ |
| @Override |
| public void addUnique(E object) { |
| synchronized(lock) { |
| super.addUnique(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addUnique(int, java.lang.Object) |
| */ |
| @Override |
| public void addUnique(int index, E object) { |
| synchronized(lock) { |
| super.addUnique(index, object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addAllUnique(java.util.Collection) |
| */ |
| @Override |
| public boolean addAllUnique(Collection<? extends E> collection) { |
| synchronized(lock) { |
| return super.addAllUnique(collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addAllUnique(int, java.util.Collection) |
| */ |
| @Override |
| public boolean addAllUnique(int index, Collection<? extends E> collection) { |
| synchronized(lock) { |
| return super.addAllUnique(index, collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addAllUnique(java.lang.Object[], int, |
| * int) |
| */ |
| @Override |
| public boolean addAllUnique(Object[] objects, int start, int end) { |
| synchronized(lock) { |
| return super.addAllUnique(objects, start, end); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#addAllUnique(int, java.lang.Object[], |
| * int, int) |
| */ |
| @Override |
| public boolean addAllUnique(int index, Object[] objects, int start, int end) { |
| synchronized(lock) { |
| return super.addAllUnique(index, objects, start, end); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#basicAdd(java.lang.Object, |
| * org.eclipse.emf.common.notify.NotificationChain) |
| */ |
| @Override |
| public NotificationChain basicAdd(E object, NotificationChain notifications) { |
| synchronized(lock) { |
| return super.basicAdd(object, notifications); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#remove(int) |
| */ |
| @Override |
| public E remove(int index) { |
| synchronized(lock) { |
| return super.remove(index); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#removeAll(java.util.Collection) |
| */ |
| @Override |
| public boolean removeAll(Collection<?> collection) { |
| synchronized(lock) { |
| return super.removeAll(collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#basicRemove(java.lang.Object, |
| * org.eclipse.emf.common.notify.NotificationChain) |
| */ |
| @Override |
| public NotificationChain basicRemove(Object object, NotificationChain notifications) { |
| synchronized(lock) { |
| return super.basicRemove(object, notifications); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#clear() |
| */ |
| @Override |
| public void clear() { |
| synchronized(lock) { |
| super.clear(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#setUnique(int, java.lang.Object) |
| */ |
| @Override |
| public E setUnique(int index, E object) { |
| synchronized(lock) { |
| return super.setUnique(index, object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#basicSet(int, java.lang.Object, |
| * org.eclipse.emf.common.notify.NotificationChain) |
| */ |
| @Override |
| public NotificationChain basicSet(int index, E object, NotificationChain notifications) { |
| synchronized(lock) { |
| return super.basicSet(index, object, notifications); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#move(int, int) |
| */ |
| @Override |
| public E move(int targetIndex, int sourceIndex) { |
| synchronized(lock) { |
| return super.move(targetIndex, sourceIndex); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicList() |
| */ |
| @Override |
| public List<E> basicList() { |
| synchronized(lock) { |
| return super.basicList(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicIterator() |
| */ |
| @Override |
| public Iterator<E> basicIterator() { |
| return new SynchronizedNonResolvingEIterator(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicListIterator() |
| */ |
| @Override |
| public ListIterator<E> basicListIterator() { |
| return new SynchronizedNonResolvingEListIterator(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicListIterator(int) |
| */ |
| @Override |
| public ListIterator<E> basicListIterator(int index) { |
| synchronized(lock) { |
| int curSize = size(); |
| if (index < 0 || index > curSize) { |
| throw new BasicIndexOutOfBoundsException(index, curSize); |
| } |
| return new SynchronizedNonResolvingEListIterator(index); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.ResourcesEList#contains(java.lang.Object) |
| */ |
| @Override |
| public boolean contains(Object object) { |
| synchronized(lock) { |
| return super.contains(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicContains(java.lang.Object) |
| */ |
| @Override |
| public boolean basicContains(Object object) { |
| synchronized(lock) { |
| return super.basicContains(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicContainsAll(java.util.Collection) |
| */ |
| @Override |
| public boolean basicContainsAll(Collection<?> collection) { |
| synchronized(lock) { |
| return super.basicContainsAll(collection); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicIndexOf(java.lang.Object) |
| */ |
| |
| @Override |
| public int basicIndexOf(Object object) { |
| synchronized(lock) { |
| return super.basicIndexOf(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicLastIndexOf(java.lang.Object) |
| */ |
| @Override |
| public int basicLastIndexOf(Object object) { |
| synchronized(lock) { |
| return super.basicLastIndexOf(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicToArray() |
| */ |
| @Override |
| public Object[] basicToArray() { |
| synchronized(lock) { |
| return super.basicToArray(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicToArray(T[]) |
| */ |
| @Override |
| public <T> T[] basicToArray(T[] array) { |
| synchronized(lock) { |
| return super.basicToArray(array); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#data() |
| */ |
| @Override |
| public Object[] data() { |
| synchronized(lock) { |
| return super.data(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.notify.impl.NotifyingListImpl#getFeature() |
| */ |
| @Override |
| public Object getFeature() { |
| synchronized(lock) { |
| return super.getFeature(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.ResourcesEList#getFeatureID() |
| */ |
| @Override |
| public int getFeatureID() { |
| synchronized(lock) { |
| return super.getFeatureID(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.ecore.resource.impl.ResourceSetImpl.ResourcesEList#getNotifier() |
| */ |
| @Override |
| public Object getNotifier() { |
| synchronized(lock) { |
| return super.getNotifier(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#isEmpty() |
| */ |
| @Override |
| public boolean isEmpty() { |
| synchronized(lock) { |
| return super.isEmpty(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.BasicEList#size() |
| */ |
| @Override |
| public int size() { |
| synchronized(lock) { |
| return super.size(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.util.AbstractList#subList(int, int) |
| */ |
| @Override |
| public List<E> subList(int fromIndex, int toIndex) { |
| synchronized(lock) { |
| return super.subList(fromIndex, toIndex); |
| } |
| } |
| |
| /** |
| * A synchronized implementation of the {@link AbstractEList.EIterator}. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| private class SynchronizedEIterator extends AbstractEList<E>.EIterator<E> { |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#hasNext() |
| */ |
| @Override |
| public boolean hasNext() { |
| synchronized(lock) { |
| return super.hasNext(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#next() |
| */ |
| @Override |
| public E next() { |
| synchronized(lock) { |
| return super.next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#remove() |
| */ |
| @Override |
| public void remove() { |
| synchronized(lock) { |
| super.remove(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| synchronized(lock) { |
| return super.equals(obj); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| synchronized(lock) { |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| synchronized(lock) { |
| return super.toString(); |
| } |
| } |
| } |
| |
| /** |
| * A synchronized implementation of the {@link AbstractEList.EListIterator}. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| private class SynchronizedEListIterator extends AbstractEList<E>.EListIterator<E> { |
| /** |
| * Delegates to the super constructor. |
| */ |
| public SynchronizedEListIterator() { |
| super(); |
| } |
| |
| /** |
| * Delegates to the super constructor. |
| * |
| * @param index |
| * Index at which this list iterator should start. |
| */ |
| public SynchronizedEListIterator(int index) { |
| super(index); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#add(java.lang.Object) |
| */ |
| @Override |
| public void add(E object) { |
| synchronized(lock) { |
| super.add(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#hasNext() |
| */ |
| @Override |
| public boolean hasNext() { |
| synchronized(lock) { |
| return super.hasNext(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#hasPrevious() |
| */ |
| @Override |
| public boolean hasPrevious() { |
| synchronized(lock) { |
| return super.hasPrevious(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#next() |
| */ |
| @Override |
| public E next() { |
| synchronized(lock) { |
| return super.next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#previous() |
| */ |
| @Override |
| public E previous() { |
| synchronized(lock) { |
| return super.previous(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#previousIndex() |
| */ |
| @Override |
| public int previousIndex() { |
| synchronized(lock) { |
| return super.previousIndex(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#remove() |
| */ |
| @Override |
| public void remove() { |
| synchronized(lock) { |
| super.remove(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#set(java.lang.Object) |
| */ |
| @Override |
| public void set(E object) { |
| synchronized(lock) { |
| super.set(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| synchronized(lock) { |
| return super.equals(obj); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| synchronized(lock) { |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| synchronized(lock) { |
| return super.toString(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#nextIndex() |
| */ |
| @Override |
| public int nextIndex() { |
| synchronized(lock) { |
| return super.nextIndex(); |
| } |
| } |
| } |
| |
| /** |
| * A synchronized implementation of the {@link AbstractEList.NonResolvingEIterator}. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| private class SynchronizedNonResolvingEIterator extends AbstractEList<E>.NonResolvingEIterator<E> { |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#hasNext() |
| */ |
| @Override |
| public boolean hasNext() { |
| synchronized(lock) { |
| return super.hasNext(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#next() |
| */ |
| @Override |
| public E next() { |
| synchronized(lock) { |
| return super.next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.NonResolvingEIterator#remove() |
| */ |
| @Override |
| public void remove() { |
| synchronized(lock) { |
| super.remove(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| synchronized(lock) { |
| return super.equals(obj); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| synchronized(lock) { |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| synchronized(lock) { |
| return super.toString(); |
| } |
| } |
| } |
| |
| /** |
| * A synchronized implementation of the {@link AbstractEList.NonResolvingEListIterator}. |
| * |
| * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> |
| */ |
| private class SynchronizedNonResolvingEListIterator extends AbstractEList<E>.NonResolvingEListIterator<E> { |
| /** |
| * Delegates to the super constructor. |
| */ |
| public SynchronizedNonResolvingEListIterator() { |
| super(); |
| } |
| |
| /** |
| * Delegates to the super constructor. |
| * |
| * @param index |
| * Index at which the iteration should start. |
| */ |
| public SynchronizedNonResolvingEListIterator(int index) { |
| super(index); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.NonResolvingEListIterator#add(java.lang.Object) |
| */ |
| @Override |
| public void add(E object) { |
| synchronized(lock) { |
| super.add(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#hasNext() |
| */ |
| @Override |
| public boolean hasNext() { |
| synchronized(lock) { |
| return super.hasNext(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#hasPrevious() |
| */ |
| @Override |
| public boolean hasPrevious() { |
| synchronized(lock) { |
| return super.hasPrevious(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EIterator#next() |
| */ |
| @Override |
| public E next() { |
| synchronized(lock) { |
| return super.next(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#previous() |
| */ |
| @Override |
| public E previous() { |
| synchronized(lock) { |
| return super.previous(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#previousIndex() |
| */ |
| @Override |
| public int previousIndex() { |
| synchronized(lock) { |
| return super.previousIndex(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.NonResolvingEListIterator#remove() |
| */ |
| @Override |
| public void remove() { |
| synchronized(lock) { |
| super.remove(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.NonResolvingEListIterator#set(java.lang.Object) |
| */ |
| @Override |
| public void set(E object) { |
| synchronized(lock) { |
| super.set(object); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| synchronized(lock) { |
| return super.equals(obj); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| synchronized(lock) { |
| return super.hashCode(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| synchronized(lock) { |
| return super.toString(); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.emf.common.util.AbstractEList.EListIterator#nextIndex() |
| */ |
| @Override |
| public int nextIndex() { |
| synchronized(lock) { |
| return super.nextIndex(); |
| } |
| } |
| } |
| } |
| } |