blob: 244930695927bf9f71db6b9295e0e4adf6b9b2ce [file] [log] [blame]
/*******************************************************************************
* 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();
}
}
}
}
}