[544413] Eliminated the effect of file number on proxy resolution

Change-Id: I83b79eb489bf7a5ebbb2d7bc95afb4ec7fe452fb
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/metamodel/MetaModelDescriptorRegistry.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/metamodel/MetaModelDescriptorRegistry.java
index c66febc..0a5eb72 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/metamodel/MetaModelDescriptorRegistry.java
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/metamodel/MetaModelDescriptorRegistry.java
@@ -1,1516 +1,1533 @@
-/**

- * <copyright>

- *

- * Copyright (c) 2008-2014 BMW Car IT, See4sys, itemis and others.

- * All rights reserved. This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License v1.0

- * which accompanies this distribution, and is available at

- * http://www.eclipse.org/legal/epl-v10.html

- *

- * Contributors:

- *     BMW Car IT - Initial API and implementation

- *     See4sys - Added support for EPackage URIs

- *     BMW Car IT - Added robustness and support for singleton instantiation of descriptors

- *     See4sys - Added facilities for retrieving descriptor(s) from identifier, name, ordinal, object, etc.

- *     itemis - [346715] IMetaModelDescriptor methods of MetaModelDescriptorRegistry taking EObject or Resource arguments should not start new EMF transactions

- *     itemis - [348544] OMG XMI files with embedded model content are not recognized as model files

- *     itemis - [348820] Performance-optimized content type detection in MetaModelDescriptorRegistry ignores file extensions

- *     Conti  - [349675] Performance improvements of MetaModelDescriptorRegistry

- *     BMW Car IT - [373481] Performance optimizations for model loading

- *     BMW Car IT - Lazy extension initialization

- *     itemis - [409367] Add a custom URI scheme to metamodel descriptor allowing mapping URI scheme to metamodel descriptor

- *     itemis - [418005] Add support for model files with multiple root elements

- *     itemis - [422334] Content-type based IMetaModelDescriptor determination for a file gets corrupted if file extension is associated to org.eclipse.emf.compare.ui.contenttype.ModelContentType

- *     itemis - [442342] Sphinx doen't trim context information from proxy URIs when serializing proxyfied cross-document references

- *

- * </copyright>

- */

-package org.eclipse.sphinx.emf.metamodel;

-

-import java.net.URI;

-import java.net.URISyntaxException;

-import java.util.ArrayList;

-import java.util.Arrays;

-import java.util.Collection;

-import java.util.Collections;

-import java.util.Comparator;

-import java.util.HashMap;

-import java.util.HashSet;

-import java.util.LinkedHashMap;

-import java.util.List;

-import java.util.Map;

-import java.util.Set;

-import java.util.regex.Pattern;

-

-import org.eclipse.core.internal.content.ContentType;

-import org.eclipse.core.internal.content.ContentTypeHandler;

-import org.eclipse.core.resources.IFile;

-import org.eclipse.core.resources.IResource;

-import org.eclipse.core.runtime.Assert;

-import org.eclipse.core.runtime.CoreException;

-import org.eclipse.core.runtime.IAdaptable;

-import org.eclipse.core.runtime.IConfigurationElement;

-import org.eclipse.core.runtime.IExtension;

-import org.eclipse.core.runtime.IExtensionRegistry;

-import org.eclipse.core.runtime.Platform;

-import org.eclipse.core.runtime.content.IContentDescriber;

-import org.eclipse.core.runtime.content.IContentType;

-import org.eclipse.core.runtime.content.IContentTypeSettings;

-import org.eclipse.emf.common.notify.Notifier;

-import org.eclipse.emf.common.util.EList;

-import org.eclipse.emf.ecore.EClass;

-import org.eclipse.emf.ecore.EClassifier;

-import org.eclipse.emf.ecore.EObject;

-import org.eclipse.emf.ecore.EPackage;

-import org.eclipse.emf.ecore.InternalEObject;

-import org.eclipse.emf.ecore.resource.ContentHandler;

-import org.eclipse.emf.ecore.resource.Resource;

-import org.eclipse.emf.ecore.util.FeatureMap;

-import org.eclipse.emf.ecore.xmi.impl.RootXMLContentHandlerImpl;

-import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;

-import org.eclipse.emf.edit.provider.IWrapperItemProvider;

-import org.eclipse.osgi.util.NLS;

-import org.eclipse.sphinx.emf.Activator;

-import org.eclipse.sphinx.emf.edit.TransientItemProvider;

-import org.eclipse.sphinx.emf.internal.messages.Messages;

-import org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache;

-import org.eclipse.sphinx.emf.scoping.ResourceScopeProviderRegistry;

-import org.eclipse.sphinx.emf.util.EcorePlatformUtil;

-import org.eclipse.sphinx.emf.util.EcoreResourceUtil;

-import org.eclipse.sphinx.platform.IExtendedPlatformConstants;

-import org.eclipse.sphinx.platform.util.ExtendedPlatform;

-import org.eclipse.sphinx.platform.util.PlatformLogUtil;

-import org.eclipse.sphinx.platform.util.ReflectUtil;

-

-@SuppressWarnings("restriction")

-public class MetaModelDescriptorRegistry implements IAdaptable {

-

-	/**

-	 * The singleton instance of this registry.

-	 */

-	public static final MetaModelDescriptorRegistry INSTANCE = new MetaModelDescriptorRegistry();

-

-	/**

-	 * A default meta-model descriptor for any type of meta model.

-	 */

-	public static final IMetaModelDescriptor ANY_MM = new AnyMetaModelDescriptor();

-

-	/**

-	 * A default meta-model descriptor for no meta model.

-	 */

-	public static final IMetaModelDescriptor NO_MM = new NoMetaModelDescriptor();

-

-	/*

-	 * Extension point related constants

-	 */

-	private static final String EXTP_META_MODEL_DESCRIPTORS = "org.eclipse.sphinx.emf.metaModelDescriptors"; //$NON-NLS-1$

-	private static final String NODE_DESCRIPTOR = "descriptor"; //$NON-NLS-1$

-	private static final String NODE_CONTENT_TYPE_ASSOCIATION = "contentTypeAssociation"; //$NON-NLS-1$

-	private static final String NODE_TARGET_DESCRIPTOR = "targetDescriptorProvider";//$NON-NLS-1$

-	private static final String NODE_CONTENT_TYPE = "contentType";//$NON-NLS-1$

-	private static final String NODE_FILE_TYPE = "fileType";//$NON-NLS-1$

-	private static final String ATTR_ID = "id"; //$NON-NLS-1$

-	private static final String ATTR_EXTENSION = "extension";//$NON-NLS-1$

-	private static final String ATTR_CLASS = "class"; //$NON-NLS-1$

-	private static final String ATTR_OVERRIDE = "override";//$NON-NLS-1$

-	private static final String ATTR_METAMODEL_DESCRIPTOR_ID = "metaModelDescriptorId"; //$NON-NLS-1$

-	private static final String ATTR_CONTENT_TYPE_ID = "contentTypeId"; //$NON-NLS-1$

-

-	/**

-	 * The namespace pattern for OMG-defined XMI formats.

-	 */

-	private static final Pattern OMG_XMI_NAMESPACE_PATTERN = Pattern.compile("http://(schema|www)\\.omg\\.org(/spec)?/XMI.*"); //$NON-NLS-1$

-

-	/**

-	 * The if of the special content type defined by EMF Compare used to identify files that are to be opened in EMF

-	 * Compare editor.

-	 */

-	private static final String EMF_COMPARE_CONTENT_TYPE_ID = "org.eclipse.emf.compare.ui.contenttype.ModelContentType"; //$NON-NLS-1$

-

-	/**

-	 * The extension registry.

-	 */

-	private IExtensionRegistry fExtensionRegistry;

-

-	/**

-	 * Flag to track lazy initialization.

-	 */

-	private boolean isInitialized = false;

-

-	/**

-	 * The contributed meta-model descriptors.

-	 */

-	private final Map<String, IMetaModelDescriptor> fMetaModelDescriptors = Collections

-			.synchronizedMap(new LinkedHashMap<String, IMetaModelDescriptor>());

-

-	/**

-	 * The contributed target meta-model descriptor providers.

-	 */

-	private final Map<String, ITargetMetaModelDescriptorProvider> fContentTypeIdToTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();

-

-	private final Map<String, ITargetMetaModelDescriptorProvider> fFileExtensionToTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();

-

-	private final Map<String, ITargetMetaModelDescriptorProvider> fAllTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();

-

-	private final FileMetaModelDescriptorCache fFileMetaModelDescriptorCache = new FileMetaModelDescriptorCache();

-

-	private final Map<String, String> fContentTypeIdCache = new HashMap<String, String>();

-

-	private final Map<EPackage, IMetaModelDescriptor> fPackageMetaModelDescriptorCache = new HashMap<EPackage, IMetaModelDescriptor>();

-

-	/**

-	 * Private constructor for the singleton pattern.

-	 */

-	private MetaModelDescriptorRegistry() {

-	}

-

-	private IExtensionRegistry getExtensionRegistry() {

-		if (fExtensionRegistry == null) {

-			fExtensionRegistry = Platform.getExtensionRegistry();

-		}

-		return fExtensionRegistry;

-	}

-

-	// FIXME Should be entirely removed as soon as integration tests will be available.

-	// Only used for testing

-	public void setExtensionRegistry(IExtensionRegistry extensionRegistry) {

-		fExtensionRegistry = extensionRegistry;

-		isInitialized = true;

-		getMetaModelDescriptors().clear();

-		getContentTypeIdToTargetMetaModelDescriptorProviders().clear();

-		getFileExtensionToTargetMetaModelDescriptorProviders().clear();

-		getAllTargetMetaModelDescriptorProviders().clear();

-		isInitialized = false;

-	}

-

-	/**

-	 * Reads contributions to <em>Meta-Model Descriptor</em> extension point.

-	 * <p>

-	 * <table>

-	 * <tr valign=top> <td><b>Note</b>&nbsp;&nbsp;</td> <td>It is recommended to call this method inside a block

-	 * <tt><b>synchronized</b></tt> on the encapsulated <code>fMetaModelDescriptors</code> field in order to avoid

-	 * inconsistencies in registered meta-model {@linkplain IMetaModelDescriptor descriptor}s in case of concurrent

-	 * read/adds.</td> </tr> </table>

-	 */

-	private void readContributedDescriptors() {

-		IExtensionRegistry extensionRegistry = getExtensionRegistry();

-		if (extensionRegistry != null) {

-			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();

-			for (IExtension extension : extensions) {

-				IConfigurationElement[] configElements = extension.getConfigurationElements();

-				for (IConfigurationElement configElement : configElements) {

-					try {

-						if (NODE_DESCRIPTOR.equals(configElement.getName())) {

-							String id = configElement.getAttribute(ATTR_ID);

-							IMetaModelDescriptor mmDescriptor = null;

-							try {

-								String className = configElement.getAttribute(ATTR_CLASS);

-								Class<?> clazz = Platform.getBundle(configElement.getContributor().getName()).loadClass(className);

-								mmDescriptor = (IMetaModelDescriptor) ReflectUtil.getFieldValue(clazz, "INSTANCE"); //$NON-NLS-1$

-							} catch (ClassNotFoundException e) {

-								PlatformLogUtil.logAsError(Activator.getPlugin(), e);

-							} catch (IllegalAccessException e) {

-								PlatformLogUtil.logAsError(Activator.getPlugin(), e);

-							} catch (NoSuchFieldException noSuchFieldEx) {

-								PlatformLogUtil.logAsInfo(Activator.getPlugin(), noSuchFieldEx);

-								mmDescriptor = (IMetaModelDescriptor) configElement.createExecutableExtension(ATTR_CLASS);

-							}

-							if (!id.equals(mmDescriptor.getIdentifier())) {

-								throw new RuntimeException(NLS.bind(Messages.error_mmDescriptorIdentifierNotEqual, id, mmDescriptor.getIdentifier()));

-							}

-							addDescriptor(mmDescriptor);

-						}

-					} catch (Exception ex) {

-						PlatformLogUtil.logAsError(Activator.getDefault(), ex);

-					}

-				}

-			}

-		}

-	}

-

-	/**

-	 * Reads contributions to <em>Associated Content Type</em> of <em>Meta-Model Descriptor</em> extension point.

-	 */

-	private void readAssociatedContentTypeIds() {

-		IExtensionRegistry extensionRegistry = getExtensionRegistry();

-		if (extensionRegistry != null) {

-			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();

-			for (IExtension extension : extensions) {

-				IConfigurationElement[] configElements = extension.getConfigurationElements();

-				for (IConfigurationElement configElement : configElements) {

-					try {

-						if (NODE_CONTENT_TYPE_ASSOCIATION.equals(configElement.getName())) {

-							String mmDescriptorId = configElement.getAttribute(ATTR_METAMODEL_DESCRIPTOR_ID);

-							String contentTypeId = configElement.getAttribute(ATTR_CONTENT_TYPE_ID);

-							IMetaModelDescriptor mmDescriptor = getDescriptor(mmDescriptorId);

-							mmDescriptor.addAssociatedContentTypeId(contentTypeId);

-						}

-					} catch (Exception ex) {

-						PlatformLogUtil.logAsError(Activator.getDefault(), ex);

-					}

-				}

-			}

-		}

-	}

-

-	protected IMetaModelDescriptor createDescriptor(EPackage ePackage) {

-		Assert.isNotNull(ePackage);

-

-		String ePackageClassName = ePackage.getClass().getName();

-		String id = ePackageClassName.substring(0, ePackageClassName.lastIndexOf(".")); //$NON-NLS-1$

-		if (id.endsWith(".impl") || id.endsWith(".util")) {//$NON-NLS-1$ //$NON-NLS-2$

-			id = id.substring(0, id.lastIndexOf(".")); //$NON-NLS-1$

-		}

-

-		return new DefaultMetaModelDescriptor(id, ePackage.getNsURI(), ePackage.getName());

-	}

-

-	/**

-	 * Add the specified {@link IMetaModelDescriptor mmDescriptor} to this registry (if not already added).

-	 *

-	 * @param mmDescriptor

-	 *            The meta-model {@linkplain IMetaModelDescriptor descriptor} to add to this registry.

-	 */

-	public void addDescriptor(IMetaModelDescriptor mmDescriptor) {

-		if (mmDescriptor != null && !mmDescriptor.equals(ANY_MM) && !mmDescriptor.equals(NO_MM)) {

-			String id = mmDescriptor.getIdentifier();

-			if (id == null) {

-				PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-						new RuntimeException(NLS.bind(Messages.warning_mmDescriptorHasNoIdentifier, mmDescriptor.getName())));

-			}

-			if (getMetaModelDescriptors().containsKey(id)) {

-				PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-						new RuntimeException(NLS.bind(Messages.warning_mmDescriptorIdentifierNotUnique, id)));

-			}

-			getMetaModelDescriptors().put(id, mmDescriptor);

-		}

-	}

-

-	/**

-	 * Reads contributions to <em>Meta-Model Descriptor/TargetMetaModelDescriptorProvider</em> extension point.

-	 */

-	private void readContributedTargetMetaModelDescriptorProviders() {

-		IExtensionRegistry extensionRegistry = getExtensionRegistry();

-		if (extensionRegistry != null) {

-			Set<String> overriddenIds = new HashSet<String>();

-			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();

-			for (IExtension extension : extensions) {

-				IConfigurationElement[] configElements = extension.getConfigurationElements();

-				overriddenIds.addAll(getOverriddenTargetMetaModelDescriptorProviderIds(configElements));

-			}

-			for (IExtension extension : extensions) {

-				IConfigurationElement[] configElements = extension.getConfigurationElements();

-				readContributedTargetMetaModelDescriptorProviders(configElements, overriddenIds);

-			}

-		}

-	}

-

-	private void readContributedTargetMetaModelDescriptorProviders(IConfigurationElement[] configElements, Set<String> overriddenIds) {

-		Assert.isNotNull(configElements);

-		Assert.isNotNull(overriddenIds);

-

-		for (IConfigurationElement configElement : configElements) {

-			try {

-				if (NODE_TARGET_DESCRIPTOR.equals(configElement.getName())) {

-					String id = configElement.getAttribute(ATTR_ID);

-					if (!overriddenIds.contains(id)) {

-						ITargetMetaModelDescriptorProvider provider = (ITargetMetaModelDescriptorProvider) configElement

-								.createExecutableExtension(ATTR_CLASS);

-						if (addTargetDescriptorProvider(id, provider)) {

-							for (IConfigurationElement childConfigElement : configElement.getChildren()) {

-								if (NODE_CONTENT_TYPE.equals(childConfigElement.getName())) {

-									String contenTypeId = childConfigElement.getAttribute(ATTR_ID);

-									addTargetDescriptorProviderForContentTypeId(contenTypeId, provider);

-								} else if (NODE_FILE_TYPE.equals(childConfigElement.getName())) {

-									String fileExtension = childConfigElement.getAttribute(ATTR_EXTENSION);

-									addTargetDescriptorProviderForFileExtension(fileExtension, provider);

-								}

-							}

-						}

-					}

-				}

-			} catch (Exception ex) {

-				PlatformLogUtil.logAsError(Activator.getDefault(), ex);

-			}

-		}

-	}

-

-	private Set<String> getOverriddenTargetMetaModelDescriptorProviderIds(IConfigurationElement[] configElements) {

-		Assert.isNotNull(configElements);

-

-		Set<String> overriddenIds = new HashSet<String>();

-		for (IConfigurationElement configElement : configElements) {

-			if (NODE_TARGET_DESCRIPTOR.equals(configElement.getName())) {

-				String overriddenTargetMetaModelDescriptorId = configElement.getAttribute(ATTR_OVERRIDE);

-				if (overriddenTargetMetaModelDescriptorId != null) {

-					if (!overriddenIds.contains(overriddenTargetMetaModelDescriptorId)) {

-						overriddenIds.add(overriddenTargetMetaModelDescriptorId);

-					} else {

-						PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(NLS

-								.bind(Messages.warning_multipleTargetMetaModelDescriptorProvidersOverride, overriddenTargetMetaModelDescriptorId)));

-					}

-				}

-			}

-		}

-		return overriddenIds;

-	}

-

-	private boolean addTargetDescriptorProvider(String id, ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {

-		Assert.isNotNull(targetMetaModelDescriptorProvider);

-

-		if (id == null) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(Messages.warning_targetMetaModelDescriptorProviderWithoutId));

-			return false;

-		}

-		if (getAllTargetMetaModelDescriptorProviders().containsKey(id)) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-					new RuntimeException(NLS.bind(Messages.warning_targetMetaModelDescriptorProviderIdNotUnique, id)));

-			return false;

-		}

-

-		getAllTargetMetaModelDescriptorProviders().put(id, targetMetaModelDescriptorProvider);

-		return true;

-	}

-

-	private void addTargetDescriptorProviderForFileExtension(String fileExtension,

-			ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {

-		Assert.isNotNull(targetMetaModelDescriptorProvider);

-		Assert.isLegal(getAllTargetMetaModelDescriptorProviders().containsValue(targetMetaModelDescriptorProvider));

-

-		if (fileExtension == null) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-					new RuntimeException(NLS.bind(Messages.warning_fileExtensionForTargetMetaModelDescriptorProviderMustNotBeNull, fileExtension)));

-		}

-		if (getFileExtensionToTargetMetaModelDescriptorProviders().containsKey(fileExtension)) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-					new RuntimeException(NLS.bind(Messages.warning_fileExtensionForTargetMetaModelDescriptorProviderNotUnique, fileExtension)));

-		}

-

-		getFileExtensionToTargetMetaModelDescriptorProviders().put(fileExtension, targetMetaModelDescriptorProvider);

-	}

-

-	private void addTargetDescriptorProviderForContentTypeId(String contentTypeId,

-			ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {

-		Assert.isNotNull(targetMetaModelDescriptorProvider);

-		Assert.isLegal(getAllTargetMetaModelDescriptorProviders().containsValue(targetMetaModelDescriptorProvider));

-

-		if (contentTypeId == null) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-					new RuntimeException(NLS.bind(Messages.warning_contentTypeIdForTargetMetaModelDescriptorProviderMustNotBeNull, contentTypeId)));

-

-		}

-		if (getContentTypeIdToTargetMetaModelDescriptorProviders().containsKey(contentTypeId)) {

-			PlatformLogUtil.logAsWarning(Activator.getPlugin(),

-					new RuntimeException(NLS.bind(Messages.warning_contentTypeIdForTargetMetaModelDescriptorProviderNotUnique, contentTypeId)));

-		}

-

-		getContentTypeIdToTargetMetaModelDescriptorProviders().put(contentTypeId, targetMetaModelDescriptorProvider);

-	}

-

-	/*

-	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)

-	 */

-	@Override

-	public Object getAdapter(@SuppressWarnings("rawtypes") Class adapterType) {

-		if (adapterType.equals(IFileMetaModelDescriptorCache.class)) {

-			return fFileMetaModelDescriptorCache;

-		}

-		return null;

-	}

-

-	/**

-	 * @param mmDescriptor

-	 * @return

-	 */

-	public List<IMetaModelDescriptor> getResolvedDescriptors(IMetaModelDescriptor mmDescriptor) {

-		List<IMetaModelDescriptor> resolvedDescriptors = new ArrayList<IMetaModelDescriptor>();

-		for (IMetaModelDescriptor descriptor : getDescriptors(mmDescriptor)) {

-			if (descriptor.getRootEPackage() != null) {

-				resolvedDescriptors.add(descriptor);

-			}

-		}

-		return resolvedDescriptors;

-	}

-

-	public IMetaModelDescriptor getDescriptor(Object object) {

-		if (object instanceof String) {

-			return getDescriptor((String) object);

-		} else if (object instanceof URI) {

-			return getDescriptor((URI) object);

-		} else if (object instanceof IFile) {

-			return getDescriptor((IFile) object);

-		} else if (object instanceof Resource) {

-			return getDescriptor((Resource) object);

-		} else if (object instanceof EObject) {

-			return getDescriptor((EObject) object);

-		} else if (object instanceof IWrapperItemProvider) {

-			return getDescriptor((IWrapperItemProvider) object);

-		} else if (object instanceof FeatureMap.Entry) {

-			return getDescriptor((FeatureMap.Entry) object);

-		} else if (object instanceof TransientItemProvider) {

-			return getDescriptor((TransientItemProvider) object);

-		} else if (object instanceof EClass) {

-			return getDescriptor((EClass) object);

-		} else if (object instanceof EPackage) {

-			return getDescriptor((EPackage) object);

-		}

-		return null;

-	}

-

-	/**

-	 * Used in UI component to return a list of sorted descriptors.

-	 *

-	 * @param mmDescriptor

-	 * @return

-	 * @since 0.7.0

-	 */

-	public <T extends IMetaModelDescriptor> List<T> getDescriptors(T mmDescriptor, boolean sorted) {

-		List<T> descriptors = new ArrayList<T>();

-		if (mmDescriptor != null) {

-			synchronized (getMetaModelDescriptors()) {

-				for (IMetaModelDescriptor descriptor : getMetaModelDescriptors().values()) {

-					if (mmDescriptor == ANY_MM || mmDescriptor.getClass().isInstance(descriptor)) {

-						@SuppressWarnings("unchecked")

-						T desc = (T) descriptor;

-						descriptors.add(desc);

-					}

-				}

-			}

-		}

-		if (sorted) {

-			Collections.sort(descriptors, new Comparator<T>() {

-				@Override

-				public int compare(IMetaModelDescriptor mmd1, IMetaModelDescriptor mmd2) {

-					String label1 = String.format(IMetaModelDescriptor.LABEL_PATTERN, mmd1.getName(), mmd1.getNamespace());

-					String label2 = String.format(IMetaModelDescriptor.LABEL_PATTERN, mmd2.getName(), mmd2.getNamespace());

-					return label1.compareTo(label2);

-				}

-			});

-		}

-		return descriptors;

-	}

-

-	/**

-	 * @param mmDescriptor

-	 * @return

-	 */

-	public <T extends IMetaModelDescriptor> List<T> getDescriptors(T mmDescriptor) {

-		return getDescriptors(mmDescriptor, false);

-	}

-

-	/**

-	 * @param identifier

-	 *            A meta-model descriptor identifier.

-	 * @return The meta-model descriptor contributed with the specified identifier.

-	 */

-	public IMetaModelDescriptor getDescriptor(String identifier) {

-		if (ANY_MM.getIdentifier().equals(identifier)) {

-			return ANY_MM;

-		}

-		return getMetaModelDescriptors().get(identifier);

-	}

-

-	/**

-	 * @param idPattern

-	 *            A regular expression which the identifiers of the returned meta-model descriptors must match.

-	 * @return Meta-model descriptors whose identifier matches the specified regular expression.

-	 */

-	public List<IMetaModelDescriptor> getDescriptors(String idPattern) {

-		if (ANY_MM.getIdentifier().equals(idPattern)) {

-			return Collections.singletonList(ANY_MM);

-		}

-

-		List<IMetaModelDescriptor> mmDescriptors = new ArrayList<IMetaModelDescriptor>();

-		if (idPattern != null) {

-			Pattern pattern = Pattern.compile(idPattern);

-			synchronized (getMetaModelDescriptors()) {

-				for (Map.Entry<String, IMetaModelDescriptor> entry : getMetaModelDescriptors().entrySet()) {

-					if (pattern.matcher(entry.getKey()).matches()) {

-						mmDescriptors.add(entry.getValue());

-					}

-				}

-			}

-		}

-		return mmDescriptors;

-	}

-

-	/**

-	 * Returns the {@link IMetaModelDescriptor descriptors} of all meta-models that use URIs with given

-	 * <code>customURIScheme</code> in cross-document references and as proxy URIs.

-	 *

-	 * @param scheme

-	 *            The custom URI scheme for which the descriptors of the meta-model using it is to be returned.

-	 * @return The descriptors of the meta-models using specified <code>customURIScheme</code>.

-	 */

-	public List<IMetaModelDescriptor> getDescriptorsFromURIScheme(String scheme) {

-		List<IMetaModelDescriptor> mmDescriptors = new ArrayList<IMetaModelDescriptor>();

-		if (scheme != null) {

-			synchronized (getMetaModelDescriptors()) {

-				for (IMetaModelDescriptor mmDescriptor : getMetaModelDescriptors().values()) {

-					if (mmDescriptor.getCustomURIScheme() != null) {

-						if (mmDescriptor.getCustomURIScheme().equals(scheme)) {

-							mmDescriptors.add(mmDescriptor);

-						}

-					}

-				}

-			}

-		}

-		return mmDescriptors;

-	}

-

-	/**

-	 * @param mmDescriptor

-	 * @param ordinal

-	 * @return

-	 * @deprecated see {@link MetaModelVersionData#getOrdinal()}

-	 */

-	@Deprecated

-	public <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, final int ordinal) {

-		return getDescriptor(mmDescriptor, new IDescriptorFilter() {

-			@Override

-			public boolean accept(IMetaModelDescriptor descriptor) {

-				return descriptor.getOrdinal() == ordinal;

-			}

-		});

-	}

-

-	/**

-	 * @param mmDescriptor

-	 * @param name

-	 * @return

-	 */

-	public <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, final String name) {

-		return getDescriptor(mmDescriptor, new IDescriptorFilter() {

-			@Override

-			public boolean accept(IMetaModelDescriptor descriptor) {

-				return descriptor.getName().equals(name);

-			}

-		});

-	}

-

-	/**

-	 * Returns the {@link IMetaModelDescriptor meta-model descriptor} for the given <code>resource</code>.

-	 *

-	 * @param resource

-	 *            The {@link Resource resource} whose meta-model descriptor is to be returned.

-	 * @return The meta-model descriptor of the specified <code>resource</code>.

-	 */

-	public IMetaModelDescriptor getDescriptor(final Resource resource) {

-		/*

-		 * Performance optimization: Theoretically we could just all the time rely on the id of the content type behind

-		 * given file and retrieve the metamodel descriptor from there. However, keeping in mind that content type

-		 * detection is an incredibly slow affair we must not do that but proceed in the following order: For loaded

-		 * resources the fastest option is to retrieve the metamodel descriptor from the nsURI of the EPackage behind

-		 * one of the root objects in the resource. For resources that have just been created but not loaded (and

-		 * therefore no content) yet we try to retrieve the metamodel descriptor from the underlying workspace file so

-		 * as to benefit from metamodel descriptor that potentially has already been cached for the same. At last, we

-		 * rely on the resource's model namespace which enables us to determine the metamodel descriptors of files that

-		 * are not loaded yet and located outside the workspace.

-		 */

-

-		// Try to retrieve descriptor from model root object in given resource (applies to loaded resources)

-		if (resource != null) {

-			EList<EObject> contents = resource.getContents();

-			if (!contents.isEmpty()) {

-				IMetaModelDescriptor mmDescriptor = getDescriptor(contents.get(0));

-				if (mmDescriptor != null) {

-					return mmDescriptor;

-				}

-			}

-		}

-

-		// Try to retrieve descriptor from underlying workspace file (applies to resources that have been

-		// created but not loaded - and therefore no EObject content - yet and are located inside the workspace)

-		IFile file = EcorePlatformUtil.getFile(resource);

-		if (file != null) {

-			return getDescriptor(file);

-		}

-

-		// Try to retrieve descriptor from model namespace of given resource (applies to resources that have been

-		// created but not loaded - and therefore no EObject content - yet and are located outside the workspace)

-		if (resource != null) {

-			String namespace = EcoreResourceUtil.readModelNamespace(resource);

-			if (namespace != null) {

-				// Determine corresponding meta-model descriptor

-				try {

-					return getDescriptor(new URI(namespace));

-				} catch (URISyntaxException ex) {

-					// Ignore exception, just return null

-				}

-			}

-		}

-

-		return null;

-	}

-

-	/**

-	 * Returns the {@link IMetaModelDescriptor meta-model descriptor} for given {@link IFile file}.

-	 *

-	 * @param file

-	 *            The {@link IFile file} whose {@link IMetaModelDescriptor meta-model descriptor} is to be returned.

-	 * @return The {@link IMetaModelDescriptor meta-model descriptor} of given {@link IFile}, or <code>null</code> if no

-	 *         such could be determined.

-	 */

-	public IMetaModelDescriptor getDescriptor(IFile file) {

-		if (file != null) {

-			// Try to retrieve meta-model descriptor from cache

-			if (fFileMetaModelDescriptorCache.hasDescriptor(file)) {

-				return fFileMetaModelDescriptorCache.getDescriptor(file);

-			} else {

-				try {

-					IMetaModelDescriptor mmDescriptor = null;

-

-					// Retrieve content type id of given file

-					final String contentTypeId = fastGetContentTypeId(file);

-

-					if (contentTypeId != null) {

-						// EMF Compare content type encountered?

-						if (EMF_COMPARE_CONTENT_TYPE_ID.equals(contentTypeId)) {

-							// Refer to target metamodel descriptor if any

-							/*

-							 * !! Important Note !! This is a workaround for the fact that EMF Compare has hijacked the

-							 * content type concept for expressing file associations, i.e., to identify which file types

-							 * are to be opened with the EMF Compare editor. As the consequence, the files which yield

-							 * the EMF Compare content type can actually have any content and it becomes impossible to

-							 * determine their real file type based on this content type. To to remedy this defect, we

-							 * enable clients to contribute a target metamodel descriptor provider for the file types in

-							 * question and directly indicate the corresponding metamodel descriptor.

-							 */

-							mmDescriptor = getTargetDescriptor(file);

-						} else {

-							// Determine corresponding meta-model descriptor

-							mmDescriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {

-								@Override

-								public boolean accept(IMetaModelDescriptor descriptor) {

-									if (descriptor.getContentTypeIds().contains(contentTypeId)) {

-										return true;

-									}

-									if (descriptor.getCompatibleContentTypeIds().contains(contentTypeId)) {

-										return true;

-									}

-									return false;

-								}

-							});

-						}

-					}

-

-					// Cache resulting meta-model descriptor

-					if (file.isAccessible()) {

-						fFileMetaModelDescriptorCache.addDescriptor(file, mmDescriptor);

-					}

-

-					return mmDescriptor;

-				} catch (Exception ex) {

-					// Ignore exception, just return null

-				}

-			}

-		}

-		return null;

-	}

-

-	private String fastGetContentTypeId(IFile file) throws CoreException {

-		// Content type id for given file already cached?

-		if (ExtendedPlatform.hasCachedContentTypeId(file)) {

-			// Retrieve content type id of given file normally - we know that it will be quick

-			return ExtendedPlatform.getContentTypeId(file);

-		} else {

-			try {

-				/*

-				 * Performance optimization: Use optimized detection of content type only if there is a realistic chance

-				 * that given file is a model file inside an existing scope. For any other file it would just add some

-				 * useless extra time to the native content type retrieval process.

-				 */

-				if (!ResourceScopeProviderRegistry.INSTANCE.isNotInAnyScope(file)) {

-					/*

-					 * Performance optimization: Try to determine meta-model descriptor from model namespace in given

-					 * file. This works significantly more quickly than retrieving the file's content type and looking

-					 * up the corresponding meta-model descriptor. In case the meta-model descriptor can be found this

-					 * way we go on and try to deduce the file's content type id from the model namespace which we have

-					 * found and cache it for the given file. If successful, this enables us to completely avoid very

-					 * slow native content type detection later on (e.g. during Resource creation in

-					 * ExtendedResourceSetImpl#demandCreateResource(URI)) resulting in a significant acceleration when

-					 * content type dependent operations on many files need to be carried out (e.g. model loading).

-					 */

-					// Try to retrieve model namespace which might be present in given file

-					String namespace = EcorePlatformUtil.readModelNamespace(file);

-

-					// Has a model namespace been found?

-					IMetaModelDescriptor mmDescriptor = null;

-					if (namespace != null) {

-						// Determine corresponding meta-model descriptor

-						mmDescriptor = getDescriptor(new URI(namespace));

-					}

-

-					// Does a matching meta-model descriptor exist?

-					if (mmDescriptor != null) {

-						// Try to retrieve content type id for given model namespace and file extension

-						String contentTypeId = getContentTypeIdFromDescriber(namespace, file.getFileExtension());

-						// Is a matching content type id available?

-						if (contentTypeId != null) {

-							// Cache content type id for given file to accelerate subsequent content type

-							// dependent operations (e.g., ResourceFactory retrieval)

-							ExtendedPlatform.setCachedContentTypeId(file, contentTypeId);

-							return contentTypeId;

-						}

-					} else {

-						/*

-						 * Performance optimization: If the namespace-based retrieval of the meta-model descriptor

-						 * didn't succeed and given file is an XML file that has a namespace then we can be sure that

-						 * the XML file is not a model file. Consequently, we can immediately remember it is such and

-						 * can spare out the lengthy analysis or its content type. The only exception to this rule are

-						 * XML files with OMG XMI content - they yield an OMG-defined XMI namespace rather than the

-						 * model namespace but still may embed model content somewhere inside. In this case we must let

-						 * perform a full content type analysis so as to detect if the OMG XMI file is a model file or

-						 * not.

-						 */

-						if (namespace != null && !OMG_XMI_NAMESPACE_PATTERN.matcher(namespace).matches()) {

-							// Set cached content type id for given file to unspecified to accelerate subsequent

-							// content type dependent operations

-							ExtendedPlatform.setCachedContentTypeId(file, IExtendedPlatformConstants.CONTENT_TYPE_ID_NON_MODEL_XML_FILE);

-							return IExtendedPlatformConstants.CONTENT_TYPE_ID_NON_MODEL_XML_FILE;

-						}

-					}

-				}

-

-				// If we are still here then we have to retrieve the content type id of given file natively - and accept

-				// that it will take time

-				return ExtendedPlatform.getContentTypeId(file);

-			} catch (Exception ex) {

-				// Ignore exception, just return null

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * Returns content type id for given model namespace and file extension in case that an EMF {@link Describer content

-	 * type describer} has been contributed for this model namespace and matches it.

-	 *

-	 * @param namespace

-	 *            The model namespace for which the corresponding content type id is to be determined.

-	 * @param extension

-	 *            The file extension that must be supported by the corresponding content type.

-	 * @return The content type id for given model namespace and file extension, or <code>null</code> if no such could

-	 *         be determined.

-	 */

-	private String getContentTypeIdFromDescriber(String namespace, String extension) {

-		String key = namespace + "@" + extension; //$NON-NLS-1$

-		if (fContentTypeIdCache.containsKey(key)) {

-			return fContentTypeIdCache.get(key);

-		}

-

-		// Scan all registered content types

-		List<String> contentTypeIdCandidates = new ArrayList<String>(2);

-		for (IContentType contentType : Platform.getContentTypeManager().getAllContentTypes()) {

-			try {

-				// Sort out any content type which does not support required file extension

-				if (Arrays.asList(contentType.getFileSpecs(IContentTypeSettings.FILE_EXTENSION_SPEC)).contains(extension)) {

-					// Try to retrieve content type describer which matches model namespace

-					IContentDescriber describer = null;

-					if (contentType instanceof ContentType) {

-						describer = ((ContentType) contentType).getDescriber();

-					} else if (contentType instanceof ContentTypeHandler) {

-						describer = ((ContentTypeHandler) contentType).getTarget().getDescriber();

-					}

-

-					if (describer instanceof RootXMLContentHandlerImpl.Describer) {

-						ContentHandler contentHandler = (ContentHandler) ReflectUtil.getInvisibleFieldValue(describer, "contentHandler"); //$NON-NLS-1$

-						Boolean matching = (Boolean) ReflectUtil.invokeInvisibleMethod(contentHandler, "isMatchingNamespace", namespace); //$NON-NLS-1$

-						if (matching) {

-							// Remember id of matching content type as candidate

-							contentTypeIdCandidates.add(contentType.getId());

-

-							// Exact match?

-							String contentHandlerNamespace = (String) ReflectUtil.getInvisibleFieldValue(contentHandler, "namespace"); //$NON-NLS-1$

-							if (contentHandlerNamespace == null && namespace == null || contentHandlerNamespace != null && namespace != null

-									&& contentHandlerNamespace.length() == namespace.length()) {

-								// No need to look at other conten types

-								break;

-							}

-						}

-					}

-				}

-			} catch (Exception ex) {

-				// Ignore exception, just log it as warning

-				PlatformLogUtil.logAsWarning(Activator.getPlugin(), ex);

-			}

-		}

-

-		// Return best fitting content type id candidate if any

-		String contentTypeId = null;

-		if (contentTypeIdCandidates.size() > 1) {

-			Collections.sort(contentTypeIdCandidates);

-			contentTypeId = contentTypeIdCandidates.get(contentTypeIdCandidates.size() - 1);

-		} else if (contentTypeIdCandidates.size() == 1) {

-			contentTypeId = contentTypeIdCandidates.get(0);

-		}

-

-		fContentTypeIdCache.put(key, contentTypeId);

-		return contentTypeId;

-	}

-

-	/**

-	 * Returns the old {@link IMetaModelDescriptor meta-model descriptor} which given {@link Resource resource} had had

-	 * before is was changed or deleted. !Important note! The information will only be available during processing of

-	 * the method

-	 * org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry.FileMetaModelDescriptorCache.removeDescriptor(IFile)

-	 * called from org.eclipse.sphinx.emf.internal.MetaModelDescriptorCacheAndModelDescriptorRegistryUpdater.

-	 * handleModelResourceUnloaded(Collection<Resource>).In any other use case the method will behave as if there was no

-	 * old meta-model descriptor available. The reason is that old meta-model descriptor is removed as soon as model

-	 * descriptor has been removed.

-	 *

-	 * @param resource

-	 *            The {@link Resource resource} whose old {@link IMetaModelDescriptor meta-model descriptor} is to be

-	 *            returned.

-	 * @return The old {@link IMetaModelDescriptor meta-model descriptor} of given {@link Resource}, or

-	 *         <code>null</code> {@link IFile file} hadn't had any {@link IMetaModelDescriptor meta-model descriptor}

-	 *         before it was changed or deleted.

-	 */

-	public IMetaModelDescriptor getOldDescriptor(Resource resource) {

-		IFile file = EcorePlatformUtil.getFile(resource);

-		return getOldDescriptor(file);

-	}

-

-	/**

-	 * Returns the old {@link IMetaModelDescriptor meta-model descriptor} which given {@link IFile file} had had before

-	 * is was changed or deleted. !Important note! The information will only be available during processing of the

-	 * method

-	 * org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry.FileMetaModelDescriptorCache.removeDescriptor(IFile)

-	 * called from org.eclipse.sphinx.emf.internal.MetaModelDescriptorCacheAndModelDescriptorRegistryUpdater.

-	 * handleModelResourceUnloaded(Collection<Resource>).In any other use case the method will behave as if there was no

-	 * old meta-model descriptor available. The reason is that old meta-model descriptor is removed as soon as model

-	 * descriptor has been removed.

-	 *

-	 * @param file

-	 *            The {@link IFile file} whose old {@link IMetaModelDescriptor meta-model descriptor} is to be returned.

-	 * @return The old {@link IMetaModelDescriptor meta-model descriptor} of given {@link IFile}, or <code>null</code>

-	 *         {@link IFile file} hadn't had any {@link IMetaModelDescriptor meta-model descriptor} before it was

-	 *         changed or deleted.

-	 */

-	public IMetaModelDescriptor getOldDescriptor(IFile file) {

-		return fFileMetaModelDescriptorCache.getOldDescriptor(file);

-	}

-

-	/**

-	 * @param eObject

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(EObject eObject) {

-		if (eObject != null) {

-			// Special handling for proxies representing EObjects of meta-models that extend Ecore (e.g., UML2); instead

-			// of being instances of the respective meta-model classes they may be instances of EClass and have proxy

-			// URIs starting with the namespace URI of the applicable meta-model package

-			if (eObject.eIsProxy() && eObject instanceof EClass) {

-				org.eclipse.emf.common.util.URI proxyURI = ((InternalEObject) eObject).eProxyURI();

-				EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(proxyURI.trimFragment().toString());

-				if (ePackage != null) {

-					return getDescriptor(ePackage);

-				}

-			}

-

-			// Retrieve and return meta-model descriptor from EClass behind given EObject unless it turns out that it is

-			// outdated

-			/*

-			 * !! Important Note !! This is necessary to return an appropriate results for EObjects from model files

-			 * that are in special intermediate states. An example of such an intermediate state is where a model file

-			 * has been deleted but not yet unloaded is requested. Returning the meta-model descriptor corresponding to

-			 * the underlying EClass/EPackage would be wrong because the underlying model file doesn't exist anymore and

-			 * requesting the meta-model descriptor for that file would result in null. We therefore need to detect such

-			 * cases and return the meta-model descriptor corresponding to the underlying model file instead.

-			 */

-			IMetaModelDescriptor descriptor = getDescriptor(eObject.eClass());

-			IMetaModelDescriptor oldDescriptor = getOldDescriptor(eObject.eResource());

-			if (descriptor != oldDescriptor) {

-				return descriptor;

-			} else {

-				// Try to retrieve an up to date meta-model descriptor from underlying file otherwise

-				IFile file = EcorePlatformUtil.getFile(eObject.eResource());

-				return getDescriptor(file);

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * @param eClass

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(EClass eClass) {

-		if (eClass != null) {

-			return getDescriptor(eClass.getEPackage());

-		}

-		return null;

-	}

-

-	/**

-	 * @param eClass

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(EClassifier eClassifier) {

-		if (eClassifier != null) {

-			return getDescriptor(eClassifier.getEPackage());

-		}

-		return null;

-	}

-

-	/**

-	 * @param ePackage

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(EPackage ePackage) {

-		if (ePackage != null) {

-			synchronized (fPackageMetaModelDescriptorCache) {

-				IMetaModelDescriptor mmDescriptor = fPackageMetaModelDescriptorCache.get(ePackage);

-				if (mmDescriptor == null) {

-					try {

-						mmDescriptor = getDescriptor(new URI(ePackage.getNsURI()));

-						if (mmDescriptor != null) {

-							fPackageMetaModelDescriptorCache.put(ePackage, mmDescriptor);

-						} else {

-							fPackageMetaModelDescriptorCache.put(ePackage, NO_MM);

-						}

-					} catch (URISyntaxException ex) {

-						PlatformLogUtil.logAsError(Activator.getPlugin(), ex);

-					}

-				}

-				return mmDescriptor != NO_MM ? mmDescriptor : null;

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * @param wrapperItemProvider

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(IWrapperItemProvider wrapperItemProvider) {

-		if (wrapperItemProvider != null) {

-			Object unwrapped = AdapterFactoryEditingDomain.unwrap(wrapperItemProvider);

-			IMetaModelDescriptor mmDescriptor = getDescriptor(unwrapped);

-			if (mmDescriptor != null) {

-				return mmDescriptor;

-			}

-			return getDescriptor(wrapperItemProvider.getOwner());

-		}

-		return null;

-	}

-

-	/**

-	 * @param entry

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(FeatureMap.Entry entry) {

-		Object unwrapped = AdapterFactoryEditingDomain.unwrap(entry);

-		return getDescriptor(unwrapped);

-	}

-

-	/**

-	 * @param transientItemProvider

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(TransientItemProvider transientItemProvider) {

-		if (transientItemProvider != null) {

-			Notifier target = transientItemProvider.getTarget();

-			return getDescriptor(target);

-		}

-		return null;

-	}

-

-	/**

-	 * @param namespaceURI

-	 * @return

-	 */

-	public IMetaModelDescriptor getDescriptor(final URI namespaceURI) {

-		if (namespaceURI != null) {

-			synchronized (getMetaModelDescriptors()) {

-				final String namespaceURIString = namespaceURI.toString();

-				IMetaModelDescriptor mmDescriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {

-					@Override

-					public boolean accept(IMetaModelDescriptor mmDescriptor) {

-						if (namespaceURIString.equals(mmDescriptor.getNamespace())) {

-							return true;

-						}

-						if (mmDescriptor.matchesEPackageNsURIPattern(namespaceURIString)) {

-							return true;

-						}

-						for (URI compatibleNamepaceURI : mmDescriptor.getCompatibleNamespaceURIs()) {

-							if (namespaceURIString.equals(compatibleNamepaceURI.toString())) {

-								return true;

-							}

-						}

-						for (IMetaModelDescriptor compatibleResourceVersionDescriptor : mmDescriptor.getCompatibleResourceVersionDescriptors()) {

-							if (namespaceURIString.equals(compatibleResourceVersionDescriptor.getNamespace())) {

-								return true;

-							}

-							if (compatibleResourceVersionDescriptor.matchesEPackageNsURIPattern(namespaceURIString)) {

-								return true;

-							}

-						}

-						return false;

-					}

-				});

-

-				// No static meta-model descriptor found?

-				if (mmDescriptor == null) {

-					// Try to retrieve Ecore model behind given namespace and dynamically create a new meta-model

-					// descriptor

-					EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(namespaceURIString);

-					if (ePackage != null) {

-						mmDescriptor = createDescriptor(ePackage);

-						addDescriptor(mmDescriptor);

-					}

-				}

-				return mmDescriptor;

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * @param class

-	 * @return

-	 * @deprecated It is not recommended use this method because the {@link IMetaModelDescriptor metamodel descriptor}

-	 *             retrieval strategy implemented here has the side effect of that it triggers a full initialization of

-	 *             all {@link EPackage}s behind potentially all {@link IMetaModelDescriptor metamodel descriptor}s. This

-	 *             can have significant impact on runtime performance and may cause that the {@link EPackage}s of

-	 *             metamodels become initialized even though not a single instance of these metamodels exists in the

-	 *             workspace.

-	 */

-	@Deprecated

-	public IMetaModelDescriptor getDescriptor(final Class<?> clazz) {

-		if (clazz != null) {

-			IMetaModelDescriptor descriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {

-				@Override

-				public boolean accept(IMetaModelDescriptor descriptor) {

-					// Test if the class name of one of the metamodel's EPackages is the prefix of the given class' name

-					for (EPackage ePackage : descriptor.getEPackages()) {

-						if (clazz.getName().startsWith(ePackage.getClass().getName())) {

-							return true;

-						}

-					}

-					return false;

-				}

-			});

-			return descriptor;

-		}

-		return null;

-	}

-

-	/**

-	 * @param mmDescriptor

-	 * @param filter

-	 * @return

-	 */

-	private <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, IDescriptorFilter filter) {

-		List<T> descriptors = getDescriptors(mmDescriptor);

-		for (int i = descriptors.size() - 1; i >= 0; i--) {

-			T descriptor = descriptors.get(i);

-			if (filter.accept(descriptor)) {

-				if (i < descriptors.size() - 1) {

-					// there is a very good chance that the next descriptor lookup to trigger the same descriptor,

-					// as a a result, moving the descriptor to the last position could improve the performance

-					synchronized (getMetaModelDescriptors()) {

-						getMetaModelDescriptors().remove(descriptor.getIdentifier());

-						getMetaModelDescriptors().put(descriptor.getIdentifier(), descriptor);

-					}

-				}

-				return descriptor;

-			}

-		}

-		return null;

-	}

-

-	/**

-	 * Retrieves {@link IMetaModelDescriptor target meta-model descriptor} behind the given {@link IFile file}.

-	 *

-	 * @param file

-	 *            The {@link IFile file} to be investigated.

-	 * @return The {@link IFile file}'s {@link IMetaModelDescriptor target meta-model descriptor} or <code>null</code>

-	 *         if no such exists.

-	 */

-	public IMetaModelDescriptor getTargetDescriptor(IFile file) {

-		ITargetMetaModelDescriptorProvider provider = getTargetMetaModelDescriptorProvider(file);

-		if (provider != null) {

-			return provider.getDescriptor(file);

-		}

-		return null;

-	}

-

-	/**

-	 * Retrieves {@link IMetaModelDescriptor target meta-model descriptor} behind the given {@link Resource resource}.

-	 *

-	 * @param resource

-	 *            The {@link Resource resource} to be investigated.

-	 * @return The {@link Resource resource}'s {@link IMetaModelDescriptor target meta-model descriptor} or

-	 *         <code>null</code> if no such exists.

-	 */

-	public IMetaModelDescriptor getTargetDescriptor(Resource resource) {

-		ITargetMetaModelDescriptorProvider provider = getTargetMetaModelDescriptorProvider(resource);

-		if (provider != null) {

-			return provider.getDescriptor(resource);

-		}

-		return null;

-	}

-

-	/**

-	 * Retrieves the extensions of all file types which are associated with a {@link IMetaModelDescriptor target

-	 * meta-model descriptor}. Includes both file extensions for which a {@link IMetaModelDescriptor target meta-model

-	 * descriptor} has been specified directly and file extensions supported by content types for which a

-	 * {@link IMetaModelDescriptor target meta-model descriptor} has been defined.

-	 *

-	 * @return A {@link Collection collection} with all file types associated with a {@link IMetaModelDescriptor target

-	 *         meta-model descriptor} or an empty {@link Collection collection} if no such exist.

-	 * @deprecated use {@link MetaModelDescriptorRegistry#isContentTypeOfTargetDescriptorsApplicable(IFile)} instead

-	 */

-	@Deprecated

-	public Collection<String> getFileExtensionsAssociatedWithTargetDescriptors() {

-		Collection<String> extensions = new HashSet<String>(2);

-		extensions.addAll(getFileExtensionToTargetMetaModelDescriptorProviders().keySet());

-		for (String contentTypeId : getContentTypeIdToTargetMetaModelDescriptorProviders().keySet()) {

-			extensions.addAll(ExtendedPlatform.getContentTypeFileExtensions(contentTypeId));

-		}

-		return Collections.unmodifiableCollection(extensions);

-	}

-

-	/**

-	 * Returns true if the extension of the passed in file matches any extension of all file types which are associated

-	 * with a {@link IMetaModelDescriptor target meta-model descriptor}. Matching is done against both file extensions

-	 * for which a {@link IMetaModelDescriptor target meta-model descriptor} has been specified directly and file

-	 * extensions supported by content types for which a {@link IMetaModelDescriptor target meta-model descriptor} has

-	 * been defined.

-	 *

-	 * @return true if the extensions any target descriptor content type match the passed in file's extension. false if

-	 *         the file is null or has no extension.

-	 */

-	public boolean isContentTypeOfTargetDescriptorsApplicable(IFile file) {

-		if (file == null) {

-			return false;

-		}

-

-		String extension = file.getFileExtension();

-		if (extension == null) {

-			return false;

-		}

-

-		if (getFileExtensionToTargetMetaModelDescriptorProviders().keySet().contains(extension)) {

-			return true;

-		}

-

-		for (String contentTypeId : getContentTypeIdToTargetMetaModelDescriptorProviders().keySet()) {

-			if (ExtendedPlatform.isContentTypeApplicable(contentTypeId, file)) {

-				return true;

-			}

-		}

-

-		return false;

-	}

-

-	private ITargetMetaModelDescriptorProvider getTargetMetaModelDescriptorProvider(IFile file) {

-		try {

-			ITargetMetaModelDescriptorProvider provider = null;

-			if (file != null) {

-				String fileExtension = file.getFileExtension();

-				provider = getFileExtensionToTargetMetaModelDescriptorProviders().get(fileExtension);

-				if (provider == null) {

-					// Abort for files that are not in-sync. Reading the model namespace would trigger a refresh for

-					// out-of-sync files which would then trigger the model synchronizer via its resource change

-					// listener. This is not desirable at this point.

-					if (file.isSynchronized(IResource.DEPTH_ONE) == false) {

-						return null;

-					}

-					String contentTypeId = fastGetContentTypeId(file);

-					provider = getContentTypeIdToTargetMetaModelDescriptorProviders().get(contentTypeId);

-				}

-			}

-			return provider;

-		} catch (CoreException ex) {

-			// Ignore exception, just return null

-		}

-		return null;

-	}

-

-	private ITargetMetaModelDescriptorProvider getTargetMetaModelDescriptorProvider(Resource resource) {

-		IFile file = EcorePlatformUtil.getFile(resource);

-		return getTargetMetaModelDescriptorProvider(file);

-	}

-

-	/**

-	 * Retrieves {@link IMetaModelDescriptor meta-model descriptor} behind the given {@link IFile file} which will be

-	 * eventually effective or relevant to clients. This is the {@link IFile}'s {@link IMetaModelDescriptor target

-	 * meta-model descriptor} if such one is available or the {@link IFile}'s native {@link IMetaModelDescriptor

-	 * meta-model descriptor} otherwise.

-	 *

-	 * @param file

-	 *            The {@link IFile file} to be investigated.

-	 * @return The {@link IFile file}'s effective {@link IMetaModelDescriptor meta-model descriptor} or

-	 *         <code>null</code> if no such exists.

-	 */

-	public IMetaModelDescriptor getEffectiveDescriptor(IFile file) {

-		// Try to retrieve target meta-model descriptor

-		IMetaModelDescriptor descriptor = getTargetDescriptor(file);

-		if (descriptor == null) {

-			// Retrieve native meta-model descriptor otherwise

-			descriptor = getDescriptor(file);

-		}

-		return descriptor;

-	}

-

-	/**

-	 * Retrieves {@link IMetaModelDescriptor meta-model descriptor} behind the given {@link Resource resource} which

-	 * will be eventually effective or relevant to clients. This is the {@link IFile}'s {@link IMetaModelDescriptor

-	 * target meta-model descriptor} if such one is available or the {@link IFile}'s native {@link IMetaModelDescriptor

-	 * meta-model descriptor} otherwise.

-	 *

-	 * @param resource

-	 *            The {@link Resource resource} to be investigated.

-	 * @return The {@link Resource resource}'s effective {@link IMetaModelDescriptor meta-model descriptor} or

-	 *         <code>null</code> if no such exists.

-	 */

-	public IMetaModelDescriptor getEffectiveDescriptor(Resource resource) {

-		// Try to retrieve target meta-model descriptor

-		IMetaModelDescriptor descriptor = getTargetDescriptor(resource);

-		if (descriptor == null) {

-			// Retrieve native meta-model descriptor otherwise

-			descriptor = getDescriptor(resource);

-		}

-		return descriptor;

-	}

-

-	/**

-	 * Returns a {@link IMetaModelDescriptor descriptor} describing the version of specified {@link Resource resource}.

-	 * This is done by retrieving the resource's {@link EcoreResourceUtil#readModelNamespace(Resource) model namespace}

-	 * and finding a matching {@link IMetaModelDescriptor metamodel descriptor} or

-	 * {@link IMetaModelDescriptor#getCompatibleResourceVersionDescriptors() compatible resource version descriptor}.

-	 *

-	 * @param resource

-	 *            The {@link Resource resource} whose version descriptor is to be retrieved.

-	 * @return The resource's {@link IMetaModelDescriptor version descriptor} or <code>null</code> if no such could be

-	 *         determined.

-	 * @see EcoreResourceUtil#readModelNamespace(Resource)

-	 * @see #getCompatibleResourceVersionDescriptors()

-	 */

-	public IMetaModelDescriptor getResourceVersionDescriptor(Resource resource) {

-		try {

-			String resourceNamespace = EcoreResourceUtil.readModelNamespace(resource);

-			if (resourceNamespace != null) {

-				IMetaModelDescriptor mmDescriptor = getDescriptor(new URI(resourceNamespace));

-				if (mmDescriptor != null) {

-					// Newly created resources typically match implemented metamodel version exactly

-					if (resourceNamespace.equals(mmDescriptor.getNamespace())) {

-						return mmDescriptor;

-					}

-					if (mmDescriptor.matchesEPackageNsURIPattern(resourceNamespace)) {

-						return mmDescriptor;

-					}

-

-					// Resource version is older than but compatible with metamodel version

-					for (IMetaModelDescriptor compatibleResourceVersionDescriptor : mmDescriptor.getCompatibleResourceVersionDescriptors()) {

-						if (resourceNamespace.equals(compatibleResourceVersionDescriptor.getNamespace())) {

-							return compatibleResourceVersionDescriptor;

-						}

-						if (compatibleResourceVersionDescriptor.matchesEPackageNsURIPattern(resourceNamespace)) {

-							return compatibleResourceVersionDescriptor;

-						}

-					}

-				}

-			}

-		} catch (URISyntaxException ex) {

-			PlatformLogUtil.logAsError(Activator.getPlugin(), ex);

-		}

-		return null;

-	}

-

-	private synchronized void lazyInitialization() {

-		if (isInitialized == false) {

-			// already set isInitialized to true before actual initializaton to avoid infinite recursion

-			isInitialized = true;

-			readContributedDescriptors();

-			readAssociatedContentTypeIds();

-			readContributedTargetMetaModelDescriptorProviders();

-		}

-	}

-

-	private Map<String, IMetaModelDescriptor> getMetaModelDescriptors() {

-		lazyInitialization();

-		return fMetaModelDescriptors;

-	}

-

-	private Map<String, ITargetMetaModelDescriptorProvider> getContentTypeIdToTargetMetaModelDescriptorProviders() {

-		lazyInitialization();

-		return fContentTypeIdToTargetMetaModelDescriptorProviders;

-	}

-

-	private Map<String, ITargetMetaModelDescriptorProvider> getFileExtensionToTargetMetaModelDescriptorProviders() {

-		lazyInitialization();

-		return fFileExtensionToTargetMetaModelDescriptorProviders;

-	}

-

-	private Map<String, ITargetMetaModelDescriptorProvider> getAllTargetMetaModelDescriptorProviders() {

-		lazyInitialization();

-		return fAllTargetMetaModelDescriptorProviders;

-	}

-

-	/**

-	 *

-	 */

-	private interface IDescriptorFilter {

-

-		/**

-		 * @param descriptor

-		 * @return

-		 */

-		public boolean accept(IMetaModelDescriptor descriptor);

-	}

-

-	private class FileMetaModelDescriptorCache implements IFileMetaModelDescriptorCache {

-

-		/**

-		 * A cache of {@link IFile file}/{@link IMetaModelDescriptor meta-model descriptor} associations for

-		 * accelerating {@link IMetaModelDescriptor meta-model descriptor} retrieval.

-		 */

-		private Map<IFile, IMetaModelDescriptor> fFileMetaModelDescriptors = Collections.synchronizedMap(new HashMap<IFile, IMetaModelDescriptor>());

-

-		/**

-		 * A cache of {@link IFile file}/{@link IMetaModelDescriptor meta-model descriptor} associations for enabling

-		 * retrieval of old {@link IMetaModelDescriptor meta-model descriptor}s for {@link IFile file}s which have been

-		 * changed or deleted.

-		 */

-		private Map<IFile, IMetaModelDescriptor> fOldFileMetaModelDescriptors = Collections

-				.synchronizedMap(new HashMap<IFile, IMetaModelDescriptor>());

-

-		/*

-		 * @see

-		 * org.eclipse.sphinx.emf.metamodel.InternalMetaModelDescriptorRegistry#addCachedMetaModelDescriptor(org.eclipse

-		 * . core.resources.IFile, org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor)

-		 */

-		@Override

-		public void addDescriptor(IFile file, IMetaModelDescriptor mmDescriptor) {

-			if (file != null) {

-				// Encode and cache given meta-model descriptor

-				fFileMetaModelDescriptors.put(file, mmDescriptor != null ? mmDescriptor : NO_MM);

-			}

-		}

-

-		boolean hasDescriptor(IFile file) {

-			if (file != null) {

-				return fFileMetaModelDescriptors.containsKey(file);

-			}

-			return false;

-		}

-

-		IMetaModelDescriptor getDescriptor(IFile file) {

-			if (file != null) {

-				IMetaModelDescriptor mmDescriptor = fFileMetaModelDescriptors.get(file);

-

-				// Decode and return cached meta-model descriptor

-				return mmDescriptor != NO_MM ? mmDescriptor : null;

-			}

-			return null;

-		}

-

-		/*

-		 * @see org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache#moveDescriptor(org.eclipse.core.

-		 * resources .IFile, org.eclipse.core.resources.IFile)

-		 */

-		@Override

-		public void moveDescriptor(IFile oldFile, IFile newFile) {

-			if (oldFile != null && newFile != null) {

-				synchronized (fFileMetaModelDescriptors) {

-					IMetaModelDescriptor mmDescriptor = fFileMetaModelDescriptors.remove(oldFile);

-					if (mmDescriptor != null) {

-						if (!mmDescriptor.equals(MetaModelDescriptorRegistry.NO_MM)) {

-							fOldFileMetaModelDescriptors.put(oldFile, mmDescriptor);

-						}

-						/*

-						 * !! Important Note !! Don't keep old metamodel descriptor as metamodel descriptor for moved

-						 * file because it might no longer be a model file (e.g., because its extension has been

-						 * changed)

-						 */

-					}

-				}

-

-				// Make sure that cached content id gets purged along with cached metamodel descriptor

-				/*

-				 * !! Important Note !! This should normally be the business of ContentTypeIdCachePurger. However, we

-				 * have to do so here as well because we must avoid that clients end up calling

-				 * MetaModelDescriptorRegistry#getDescriptor(IFile) before ContentTypeIdCachePurger has got an

-				 * opportunity to do its job. Otherwise it could happen that the meta model descriptor for the file in

-				 * question gets retrieved from an obsolete but still cached content type id.

-				 */

-				ExtendedPlatform.removeCachedContentTypeId(newFile);

-			}

-		}

-

-		/*

-		 * @see

-		 * org.eclipse.sphinx.emf.metamodel.InternalMetaModelDescriptorRegistry#removeCachedMetaModelDescriptor(org.

-		 * eclipse .core.resources.IFile)

-		 */

-		@Override

-		public void removeDescriptor(IFile file) {

-			if (file != null) {

-				synchronized (fFileMetaModelDescriptors) {

-					IMetaModelDescriptor removedMMDescriptor = fFileMetaModelDescriptors.remove(file);

-					if (removedMMDescriptor != null && !removedMMDescriptor.equals(MetaModelDescriptorRegistry.NO_MM)) {

-						fOldFileMetaModelDescriptors.put(file, removedMMDescriptor);

-					}

-				}

-

-				// Make sure that cached content id gets purged along with cached metamodel descriptor

-				/*

-				 * !! Important Note !! This should normally be the business of ContentTypeIdCachePurger. However, we

-				 * have to do so here as well because we must avoid that clients end up calling

-				 * MetaModelDescriptorRegistry#getDescriptor(IFile) before ContentTypeIdCachePurger has got an

-				 * opportunity to do its job. Otherwise it could happen that the meta model descriptor for the file in

-				 * question gets retrieved from an obsolete but still cached content type id.

-				 */

-				ExtendedPlatform.removeCachedContentTypeId(file);

-			}

-		}

-

-		IMetaModelDescriptor getOldDescriptor(IFile file) {

-			if (file != null) {

-				return fOldFileMetaModelDescriptors.get(file);

-			}

-			return null;

-		}

-

-		/*

-		 * @see org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache#clearOldDescriptors()

-		 */

-		@Override

-		public void clearOldDescriptors() {

-			fOldFileMetaModelDescriptors.clear();

-		}

-	}

-

-	private static class DefaultMetaModelDescriptor extends AbstractMetaModelDescriptor {

-

-		protected DefaultMetaModelDescriptor(String identifier, String namespace, String name) {

-			super(identifier, namespace, name, null);

-		}

-

-		/*

-		 * @see org.eclipse.sphinx.emf.metamodel.AbstractMetaModelDescriptor#getDefaultContentTypeId()

-		 */

-		@Override

-		public String getDefaultContentTypeId() {

-			return ""; //$NON-NLS-1$

-		}

-	}

-

-	private static final class AnyMetaModelDescriptor extends DefaultMetaModelDescriptor {

-

-		public AnyMetaModelDescriptor() {

-			super("org.eclipse.sphinx.emf.metamodel.any", "http://any.mm", "Any metamodel"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

-		}

-	}

-

-	private static final class NoMetaModelDescriptor extends DefaultMetaModelDescriptor {

-

-		public NoMetaModelDescriptor() {

-			super("org.eclipse.sphinx.emf.metamodel.no", "http://no.mm", "No metamodel"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

-		}

-	}

-

-}

+/**
+ * <copyright>
+ *
+ * Copyright (c) 2008-2014 BMW Car IT, See4sys, itemis and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     BMW Car IT - Initial API and implementation
+ *     See4sys - Added support for EPackage URIs
+ *     BMW Car IT - Added robustness and support for singleton instantiation of descriptors
+ *     See4sys - Added facilities for retrieving descriptor(s) from identifier, name, ordinal, object, etc.
+ *     itemis - [346715] IMetaModelDescriptor methods of MetaModelDescriptorRegistry taking EObject or Resource arguments should not start new EMF transactions
+ *     itemis - [348544] OMG XMI files with embedded model content are not recognized as model files
+ *     itemis - [348820] Performance-optimized content type detection in MetaModelDescriptorRegistry ignores file extensions
+ *     Conti  - [349675] Performance improvements of MetaModelDescriptorRegistry
+ *     BMW Car IT - [373481] Performance optimizations for model loading
+ *     BMW Car IT - Lazy extension initialization
+ *     itemis - [409367] Add a custom URI scheme to metamodel descriptor allowing mapping URI scheme to metamodel descriptor
+ *     itemis - [418005] Add support for model files with multiple root elements
+ *     itemis - [422334] Content-type based IMetaModelDescriptor determination for a file gets corrupted if file extension is associated to org.eclipse.emf.compare.ui.contenttype.ModelContentType
+ *     itemis - [442342] Sphinx doen't trim context information from proxy URIs when serializing proxyfied cross-document references
+ *
+ * </copyright>
+ */
+package org.eclipse.sphinx.emf.metamodel;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.internal.content.ContentType;
+import org.eclipse.core.internal.content.ContentTypeHandler;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.content.IContentDescriber;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.content.IContentTypeSettings;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EClassifier;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.resource.ContentHandler;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.ecore.xmi.impl.RootXMLContentHandlerImpl;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.provider.IWrapperItemProvider;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.sphinx.emf.Activator;
+import org.eclipse.sphinx.emf.edit.TransientItemProvider;
+import org.eclipse.sphinx.emf.internal.messages.Messages;
+import org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache;
+import org.eclipse.sphinx.emf.scoping.ResourceScopeProviderRegistry;
+import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
+import org.eclipse.sphinx.emf.util.EcoreResourceUtil;
+import org.eclipse.sphinx.platform.IExtendedPlatformConstants;
+import org.eclipse.sphinx.platform.util.ExtendedPlatform;
+import org.eclipse.sphinx.platform.util.PlatformLogUtil;
+import org.eclipse.sphinx.platform.util.ReflectUtil;
+
+@SuppressWarnings("restriction")
+public class MetaModelDescriptorRegistry implements IAdaptable {
+
+	/**
+	 * The singleton instance of this registry.
+	 */
+	public static final MetaModelDescriptorRegistry INSTANCE = new MetaModelDescriptorRegistry();
+
+	/**
+	 * A default meta-model descriptor for any type of meta model.
+	 */
+	public static final IMetaModelDescriptor ANY_MM = new AnyMetaModelDescriptor();
+
+	/**
+	 * A default meta-model descriptor for no meta model.
+	 */
+	public static final IMetaModelDescriptor NO_MM = new NoMetaModelDescriptor();
+
+	/*
+	 * Extension point related constants
+	 */
+	private static final String EXTP_META_MODEL_DESCRIPTORS = "org.eclipse.sphinx.emf.metaModelDescriptors"; //$NON-NLS-1$
+	private static final String NODE_DESCRIPTOR = "descriptor"; //$NON-NLS-1$
+	private static final String NODE_CONTENT_TYPE_ASSOCIATION = "contentTypeAssociation"; //$NON-NLS-1$
+	private static final String NODE_TARGET_DESCRIPTOR = "targetDescriptorProvider";//$NON-NLS-1$
+	private static final String NODE_CONTENT_TYPE = "contentType";//$NON-NLS-1$
+	private static final String NODE_FILE_TYPE = "fileType";//$NON-NLS-1$
+	private static final String ATTR_ID = "id"; //$NON-NLS-1$
+	private static final String ATTR_EXTENSION = "extension";//$NON-NLS-1$
+	private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+	private static final String ATTR_OVERRIDE = "override";//$NON-NLS-1$
+	private static final String ATTR_METAMODEL_DESCRIPTOR_ID = "metaModelDescriptorId"; //$NON-NLS-1$
+	private static final String ATTR_CONTENT_TYPE_ID = "contentTypeId"; //$NON-NLS-1$
+
+	/**
+	 * The namespace pattern for OMG-defined XMI formats.
+	 */
+	private static final Pattern OMG_XMI_NAMESPACE_PATTERN = Pattern.compile("http://(schema|www)\\.omg\\.org(/spec)?/XMI.*"); //$NON-NLS-1$
+
+	/**
+	 * The if of the special content type defined by EMF Compare used to identify files that are to be opened in EMF Compare
+	 * editor.
+	 */
+	private static final String EMF_COMPARE_CONTENT_TYPE_ID = "org.eclipse.emf.compare.ui.contenttype.ModelContentType"; //$NON-NLS-1$
+
+	/**
+	 * The extension registry.
+	 */
+	private IExtensionRegistry fExtensionRegistry;
+
+	/**
+	 * Flag to track lazy initialization.
+	 */
+	private boolean isInitialized = false;
+
+	/**
+	 * The contributed meta-model descriptors.
+	 */
+	private final Map<String, IMetaModelDescriptor> fMetaModelDescriptors = Collections
+			.synchronizedMap(new LinkedHashMap<String, IMetaModelDescriptor>());
+
+	/**
+	 * The contributed target meta-model descriptor providers.
+	 */
+	private final Map<String, ITargetMetaModelDescriptorProvider> fContentTypeIdToTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();
+
+	private final Map<String, ITargetMetaModelDescriptorProvider> fFileExtensionToTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();
+
+	private final Map<String, ITargetMetaModelDescriptorProvider> fAllTargetMetaModelDescriptorProviders = new HashMap<String, ITargetMetaModelDescriptorProvider>();
+
+	private final FileMetaModelDescriptorCache fFileMetaModelDescriptorCache = new FileMetaModelDescriptorCache();
+
+	private final Map<String, String> fContentTypeIdCache = new HashMap<String, String>();
+
+	private final Map<EPackage, IMetaModelDescriptor> fPackageMetaModelDescriptorCache = new HashMap<EPackage, IMetaModelDescriptor>();
+
+	/**
+	 * Private constructor for the singleton pattern.
+	 */
+	private MetaModelDescriptorRegistry() {
+	}
+
+	private IExtensionRegistry getExtensionRegistry() {
+		if (fExtensionRegistry == null) {
+			fExtensionRegistry = Platform.getExtensionRegistry();
+		}
+		return fExtensionRegistry;
+	}
+
+	// FIXME Should be entirely removed as soon as integration tests will be available.
+	// Only used for testing
+	public void setExtensionRegistry(IExtensionRegistry extensionRegistry) {
+		fExtensionRegistry = extensionRegistry;
+		isInitialized = true;
+		getMetaModelDescriptors().clear();
+		getContentTypeIdToTargetMetaModelDescriptorProviders().clear();
+		getFileExtensionToTargetMetaModelDescriptorProviders().clear();
+		getAllTargetMetaModelDescriptorProviders().clear();
+		isInitialized = false;
+	}
+
+	/**
+	 * Reads contributions to <em>Meta-Model Descriptor</em> extension point.
+	 * <p>
+	 * <table>
+	 * <tr valign=top>
+	 * <td><b>Note</b>&nbsp;&nbsp;</td>
+	 * <td>It is recommended to call this method inside a block <tt><b>synchronized</b></tt> on the encapsulated
+	 * <code>fMetaModelDescriptors</code> field in order to avoid inconsistencies in registered meta-model
+	 * {@linkplain IMetaModelDescriptor descriptor}s in case of concurrent read/adds.</td>
+	 * </tr>
+	 * </table>
+	 */
+	private void readContributedDescriptors() {
+		IExtensionRegistry extensionRegistry = getExtensionRegistry();
+		if (extensionRegistry != null) {
+			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();
+			for (IExtension extension : extensions) {
+				IConfigurationElement[] configElements = extension.getConfigurationElements();
+				for (IConfigurationElement configElement : configElements) {
+					try {
+						if (NODE_DESCRIPTOR.equals(configElement.getName())) {
+							String id = configElement.getAttribute(ATTR_ID);
+							IMetaModelDescriptor mmDescriptor = null;
+							try {
+								String className = configElement.getAttribute(ATTR_CLASS);
+								Class<?> clazz = Platform.getBundle(configElement.getContributor().getName()).loadClass(className);
+								mmDescriptor = (IMetaModelDescriptor) ReflectUtil.getFieldValue(clazz, "INSTANCE"); //$NON-NLS-1$
+							} catch (ClassNotFoundException e) {
+								PlatformLogUtil.logAsError(Activator.getPlugin(), e);
+							} catch (IllegalAccessException e) {
+								PlatformLogUtil.logAsError(Activator.getPlugin(), e);
+							} catch (NoSuchFieldException noSuchFieldEx) {
+								PlatformLogUtil.logAsInfo(Activator.getPlugin(), noSuchFieldEx);
+								mmDescriptor = (IMetaModelDescriptor) configElement.createExecutableExtension(ATTR_CLASS);
+							}
+							if (!id.equals(mmDescriptor.getIdentifier())) {
+								throw new RuntimeException(NLS.bind(Messages.error_mmDescriptorIdentifierNotEqual, id, mmDescriptor.getIdentifier()));
+							}
+							addDescriptor(mmDescriptor);
+						}
+					} catch (Exception ex) {
+						PlatformLogUtil.logAsError(Activator.getDefault(), ex);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Reads contributions to <em>Associated Content Type</em> of <em>Meta-Model Descriptor</em> extension point.
+	 */
+	private void readAssociatedContentTypeIds() {
+		IExtensionRegistry extensionRegistry = getExtensionRegistry();
+		if (extensionRegistry != null) {
+			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();
+			for (IExtension extension : extensions) {
+				IConfigurationElement[] configElements = extension.getConfigurationElements();
+				for (IConfigurationElement configElement : configElements) {
+					try {
+						if (NODE_CONTENT_TYPE_ASSOCIATION.equals(configElement.getName())) {
+							String mmDescriptorId = configElement.getAttribute(ATTR_METAMODEL_DESCRIPTOR_ID);
+							String contentTypeId = configElement.getAttribute(ATTR_CONTENT_TYPE_ID);
+							IMetaModelDescriptor mmDescriptor = getDescriptor(mmDescriptorId);
+							mmDescriptor.addAssociatedContentTypeId(contentTypeId);
+						}
+					} catch (Exception ex) {
+						PlatformLogUtil.logAsError(Activator.getDefault(), ex);
+					}
+				}
+			}
+		}
+	}
+
+	protected IMetaModelDescriptor createDescriptor(EPackage ePackage) {
+		Assert.isNotNull(ePackage);
+
+		String ePackageClassName = ePackage.getClass().getName();
+		String id = ePackageClassName.substring(0, ePackageClassName.lastIndexOf(".")); //$NON-NLS-1$
+		if (id.endsWith(".impl") || id.endsWith(".util")) {//$NON-NLS-1$ //$NON-NLS-2$
+			id = id.substring(0, id.lastIndexOf(".")); //$NON-NLS-1$
+		}
+
+		return new DefaultMetaModelDescriptor(id, ePackage.getNsURI(), ePackage.getName());
+	}
+
+	/**
+	 * Add the specified {@link IMetaModelDescriptor mmDescriptor} to this registry (if not already added).
+	 *
+	 * @param mmDescriptor
+	 *            The meta-model {@linkplain IMetaModelDescriptor descriptor} to add to this registry.
+	 */
+	public void addDescriptor(IMetaModelDescriptor mmDescriptor) {
+		if (mmDescriptor != null && !mmDescriptor.equals(ANY_MM) && !mmDescriptor.equals(NO_MM)) {
+			String id = mmDescriptor.getIdentifier();
+			if (id == null) {
+				PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+						new RuntimeException(NLS.bind(Messages.warning_mmDescriptorHasNoIdentifier, mmDescriptor.getName())));
+			}
+			if (getMetaModelDescriptors().containsKey(id)) {
+				PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+						new RuntimeException(NLS.bind(Messages.warning_mmDescriptorIdentifierNotUnique, id)));
+			}
+			getMetaModelDescriptors().put(id, mmDescriptor);
+		}
+	}
+
+	/**
+	 * Reads contributions to <em>Meta-Model Descriptor/TargetMetaModelDescriptorProvider</em> extension point.
+	 */
+	private void readContributedTargetMetaModelDescriptorProviders() {
+		IExtensionRegistry extensionRegistry = getExtensionRegistry();
+		if (extensionRegistry != null) {
+			Set<String> overriddenIds = new HashSet<String>();
+			IExtension[] extensions = extensionRegistry.getExtensionPoint(EXTP_META_MODEL_DESCRIPTORS).getExtensions();
+			for (IExtension extension : extensions) {
+				IConfigurationElement[] configElements = extension.getConfigurationElements();
+				overriddenIds.addAll(getOverriddenTargetMetaModelDescriptorProviderIds(configElements));
+			}
+			for (IExtension extension : extensions) {
+				IConfigurationElement[] configElements = extension.getConfigurationElements();
+				readContributedTargetMetaModelDescriptorProviders(configElements, overriddenIds);
+			}
+		}
+	}
+
+	private void readContributedTargetMetaModelDescriptorProviders(IConfigurationElement[] configElements, Set<String> overriddenIds) {
+		Assert.isNotNull(configElements);
+		Assert.isNotNull(overriddenIds);
+
+		for (IConfigurationElement configElement : configElements) {
+			try {
+				if (NODE_TARGET_DESCRIPTOR.equals(configElement.getName())) {
+					String id = configElement.getAttribute(ATTR_ID);
+					if (!overriddenIds.contains(id)) {
+						ITargetMetaModelDescriptorProvider provider = (ITargetMetaModelDescriptorProvider) configElement
+								.createExecutableExtension(ATTR_CLASS);
+						if (addTargetDescriptorProvider(id, provider)) {
+							for (IConfigurationElement childConfigElement : configElement.getChildren()) {
+								if (NODE_CONTENT_TYPE.equals(childConfigElement.getName())) {
+									String contenTypeId = childConfigElement.getAttribute(ATTR_ID);
+									addTargetDescriptorProviderForContentTypeId(contenTypeId, provider);
+								} else if (NODE_FILE_TYPE.equals(childConfigElement.getName())) {
+									String fileExtension = childConfigElement.getAttribute(ATTR_EXTENSION);
+									addTargetDescriptorProviderForFileExtension(fileExtension, provider);
+								}
+							}
+						}
+					}
+				}
+			} catch (Exception ex) {
+				PlatformLogUtil.logAsError(Activator.getDefault(), ex);
+			}
+		}
+	}
+
+	private Set<String> getOverriddenTargetMetaModelDescriptorProviderIds(IConfigurationElement[] configElements) {
+		Assert.isNotNull(configElements);
+
+		Set<String> overriddenIds = new HashSet<String>();
+		for (IConfigurationElement configElement : configElements) {
+			if (NODE_TARGET_DESCRIPTOR.equals(configElement.getName())) {
+				String overriddenTargetMetaModelDescriptorId = configElement.getAttribute(ATTR_OVERRIDE);
+				if (overriddenTargetMetaModelDescriptorId != null) {
+					if (!overriddenIds.contains(overriddenTargetMetaModelDescriptorId)) {
+						overriddenIds.add(overriddenTargetMetaModelDescriptorId);
+					} else {
+						PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(NLS
+								.bind(Messages.warning_multipleTargetMetaModelDescriptorProvidersOverride, overriddenTargetMetaModelDescriptorId)));
+					}
+				}
+			}
+		}
+		return overriddenIds;
+	}
+
+	private boolean addTargetDescriptorProvider(String id, ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {
+		Assert.isNotNull(targetMetaModelDescriptorProvider);
+
+		if (id == null) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(), new RuntimeException(Messages.warning_targetMetaModelDescriptorProviderWithoutId));
+			return false;
+		}
+		if (getAllTargetMetaModelDescriptorProviders().containsKey(id)) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+					new RuntimeException(NLS.bind(Messages.warning_targetMetaModelDescriptorProviderIdNotUnique, id)));
+			return false;
+		}
+
+		getAllTargetMetaModelDescriptorProviders().put(id, targetMetaModelDescriptorProvider);
+		return true;
+	}
+
+	private void addTargetDescriptorProviderForFileExtension(String fileExtension,
+			ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {
+		Assert.isNotNull(targetMetaModelDescriptorProvider);
+		Assert.isLegal(getAllTargetMetaModelDescriptorProviders().containsValue(targetMetaModelDescriptorProvider));
+
+		if (fileExtension == null) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+					new RuntimeException(NLS.bind(Messages.warning_fileExtensionForTargetMetaModelDescriptorProviderMustNotBeNull, fileExtension)));
+		}
+		if (getFileExtensionToTargetMetaModelDescriptorProviders().containsKey(fileExtension)) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+					new RuntimeException(NLS.bind(Messages.warning_fileExtensionForTargetMetaModelDescriptorProviderNotUnique, fileExtension)));
+		}
+
+		getFileExtensionToTargetMetaModelDescriptorProviders().put(fileExtension, targetMetaModelDescriptorProvider);
+	}
+
+	private void addTargetDescriptorProviderForContentTypeId(String contentTypeId,
+			ITargetMetaModelDescriptorProvider targetMetaModelDescriptorProvider) {
+		Assert.isNotNull(targetMetaModelDescriptorProvider);
+		Assert.isLegal(getAllTargetMetaModelDescriptorProviders().containsValue(targetMetaModelDescriptorProvider));
+
+		if (contentTypeId == null) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+					new RuntimeException(NLS.bind(Messages.warning_contentTypeIdForTargetMetaModelDescriptorProviderMustNotBeNull, contentTypeId)));
+
+		}
+		if (getContentTypeIdToTargetMetaModelDescriptorProviders().containsKey(contentTypeId)) {
+			PlatformLogUtil.logAsWarning(Activator.getPlugin(),
+					new RuntimeException(NLS.bind(Messages.warning_contentTypeIdForTargetMetaModelDescriptorProviderNotUnique, contentTypeId)));
+		}
+
+		getContentTypeIdToTargetMetaModelDescriptorProviders().put(contentTypeId, targetMetaModelDescriptorProvider);
+	}
+
+	/*
+	 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+	 */
+	@Override
+	public Object getAdapter(@SuppressWarnings("rawtypes") Class adapterType) {
+		if (adapterType.equals(IFileMetaModelDescriptorCache.class)) {
+			return fFileMetaModelDescriptorCache;
+		}
+		return null;
+	}
+
+	/**
+	 * @param mmDescriptor
+	 * @return
+	 */
+	public List<IMetaModelDescriptor> getResolvedDescriptors(IMetaModelDescriptor mmDescriptor) {
+		List<IMetaModelDescriptor> resolvedDescriptors = new ArrayList<IMetaModelDescriptor>();
+		for (IMetaModelDescriptor descriptor : getDescriptors(mmDescriptor)) {
+			if (descriptor.getRootEPackage() != null) {
+				resolvedDescriptors.add(descriptor);
+			}
+		}
+		return resolvedDescriptors;
+	}
+
+	public IMetaModelDescriptor getDescriptor(Object object) {
+		if (object instanceof String) {
+			return getDescriptor((String) object);
+		} else if (object instanceof URI) {
+			return getDescriptor((URI) object);
+		} else if (object instanceof IFile) {
+			return getDescriptor((IFile) object);
+		} else if (object instanceof Resource) {
+			return getDescriptor((Resource) object);
+		} else if (object instanceof EObject) {
+			return getDescriptor((EObject) object);
+		} else if (object instanceof IWrapperItemProvider) {
+			return getDescriptor((IWrapperItemProvider) object);
+		} else if (object instanceof FeatureMap.Entry) {
+			return getDescriptor((FeatureMap.Entry) object);
+		} else if (object instanceof TransientItemProvider) {
+			return getDescriptor((TransientItemProvider) object);
+		} else if (object instanceof EClass) {
+			return getDescriptor((EClass) object);
+		} else if (object instanceof EPackage) {
+			return getDescriptor((EPackage) object);
+		}
+		return null;
+	}
+
+	/**
+	 * Used in UI component to return a list of sorted descriptors.
+	 *
+	 * @param mmDescriptor
+	 * @return
+	 * @since 0.7.0
+	 */
+	public <T extends IMetaModelDescriptor> List<T> getDescriptors(T mmDescriptor, boolean sorted) {
+		List<T> descriptors = new ArrayList<T>();
+		if (mmDescriptor != null) {
+			synchronized (getMetaModelDescriptors()) {
+				for (IMetaModelDescriptor descriptor : getMetaModelDescriptors().values()) {
+					if (mmDescriptor == ANY_MM || mmDescriptor.getClass().isInstance(descriptor)) {
+						@SuppressWarnings("unchecked")
+						T desc = (T) descriptor;
+						descriptors.add(desc);
+					}
+				}
+			}
+		}
+		if (sorted) {
+			Collections.sort(descriptors, new Comparator<T>() {
+				@Override
+				public int compare(IMetaModelDescriptor mmd1, IMetaModelDescriptor mmd2) {
+					String label1 = String.format(IMetaModelDescriptor.LABEL_PATTERN, mmd1.getName(), mmd1.getNamespace());
+					String label2 = String.format(IMetaModelDescriptor.LABEL_PATTERN, mmd2.getName(), mmd2.getNamespace());
+					return label1.compareTo(label2);
+				}
+			});
+		}
+		return descriptors;
+	}
+
+	/**
+	 * @param mmDescriptor
+	 * @return
+	 */
+	public <T extends IMetaModelDescriptor> List<T> getDescriptors(T mmDescriptor) {
+		return getDescriptors(mmDescriptor, false);
+	}
+
+	/**
+	 * @param identifier
+	 *            A meta-model descriptor identifier.
+	 * @return The meta-model descriptor contributed with the specified identifier.
+	 */
+	public IMetaModelDescriptor getDescriptor(String identifier) {
+		if (ANY_MM.getIdentifier().equals(identifier)) {
+			return ANY_MM;
+		}
+		return getMetaModelDescriptors().get(identifier);
+	}
+
+	/**
+	 * @param idPattern
+	 *            A regular expression which the identifiers of the returned meta-model descriptors must match.
+	 * @return Meta-model descriptors whose identifier matches the specified regular expression.
+	 */
+	public List<IMetaModelDescriptor> getDescriptors(String idPattern) {
+		if (ANY_MM.getIdentifier().equals(idPattern)) {
+			return Collections.singletonList(ANY_MM);
+		}
+
+		List<IMetaModelDescriptor> mmDescriptors = new ArrayList<IMetaModelDescriptor>();
+		if (idPattern != null) {
+			Pattern pattern = Pattern.compile(idPattern);
+			synchronized (getMetaModelDescriptors()) {
+				for (Map.Entry<String, IMetaModelDescriptor> entry : getMetaModelDescriptors().entrySet()) {
+					if (pattern.matcher(entry.getKey()).matches()) {
+						mmDescriptors.add(entry.getValue());
+					}
+				}
+			}
+		}
+		return mmDescriptors;
+	}
+
+	/**
+	 * Returns the {@link IMetaModelDescriptor descriptors} of all meta-models that use URIs with given
+	 * <code>customURIScheme</code> in cross-document references and as proxy URIs.
+	 *
+	 * @param scheme
+	 *            The custom URI scheme for which the descriptors of the meta-model using it is to be returned.
+	 * @return The descriptors of the meta-models using specified <code>customURIScheme</code>.
+	 */
+	public List<IMetaModelDescriptor> getDescriptorsFromURIScheme(String scheme) {
+		List<IMetaModelDescriptor> mmDescriptors = new ArrayList<IMetaModelDescriptor>();
+		if (scheme != null) {
+			synchronized (getMetaModelDescriptors()) {
+				for (IMetaModelDescriptor mmDescriptor : getMetaModelDescriptors().values()) {
+					if (mmDescriptor.getCustomURIScheme() != null) {
+						if (mmDescriptor.getCustomURIScheme().equals(scheme)) {
+							mmDescriptors.add(mmDescriptor);
+						}
+					}
+				}
+			}
+		}
+		return mmDescriptors;
+	}
+
+	/**
+	 * @param mmDescriptor
+	 * @param ordinal
+	 * @return
+	 * @deprecated see {@link MetaModelVersionData#getOrdinal()}
+	 */
+	@Deprecated
+	public <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, final int ordinal) {
+		return getDescriptor(mmDescriptor, new IDescriptorFilter() {
+			@Override
+			public boolean accept(IMetaModelDescriptor descriptor) {
+				return descriptor.getOrdinal() == ordinal;
+			}
+		});
+	}
+
+	/**
+	 * @param mmDescriptor
+	 * @param name
+	 * @return
+	 */
+	public <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, final String name) {
+		return getDescriptor(mmDescriptor, new IDescriptorFilter() {
+			@Override
+			public boolean accept(IMetaModelDescriptor descriptor) {
+				return descriptor.getName().equals(name);
+			}
+		});
+	}
+
+	/**
+	 * Returns the {@link IMetaModelDescriptor meta-model descriptor} for the given <code>resource</code>.
+	 *
+	 * @param resource
+	 *            The {@link Resource resource} whose meta-model descriptor is to be returned.
+	 * @return The meta-model descriptor of the specified <code>resource</code>.
+	 */
+	public IMetaModelDescriptor getDescriptor(final Resource resource) {
+		/*
+		 * Performance optimization: Theoretically we could just all the time rely on the id of the content type behind given
+		 * file and retrieve the metamodel descriptor from there. However, keeping in mind that content type detection is an
+		 * incredibly slow affair we must not do that but proceed in the following order: For loaded resources the fastest
+		 * option is to retrieve the metamodel descriptor from the nsURI of the EPackage behind one of the root objects in the
+		 * resource. For resources that have just been created but not loaded (and therefore no content) yet we try to retrieve
+		 * the metamodel descriptor from the underlying workspace file so as to benefit from metamodel descriptor that
+		 * potentially has already been cached for the same. At last, we rely on the resource's model namespace which enables us
+		 * to determine the metamodel descriptors of files that are not loaded yet and located outside the workspace.
+		 */
+
+		// Try to retrieve descriptor from model root object in given resource (applies to loaded resources)
+		if (resource != null) {
+			EList<EObject> contents = resource.getContents();
+			if (!contents.isEmpty()) {
+				IMetaModelDescriptor mmDescriptor = getDescriptor(contents.get(0));
+				if (mmDescriptor != null) {
+					return mmDescriptor;
+				}
+			}
+		}
+
+		// Try to retrieve descriptor from underlying workspace file (applies to resources that have been
+		// created but not loaded - and therefore no EObject content - yet and are located inside the workspace)
+		IFile file = EcorePlatformUtil.getFile(resource);
+		if (file != null) {
+			return getDescriptor(file);
+		}
+
+		// Try to retrieve descriptor from model namespace of given resource (applies to resources that have been
+		// created but not loaded - and therefore no EObject content - yet and are located outside the workspace)
+		if (resource != null) {
+			String namespace = EcoreResourceUtil.readModelNamespace(resource);
+			if (namespace != null) {
+				// Determine corresponding meta-model descriptor
+				try {
+					return getDescriptor(new URI(namespace));
+				} catch (URISyntaxException ex) {
+					// Ignore exception, just return null
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Returns the {@link IMetaModelDescriptor meta-model descriptor} for given {@link IFile file}.
+	 *
+	 * @param file
+	 *            The {@link IFile file} whose {@link IMetaModelDescriptor meta-model descriptor} is to be returned.
+	 * @return The {@link IMetaModelDescriptor meta-model descriptor} of given {@link IFile}, or <code>null</code> if no
+	 *         such could be determined.
+	 */
+	public IMetaModelDescriptor getDescriptor(IFile file) {
+		if (file != null) {
+			// Try to retrieve meta-model descriptor from cache
+			if (fFileMetaModelDescriptorCache.hasDescriptor(file)) {
+				return fFileMetaModelDescriptorCache.getDescriptor(file);
+			} else {
+				try {
+					IMetaModelDescriptor mmDescriptor = null;
+
+					// Retrieve content type id of given file
+					final String contentTypeId = fastGetContentTypeId(file);
+
+					if (contentTypeId != null) {
+						// EMF Compare content type encountered?
+						if (EMF_COMPARE_CONTENT_TYPE_ID.equals(contentTypeId)) {
+							// Refer to target metamodel descriptor if any
+							/*
+							 * !! Important Note !! This is a workaround for the fact that EMF Compare has hijacked the content type concept for
+							 * expressing file associations, i.e., to identify which file types are to be opened with the EMF Compare editor. As the
+							 * consequence, the files which yield the EMF Compare content type can actually have any content and it becomes
+							 * impossible to determine their real file type based on this content type. To to remedy this defect, we enable clients
+							 * to contribute a target metamodel descriptor provider for the file types in question and directly indicate the
+							 * corresponding metamodel descriptor.
+							 */
+							mmDescriptor = getTargetDescriptor(file);
+						} else {
+							// Determine corresponding meta-model descriptor
+							mmDescriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {
+								@Override
+								public boolean accept(IMetaModelDescriptor descriptor) {
+									if (descriptor.getContentTypeIds().contains(contentTypeId)) {
+										return true;
+									}
+									if (descriptor.getCompatibleContentTypeIds().contains(contentTypeId)) {
+										return true;
+									}
+									return false;
+								}
+							});
+						}
+					}
+
+					// Cache resulting meta-model descriptor
+					if (file.isAccessible()) {
+						fFileMetaModelDescriptorCache.addDescriptor(file, mmDescriptor);
+					}
+
+					return mmDescriptor;
+				} catch (Exception ex) {
+					// Ignore exception, just return null
+				}
+			}
+		}
+		return null;
+	}
+
+	private String fastGetContentTypeId(IFile file) throws CoreException {
+		// Content type id for given file already cached?
+		if (ExtendedPlatform.hasCachedContentTypeId(file)) {
+			// Retrieve content type id of given file normally - we know that it will be quick
+			return ExtendedPlatform.getContentTypeId(file);
+		} else {
+			try {
+				/*
+				 * Performance optimization: Use optimized detection of content type only if there is a realistic chance that given file
+				 * is a model file inside an existing scope. For any other file it would just add some useless extra time to the native
+				 * content type retrieval process.
+				 */
+				if (!ResourceScopeProviderRegistry.INSTANCE.isNotInAnyScope(file)) {
+					/*
+					 * Performance optimization: Try to determine meta-model descriptor from model namespace in given file. This works
+					 * significantly more quickly than retrieving the file's content type and looking up the corresponding meta-model
+					 * descriptor. In case the meta-model descriptor can be found this way we go on and try to deduce the file's content
+					 * type id from the model namespace which we have found and cache it for the given file. If successful, this enables us
+					 * to completely avoid very slow native content type detection later on (e.g. during Resource creation in
+					 * ExtendedResourceSetImpl#demandCreateResource(URI)) resulting in a significant acceleration when content type
+					 * dependent operations on many files need to be carried out (e.g. model loading).
+					 */
+					// Try to retrieve model namespace which might be present in given file
+					String namespace = EcorePlatformUtil.readModelNamespace(file);
+
+					// Has a model namespace been found?
+					IMetaModelDescriptor mmDescriptor = null;
+					if (namespace != null) {
+						// Determine corresponding meta-model descriptor
+						mmDescriptor = getDescriptor(new URI(namespace));
+					}
+
+					// Does a matching meta-model descriptor exist?
+					if (mmDescriptor != null) {
+						// Try to retrieve content type id for given model namespace and file extension
+						String contentTypeId = getContentTypeIdFromDescriber(namespace, file.getFileExtension());
+						// Is a matching content type id available?
+						if (contentTypeId != null) {
+							// Cache content type id for given file to accelerate subsequent content type
+							// dependent operations (e.g., ResourceFactory retrieval)
+							ExtendedPlatform.setCachedContentTypeId(file, contentTypeId);
+							return contentTypeId;
+						}
+					} else {
+						/*
+						 * Performance optimization: If the namespace-based retrieval of the meta-model descriptor didn't succeed and given file
+						 * is an XML file that has a namespace then we can be sure that the XML file is not a model file. Consequently, we can
+						 * immediately remember it is such and can spare out the lengthy analysis or its content type. The only exception to
+						 * this rule are XML files with OMG XMI content - they yield an OMG-defined XMI namespace rather than the model
+						 * namespace but still may embed model content somewhere inside. In this case we must let perform a full content type
+						 * analysis so as to detect if the OMG XMI file is a model file or not.
+						 */
+						if (namespace != null && !OMG_XMI_NAMESPACE_PATTERN.matcher(namespace).matches()) {
+							// Set cached content type id for given file to unspecified to accelerate subsequent
+							// content type dependent operations
+							ExtendedPlatform.setCachedContentTypeId(file, IExtendedPlatformConstants.CONTENT_TYPE_ID_NON_MODEL_XML_FILE);
+							return IExtendedPlatformConstants.CONTENT_TYPE_ID_NON_MODEL_XML_FILE;
+						}
+					}
+				}
+
+				// If we are still here then we have to retrieve the content type id of given file natively - and accept
+				// that it will take time
+				return ExtendedPlatform.getContentTypeId(file);
+			} catch (Exception ex) {
+				// Ignore exception, just return null
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns content type id for given model namespace and file extension in case that an EMF {@link Describer content
+	 * type describer} has been contributed for this model namespace and matches it.
+	 *
+	 * @param namespace
+	 *            The model namespace for which the corresponding content type id is to be determined.
+	 * @param extension
+	 *            The file extension that must be supported by the corresponding content type.
+	 * @return The content type id for given model namespace and file extension, or <code>null</code> if no such could be
+	 *         determined.
+	 */
+	private String getContentTypeIdFromDescriber(String namespace, String extension) {
+		String key = namespace + "@" + extension; //$NON-NLS-1$
+		if (fContentTypeIdCache.containsKey(key)) {
+			return fContentTypeIdCache.get(key);
+		}
+
+		// Scan all registered content types
+		List<String> contentTypeIdCandidates = new ArrayList<String>(2);
+		for (IContentType contentType : Platform.getContentTypeManager().getAllContentTypes()) {
+			try {
+				// Sort out any content type which does not support required file extension
+				if (Arrays.asList(contentType.getFileSpecs(IContentTypeSettings.FILE_EXTENSION_SPEC)).contains(extension)) {
+					// Try to retrieve content type describer which matches model namespace
+					IContentDescriber describer = null;
+					if (contentType instanceof ContentType) {
+						describer = ((ContentType) contentType).getDescriber();
+					} else if (contentType instanceof ContentTypeHandler) {
+						describer = ((ContentTypeHandler) contentType).getTarget().getDescriber();
+					}
+
+					if (describer instanceof RootXMLContentHandlerImpl.Describer) {
+						ContentHandler contentHandler = (ContentHandler) ReflectUtil.getInvisibleFieldValue(describer, "contentHandler"); //$NON-NLS-1$
+						Boolean matching = (Boolean) ReflectUtil.invokeInvisibleMethod(contentHandler, "isMatchingNamespace", namespace); //$NON-NLS-1$
+						if (matching) {
+							// Remember id of matching content type as candidate
+							contentTypeIdCandidates.add(contentType.getId());
+
+							// Exact match?
+							String contentHandlerNamespace = (String) ReflectUtil.getInvisibleFieldValue(contentHandler, "namespace"); //$NON-NLS-1$
+							if (contentHandlerNamespace == null && namespace == null || contentHandlerNamespace != null && namespace != null
+									&& contentHandlerNamespace.length() == namespace.length()) {
+								// No need to look at other conten types
+								break;
+							}
+						}
+					}
+				}
+			} catch (Exception ex) {
+				// Ignore exception, just log it as warning
+				PlatformLogUtil.logAsWarning(Activator.getPlugin(), ex);
+			}
+		}
+
+		// Return best fitting content type id candidate if any
+		String contentTypeId = null;
+		if (contentTypeIdCandidates.size() > 1) {
+			Collections.sort(contentTypeIdCandidates);
+			contentTypeId = contentTypeIdCandidates.get(contentTypeIdCandidates.size() - 1);
+		} else if (contentTypeIdCandidates.size() == 1) {
+			contentTypeId = contentTypeIdCandidates.get(0);
+		}
+
+		fContentTypeIdCache.put(key, contentTypeId);
+		return contentTypeId;
+	}
+
+	/**
+	 * Returns the old {@link IMetaModelDescriptor meta-model descriptor} which given {@link Resource resource} had had
+	 * before is was changed or deleted. !Important note! The information will only be available during processing of the
+	 * method
+	 * org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry.FileMetaModelDescriptorCache.removeDescriptor(IFile)
+	 * called from org.eclipse.sphinx.emf.internal.MetaModelDescriptorCacheAndModelDescriptorRegistryUpdater.
+	 * handleModelResourceUnloaded(Collection<Resource>).In any other use case the method will behave as if there was no old
+	 * meta-model descriptor available. The reason is that old meta-model descriptor is removed as soon as model descriptor
+	 * has been removed.
+	 *
+	 * @param resource
+	 *            The {@link Resource resource} whose old {@link IMetaModelDescriptor meta-model descriptor} is to be
+	 *            returned.
+	 * @return The old {@link IMetaModelDescriptor meta-model descriptor} of given {@link Resource}, or <code>null</code>
+	 *         {@link IFile file} hadn't had any {@link IMetaModelDescriptor meta-model descriptor} before it was changed or
+	 *         deleted.
+	 */
+	public IMetaModelDescriptor getOldDescriptor(Resource resource) {
+		if (resource == null) {
+			return null;
+		}
+		return getOldDescriptor(resource.getURI());
+	}
+
+	/**
+	 * Returns the old {@link IMetaModelDescriptor meta-model descriptor} which given {@link IFile file} had had before is
+	 * was changed or deleted. !Important note! The information will only be available during processing of the method
+	 * org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry.FileMetaModelDescriptorCache.removeDescriptor(IFile)
+	 * called from org.eclipse.sphinx.emf.internal.MetaModelDescriptorCacheAndModelDescriptorRegistryUpdater.
+	 * handleModelResourceUnloaded(Collection<Resource>).In any other use case the method will behave as if there was no old
+	 * meta-model descriptor available. The reason is that old meta-model descriptor is removed as soon as model descriptor
+	 * has been removed.
+	 *
+	 * @deprecated
+	 * @param file
+	 *            The {@link IFile file} whose old {@link IMetaModelDescriptor meta-model descriptor} is to be returned.
+	 * @return The old {@link IMetaModelDescriptor meta-model descriptor} of given {@link IFile}, or <code>null</code>
+	 *         {@link IFile file} hadn't had any {@link IMetaModelDescriptor meta-model descriptor} before it was changed or
+	 *         deleted.
+	 */
+	@Deprecated
+	public IMetaModelDescriptor getOldDescriptor(IFile file) {
+		org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI.createPlatformResourceURI(file.getFullPath().toPortableString(), true);
+		return fFileMetaModelDescriptorCache.getOldDescriptor(uri);
+	}
+
+	/**
+	 * Returns the old {@link IMetaModelDescriptor meta-model descriptor} which given {@link IFile file} had had before is
+	 * was changed or deleted. !Important note! The information will only be available during processing of the method
+	 * org.eclipse.sphinx.emf.metamodel.MetaModelDescriptorRegistry.FileMetaModelDescriptorCache.removeDescriptor(IFile)
+	 * called from org.eclipse.sphinx.emf.internal.MetaModelDescriptorCacheAndModelDescriptorRegistryUpdater.
+	 * handleModelResourceUnloaded(Collection<Resource>).In any other use case the method will behave as if there was no old
+	 * meta-model descriptor available. The reason is that old meta-model descriptor is removed as soon as model descriptor
+	 * has been removed.
+	 *
+	 * @param file
+	 *            The {@link IFile file} whose old {@link IMetaModelDescriptor meta-model descriptor} is to be returned.
+	 * @return The old {@link IMetaModelDescriptor meta-model descriptor} of given {@link IFile}, or <code>null</code>
+	 *         {@link IFile file} hadn't had any {@link IMetaModelDescriptor meta-model descriptor} before it was changed or
+	 *         deleted.
+	 */
+	public IMetaModelDescriptor getOldDescriptor(org.eclipse.emf.common.util.URI uri) {
+		return fFileMetaModelDescriptorCache.getOldDescriptor(uri);
+	}
+
+	/**
+	 * @param eObject
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(EObject eObject) {
+		if (eObject != null) {
+			// Special handling for proxies representing EObjects of meta-models that extend Ecore (e.g., UML2); instead
+			// of being instances of the respective meta-model classes they may be instances of EClass and have proxy
+			// URIs starting with the namespace URI of the applicable meta-model package
+			if (eObject.eIsProxy() && eObject instanceof EClass) {
+				org.eclipse.emf.common.util.URI proxyURI = ((InternalEObject) eObject).eProxyURI();
+				EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(proxyURI.trimFragment().toString());
+				if (ePackage != null) {
+					return getDescriptor(ePackage);
+				}
+			}
+
+			// Retrieve and return meta-model descriptor from EClass behind given EObject unless it turns out that it is
+			// outdated
+			/*
+			 * !! Important Note !! This is necessary to return an appropriate results for EObjects from model files that are in
+			 * special intermediate states. An example of such an intermediate state is where a model file has been deleted but not
+			 * yet unloaded is requested. Returning the meta-model descriptor corresponding to the underlying EClass/EPackage would
+			 * be wrong because the underlying model file doesn't exist anymore and requesting the meta-model descriptor for that
+			 * file would result in null. We therefore need to detect such cases and return the meta-model descriptor corresponding
+			 * to the underlying model file instead.
+			 */
+			IMetaModelDescriptor descriptor = getDescriptor(eObject.eClass());
+			IMetaModelDescriptor oldDescriptor = getOldDescriptor(eObject.eResource());
+			if (descriptor != oldDescriptor) {
+				return descriptor;
+			} else {
+				// Try to retrieve an up to date meta-model descriptor from underlying file otherwise
+				IFile file = EcorePlatformUtil.getFile(eObject.eResource());
+				return getDescriptor(file);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * @param eClass
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(EClass eClass) {
+		if (eClass != null) {
+			return getDescriptor(eClass.getEPackage());
+		}
+		return null;
+	}
+
+	/**
+	 * @param eClass
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(EClassifier eClassifier) {
+		if (eClassifier != null) {
+			return getDescriptor(eClassifier.getEPackage());
+		}
+		return null;
+	}
+
+	/**
+	 * @param ePackage
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(EPackage ePackage) {
+		if (ePackage != null) {
+			synchronized (fPackageMetaModelDescriptorCache) {
+				IMetaModelDescriptor mmDescriptor = fPackageMetaModelDescriptorCache.get(ePackage);
+				if (mmDescriptor == null) {
+					try {
+						mmDescriptor = getDescriptor(new URI(ePackage.getNsURI()));
+						if (mmDescriptor != null) {
+							fPackageMetaModelDescriptorCache.put(ePackage, mmDescriptor);
+						} else {
+							fPackageMetaModelDescriptorCache.put(ePackage, NO_MM);
+						}
+					} catch (URISyntaxException ex) {
+						PlatformLogUtil.logAsError(Activator.getPlugin(), ex);
+					}
+				}
+				return mmDescriptor != NO_MM ? mmDescriptor : null;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * @param wrapperItemProvider
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(IWrapperItemProvider wrapperItemProvider) {
+		if (wrapperItemProvider != null) {
+			Object unwrapped = AdapterFactoryEditingDomain.unwrap(wrapperItemProvider);
+			IMetaModelDescriptor mmDescriptor = getDescriptor(unwrapped);
+			if (mmDescriptor != null) {
+				return mmDescriptor;
+			}
+			return getDescriptor(wrapperItemProvider.getOwner());
+		}
+		return null;
+	}
+
+	/**
+	 * @param entry
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(FeatureMap.Entry entry) {
+		Object unwrapped = AdapterFactoryEditingDomain.unwrap(entry);
+		return getDescriptor(unwrapped);
+	}
+
+	/**
+	 * @param transientItemProvider
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(TransientItemProvider transientItemProvider) {
+		if (transientItemProvider != null) {
+			Notifier target = transientItemProvider.getTarget();
+			return getDescriptor(target);
+		}
+		return null;
+	}
+
+	/**
+	 * @param namespaceURI
+	 * @return
+	 */
+	public IMetaModelDescriptor getDescriptor(final URI namespaceURI) {
+		if (namespaceURI != null) {
+			synchronized (getMetaModelDescriptors()) {
+				final String namespaceURIString = namespaceURI.toString();
+				IMetaModelDescriptor mmDescriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {
+					@Override
+					public boolean accept(IMetaModelDescriptor mmDescriptor) {
+						if (namespaceURIString.equals(mmDescriptor.getNamespace())) {
+							return true;
+						}
+						if (mmDescriptor.matchesEPackageNsURIPattern(namespaceURIString)) {
+							return true;
+						}
+						for (URI compatibleNamepaceURI : mmDescriptor.getCompatibleNamespaceURIs()) {
+							if (namespaceURIString.equals(compatibleNamepaceURI.toString())) {
+								return true;
+							}
+						}
+						for (IMetaModelDescriptor compatibleResourceVersionDescriptor : mmDescriptor.getCompatibleResourceVersionDescriptors()) {
+							if (namespaceURIString.equals(compatibleResourceVersionDescriptor.getNamespace())) {
+								return true;
+							}
+							if (compatibleResourceVersionDescriptor.matchesEPackageNsURIPattern(namespaceURIString)) {
+								return true;
+							}
+						}
+						return false;
+					}
+				});
+
+				// No static meta-model descriptor found?
+				if (mmDescriptor == null) {
+					// Try to retrieve Ecore model behind given namespace and dynamically create a new meta-model
+					// descriptor
+					EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(namespaceURIString);
+					if (ePackage != null) {
+						mmDescriptor = createDescriptor(ePackage);
+						addDescriptor(mmDescriptor);
+					}
+				}
+				return mmDescriptor;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * @param class
+	 * @return
+	 * @deprecated It is not recommended use this method because the {@link IMetaModelDescriptor metamodel descriptor}
+	 *             retrieval strategy implemented here has the side effect of that it triggers a full initialization of all
+	 *             {@link EPackage}s behind potentially all {@link IMetaModelDescriptor metamodel descriptor}s. This can
+	 *             have significant impact on runtime performance and may cause that the {@link EPackage}s of metamodels
+	 *             become initialized even though not a single instance of these metamodels exists in the workspace.
+	 */
+	@Deprecated
+	public IMetaModelDescriptor getDescriptor(final Class<?> clazz) {
+		if (clazz != null) {
+			IMetaModelDescriptor descriptor = getDescriptor(ANY_MM, new IDescriptorFilter() {
+				@Override
+				public boolean accept(IMetaModelDescriptor descriptor) {
+					// Test if the class name of one of the metamodel's EPackages is the prefix of the given class' name
+					for (EPackage ePackage : descriptor.getEPackages()) {
+						if (clazz.getName().startsWith(ePackage.getClass().getName())) {
+							return true;
+						}
+					}
+					return false;
+				}
+			});
+			return descriptor;
+		}
+		return null;
+	}
+
+	/**
+	 * @param mmDescriptor
+	 * @param filter
+	 * @return
+	 */
+	private <T extends IMetaModelDescriptor> T getDescriptor(T mmDescriptor, IDescriptorFilter filter) {
+		List<T> descriptors = getDescriptors(mmDescriptor);
+		for (int i = descriptors.size() - 1; i >= 0; i--) {
+			T descriptor = descriptors.get(i);
+			if (filter.accept(descriptor)) {
+				if (i < descriptors.size() - 1) {
+					// there is a very good chance that the next descriptor lookup to trigger the same descriptor,
+					// as a a result, moving the descriptor to the last position could improve the performance
+					synchronized (getMetaModelDescriptors()) {
+						getMetaModelDescriptors().remove(descriptor.getIdentifier());
+						getMetaModelDescriptors().put(descriptor.getIdentifier(), descriptor);
+					}
+				}
+				return descriptor;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Retrieves {@link IMetaModelDescriptor target meta-model descriptor} behind the given {@link IFile file}.
+	 *
+	 * @param file
+	 *            The {@link IFile file} to be investigated.
+	 * @return The {@link IFile file}'s {@link IMetaModelDescriptor target meta-model descriptor} or <code>null</code> if no
+	 *         such exists.
+	 */
+	public IMetaModelDescriptor getTargetDescriptor(IFile file) {
+		ITargetMetaModelDescriptorProvider provider = getTargetMetaModelDescriptorProvider(file);
+		if (provider != null) {
+			return provider.getDescriptor(file);
+		}
+		return null;
+	}
+
+	/**
+	 * Retrieves {@link IMetaModelDescriptor target meta-model descriptor} behind the given {@link Resource resource}.
+	 *
+	 * @param resource
+	 *            The {@link Resource resource} to be investigated.
+	 * @return The {@link Resource resource}'s {@link IMetaModelDescriptor target meta-model descriptor} or
+	 *         <code>null</code> if no such exists.
+	 */
+	public IMetaModelDescriptor getTargetDescriptor(Resource resource) {
+		ITargetMetaModelDescriptorProvider provider = getTargetMetaModelDescriptorProvider(resource);
+		if (provider != null) {
+			return provider.getDescriptor(resource);
+		}
+		return null;
+	}
+
+	/**
+	 * Retrieves the extensions of all file types which are associated with a {@link IMetaModelDescriptor target meta-model
+	 * descriptor}. Includes both file extensions for which a {@link IMetaModelDescriptor target meta-model descriptor} has
+	 * been specified directly and file extensions supported by content types for which a {@link IMetaModelDescriptor target
+	 * meta-model descriptor} has been defined.
+	 *
+	 * @return A {@link Collection collection} with all file types associated with a {@link IMetaModelDescriptor target
+	 *         meta-model descriptor} or an empty {@link Collection collection} if no such exist.
+	 * @deprecated use {@link MetaModelDescriptorRegistry#isContentTypeOfTargetDescriptorsApplicable(IFile)} instead
+	 */
+	@Deprecated
+	public Collection<String> getFileExtensionsAssociatedWithTargetDescriptors() {
+		Collection<String> extensions = new HashSet<String>(2);
+		extensions.addAll(getFileExtensionToTargetMetaModelDescriptorProviders().keySet());
+		for (String contentTypeId : getContentTypeIdToTargetMetaModelDescriptorProviders().keySet()) {
+			extensions.addAll(ExtendedPlatform.getContentTypeFileExtensions(contentTypeId));
+		}
+		return Collections.unmodifiableCollection(extensions);
+	}
+
+	/**
+	 * Returns true if the extension of the passed in file matches any extension of all file types which are associated with
+	 * a {@link IMetaModelDescriptor target meta-model descriptor}. Matching is done against both file extensions for which
+	 * a {@link IMetaModelDescriptor target meta-model descriptor} has been specified directly and file extensions supported
+	 * by content types for which a {@link IMetaModelDescriptor target meta-model descriptor} has been defined.
+	 *
+	 * @return true if the extensions any target descriptor content type match the passed in file's extension. false if the
+	 *         file is null or has no extension.
+	 */
+	public boolean isContentTypeOfTargetDescriptorsApplicable(IFile file) {
+		if (file == null) {
+			return false;
+		}
+
+		String extension = file.getFileExtension();
+		if (extension == null) {
+			return false;
+		}
+
+		if (getFileExtensionToTargetMetaModelDescriptorProviders().keySet().contains(extension)) {
+			return true;
+		}
+
+		for (String contentTypeId : getContentTypeIdToTargetMetaModelDescriptorProviders().keySet()) {
+			if (ExtendedPlatform.isContentTypeApplicable(contentTypeId, file)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	private ITargetMetaModelDescriptorProvider getTargetMetaModelDescriptorProvider(IFile file) {
+		try {
+			ITargetMetaModelDescriptorProvider provider = null;
+			if (file != null) {
+				String fileExtension = file.getFileExtension();
+				provider = getFileExtensionToTargetMetaModelDescriptorProviders().get(fileExtension);
+				if (provider == null) {
+					// Abort for files that are not in-sync. Reading the model namespace would trigger a refresh for
+					// out-of-sync files which would then trigger the model synchronizer via its resource change
+					// listener. This is not desirable at this point.
+					if (file.isSynchronized(IResource.DEPTH_ONE) == false) {
+						return null;
+					}
+					String contentTypeId = fastGetContentTypeId(file);
+					provider = getContentTypeIdToTargetMetaModelDescriptorProviders().get(contentTypeId);
+				}
+			}
+			return provider;
+		} catch (CoreException ex) {
+			// Ignore exception, just return null
+		}
+		return null;
+	}
+
+	private ITargetMetaModelDescriptorProvider getTargetMetaModelDescriptorProvider(Resource resource) {
+		IFile file = EcorePlatformUtil.getFile(resource);
+		return getTargetMetaModelDescriptorProvider(file);
+	}
+
+	/**
+	 * Retrieves {@link IMetaModelDescriptor meta-model descriptor} behind the given {@link IFile file} which will be
+	 * eventually effective or relevant to clients. This is the {@link IFile}'s {@link IMetaModelDescriptor target
+	 * meta-model descriptor} if such one is available or the {@link IFile}'s native {@link IMetaModelDescriptor meta-model
+	 * descriptor} otherwise.
+	 *
+	 * @param file
+	 *            The {@link IFile file} to be investigated.
+	 * @return The {@link IFile file}'s effective {@link IMetaModelDescriptor meta-model descriptor} or <code>null</code> if
+	 *         no such exists.
+	 */
+	public IMetaModelDescriptor getEffectiveDescriptor(IFile file) {
+		// Try to retrieve target meta-model descriptor
+		IMetaModelDescriptor descriptor = getTargetDescriptor(file);
+		if (descriptor == null) {
+			// Retrieve native meta-model descriptor otherwise
+			descriptor = getDescriptor(file);
+		}
+		return descriptor;
+	}
+
+	/**
+	 * Retrieves {@link IMetaModelDescriptor meta-model descriptor} behind the given {@link Resource resource} which will be
+	 * eventually effective or relevant to clients. This is the {@link IFile}'s {@link IMetaModelDescriptor target
+	 * meta-model descriptor} if such one is available or the {@link IFile}'s native {@link IMetaModelDescriptor meta-model
+	 * descriptor} otherwise.
+	 *
+	 * @param resource
+	 *            The {@link Resource resource} to be investigated.
+	 * @return The {@link Resource resource}'s effective {@link IMetaModelDescriptor meta-model descriptor} or
+	 *         <code>null</code> if no such exists.
+	 */
+	public IMetaModelDescriptor getEffectiveDescriptor(Resource resource) {
+		// Try to retrieve target meta-model descriptor
+		IMetaModelDescriptor descriptor = getTargetDescriptor(resource);
+		if (descriptor == null) {
+			// Retrieve native meta-model descriptor otherwise
+			descriptor = getDescriptor(resource);
+		}
+		return descriptor;
+	}
+
+	/**
+	 * Returns a {@link IMetaModelDescriptor descriptor} describing the version of specified {@link Resource resource}. This
+	 * is done by retrieving the resource's {@link EcoreResourceUtil#readModelNamespace(Resource) model namespace} and
+	 * finding a matching {@link IMetaModelDescriptor metamodel descriptor} or
+	 * {@link IMetaModelDescriptor#getCompatibleResourceVersionDescriptors() compatible resource version descriptor}.
+	 *
+	 * @param resource
+	 *            The {@link Resource resource} whose version descriptor is to be retrieved.
+	 * @return The resource's {@link IMetaModelDescriptor version descriptor} or <code>null</code> if no such could be
+	 *         determined.
+	 * @see EcoreResourceUtil#readModelNamespace(Resource)
+	 * @see #getCompatibleResourceVersionDescriptors()
+	 */
+	public IMetaModelDescriptor getResourceVersionDescriptor(Resource resource) {
+		try {
+			String resourceNamespace = EcoreResourceUtil.readModelNamespace(resource);
+			if (resourceNamespace != null) {
+				IMetaModelDescriptor mmDescriptor = getDescriptor(new URI(resourceNamespace));
+				if (mmDescriptor != null) {
+					// Newly created resources typically match implemented metamodel version exactly
+					if (resourceNamespace.equals(mmDescriptor.getNamespace())) {
+						return mmDescriptor;
+					}
+					if (mmDescriptor.matchesEPackageNsURIPattern(resourceNamespace)) {
+						return mmDescriptor;
+					}
+
+					// Resource version is older than but compatible with metamodel version
+					for (IMetaModelDescriptor compatibleResourceVersionDescriptor : mmDescriptor.getCompatibleResourceVersionDescriptors()) {
+						if (resourceNamespace.equals(compatibleResourceVersionDescriptor.getNamespace())) {
+							return compatibleResourceVersionDescriptor;
+						}
+						if (compatibleResourceVersionDescriptor.matchesEPackageNsURIPattern(resourceNamespace)) {
+							return compatibleResourceVersionDescriptor;
+						}
+					}
+				}
+			}
+		} catch (URISyntaxException ex) {
+			PlatformLogUtil.logAsError(Activator.getPlugin(), ex);
+		}
+		return null;
+	}
+
+	private synchronized void lazyInitialization() {
+		if (isInitialized == false) {
+			// already set isInitialized to true before actual initializaton to avoid infinite recursion
+			isInitialized = true;
+			readContributedDescriptors();
+			readAssociatedContentTypeIds();
+			readContributedTargetMetaModelDescriptorProviders();
+		}
+	}
+
+	private Map<String, IMetaModelDescriptor> getMetaModelDescriptors() {
+		lazyInitialization();
+		return fMetaModelDescriptors;
+	}
+
+	private Map<String, ITargetMetaModelDescriptorProvider> getContentTypeIdToTargetMetaModelDescriptorProviders() {
+		lazyInitialization();
+		return fContentTypeIdToTargetMetaModelDescriptorProviders;
+	}
+
+	private Map<String, ITargetMetaModelDescriptorProvider> getFileExtensionToTargetMetaModelDescriptorProviders() {
+		lazyInitialization();
+		return fFileExtensionToTargetMetaModelDescriptorProviders;
+	}
+
+	private Map<String, ITargetMetaModelDescriptorProvider> getAllTargetMetaModelDescriptorProviders() {
+		lazyInitialization();
+		return fAllTargetMetaModelDescriptorProviders;
+	}
+
+	/**
+	 *
+	 */
+	private interface IDescriptorFilter {
+
+		/**
+		 * @param descriptor
+		 * @return
+		 */
+		public boolean accept(IMetaModelDescriptor descriptor);
+	}
+
+	private class FileMetaModelDescriptorCache implements IFileMetaModelDescriptorCache {
+
+		/**
+		 * A cache of {@link IFile file}/{@link IMetaModelDescriptor meta-model descriptor} associations for accelerating
+		 * {@link IMetaModelDescriptor meta-model descriptor} retrieval.
+		 */
+		private Map<IFile, IMetaModelDescriptor> fFileMetaModelDescriptors = Collections.synchronizedMap(new HashMap<IFile, IMetaModelDescriptor>());
+
+		/**
+		 * A cache of {@link URI uri}/{@link IMetaModelDescriptor meta-model descriptor} associations for enabling retrieval of
+		 * old {@link IMetaModelDescriptor meta-model descriptor}s for resources which have been changed or deleted.
+		 */
+		private Map<org.eclipse.emf.common.util.URI, IMetaModelDescriptor> fOldFileMetaModelDescriptors = Collections
+				.synchronizedMap(new HashMap<org.eclipse.emf.common.util.URI, IMetaModelDescriptor>());
+
+		/*
+		 * @see org.eclipse.sphinx.emf.metamodel.InternalMetaModelDescriptorRegistry#addCachedMetaModelDescriptor(org.eclipse .
+		 * core.resources.IFile, org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor)
+		 */
+		@Override
+		public void addDescriptor(IFile file, IMetaModelDescriptor mmDescriptor) {
+			if (file != null) {
+				// Encode and cache given meta-model descriptor
+				fFileMetaModelDescriptors.put(file, mmDescriptor != null ? mmDescriptor : NO_MM);
+			}
+		}
+
+		boolean hasDescriptor(IFile file) {
+			if (file != null) {
+				return fFileMetaModelDescriptors.containsKey(file);
+			}
+			return false;
+		}
+
+		IMetaModelDescriptor getDescriptor(IFile file) {
+			if (file != null) {
+				IMetaModelDescriptor mmDescriptor = fFileMetaModelDescriptors.get(file);
+
+				// Decode and return cached meta-model descriptor
+				return mmDescriptor != NO_MM ? mmDescriptor : null;
+			}
+			return null;
+		}
+
+		/*
+		 * @see org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache#moveDescriptor(org.eclipse.core.
+		 * resources .IFile, org.eclipse.core.resources.IFile)
+		 */
+		@Override
+		public void moveDescriptor(IFile oldFile, IFile newFile) {
+			if (oldFile != null && newFile != null) {
+				synchronized (fFileMetaModelDescriptors) {
+					IMetaModelDescriptor mmDescriptor = fFileMetaModelDescriptors.remove(oldFile);
+					if (mmDescriptor != null) {
+						if (!mmDescriptor.equals(MetaModelDescriptorRegistry.NO_MM)) {
+							org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI
+									.createPlatformResourceURI(oldFile.getFullPath().toPortableString(), true);
+							fOldFileMetaModelDescriptors.put(uri, mmDescriptor);
+						}
+						/*
+						 * !! Important Note !! Don't keep old metamodel descriptor as metamodel descriptor for moved file because it might no
+						 * longer be a model file (e.g., because its extension has been changed)
+						 */
+					}
+				}
+
+				// Make sure that cached content id gets purged along with cached metamodel descriptor
+				/*
+				 * !! Important Note !! This should normally be the business of ContentTypeIdCachePurger. However, we have to do so here
+				 * as well because we must avoid that clients end up calling MetaModelDescriptorRegistry#getDescriptor(IFile) before
+				 * ContentTypeIdCachePurger has got an opportunity to do its job. Otherwise it could happen that the meta model
+				 * descriptor for the file in question gets retrieved from an obsolete but still cached content type id.
+				 */
+				ExtendedPlatform.removeCachedContentTypeId(newFile);
+			}
+		}
+
+		/*
+		 * @see org.eclipse.sphinx.emf.metamodel.InternalMetaModelDescriptorRegistry#removeCachedMetaModelDescriptor(org.
+		 * eclipse .core.resources.IFile)
+		 */
+		@Override
+		public void removeDescriptor(IFile file) {
+			if (file != null) {
+				synchronized (fFileMetaModelDescriptors) {
+					IMetaModelDescriptor removedMMDescriptor = fFileMetaModelDescriptors.remove(file);
+					if (removedMMDescriptor != null && !removedMMDescriptor.equals(MetaModelDescriptorRegistry.NO_MM)) {
+						org.eclipse.emf.common.util.URI uri = org.eclipse.emf.common.util.URI
+								.createPlatformResourceURI(file.getFullPath().toPortableString(), true);
+						fOldFileMetaModelDescriptors.put(uri, removedMMDescriptor);
+					}
+				}
+
+				// Make sure that cached content id gets purged along with cached metamodel descriptor
+				/*
+				 * !! Important Note !! This should normally be the business of ContentTypeIdCachePurger. However, we have to do so here
+				 * as well because we must avoid that clients end up calling MetaModelDescriptorRegistry#getDescriptor(IFile) before
+				 * ContentTypeIdCachePurger has got an opportunity to do its job. Otherwise it could happen that the meta model
+				 * descriptor for the file in question gets retrieved from an obsolete but still cached content type id.
+				 */
+				ExtendedPlatform.removeCachedContentTypeId(file);
+			}
+		}
+
+		IMetaModelDescriptor getOldDescriptor(org.eclipse.emf.common.util.URI uri) {
+			if (uri != null) {
+				return fOldFileMetaModelDescriptors.get(uri);
+			}
+			return null;
+		}
+
+		/*
+		 * @see org.eclipse.sphinx.emf.internal.metamodel.IFileMetaModelDescriptorCache#clearOldDescriptors()
+		 */
+		@Override
+		public void clearOldDescriptors() {
+			fOldFileMetaModelDescriptors.clear();
+		}
+	}
+
+	private static class DefaultMetaModelDescriptor extends AbstractMetaModelDescriptor {
+
+		protected DefaultMetaModelDescriptor(String identifier, String namespace, String name) {
+			super(identifier, namespace, name, null);
+		}
+
+		/*
+		 * @see org.eclipse.sphinx.emf.metamodel.AbstractMetaModelDescriptor#getDefaultContentTypeId()
+		 */
+		@Override
+		public String getDefaultContentTypeId() {
+			return ""; //$NON-NLS-1$
+		}
+	}
+
+	private static final class AnyMetaModelDescriptor extends DefaultMetaModelDescriptor {
+
+		public AnyMetaModelDescriptor() {
+			super("org.eclipse.sphinx.emf.metamodel.any", "http://any.mm", "Any metamodel"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+	}
+
+	private static final class NoMetaModelDescriptor extends DefaultMetaModelDescriptor {
+
+		public NoMetaModelDescriptor() {
+			super("org.eclipse.sphinx.emf.metamodel.no", "http://no.mm", "No metamodel"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+		}
+	}
+
+}
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceCache.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceCache.java
new file mode 100644
index 0000000..469e14e
--- /dev/null
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceCache.java
@@ -0,0 +1,134 @@
+/**
+ * <copyright>
+ *
+ * Copyright (c) {contributing company name} 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:
+ *     {contributing company name} - Initial API and implementation
+ *
+ * </copyright>
+ */
+package org.eclipse.sphinx.emf.scoping;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.sphinx.emf.Activator;
+import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
+import org.eclipse.sphinx.platform.resources.DefaultResourceChangeHandler;
+import org.eclipse.sphinx.platform.resources.ResourceDeltaVisitor;
+import org.eclipse.sphinx.platform.util.PlatformLogUtil;
+
+public class ProjectResourceCache {
+
+	class InvalidationListener implements IResourceChangeListener {
+		@Override
+		public void resourceChanged(IResourceChangeEvent event) {
+			try {
+				IResourceDelta delta = event.getDelta();
+				if (delta != null) {
+					IResourceDeltaVisitor visitor = new ResourceDeltaVisitor(event.getType(), new DefaultResourceChangeHandler() {
+						@Override
+						public void handleProjectCreated(int eventType, IProject project) {
+							invalidate();
+						}
+
+						@Override
+						public void handleProjectOpened(int eventType, IProject project) {
+							invalidate();
+						}
+
+						@Override
+						public void handleProjectRenamed(int eventType, IProject oldProject, IProject newProject) {
+							invalidate();
+						}
+
+						@Override
+						public void handleProjectDescriptionChanged(int eventType, IProject project) {
+							invalidate();
+						}
+
+						@Override
+						public void handleProjectClosed(int eventType, IProject project) {
+							invalidate();
+						}
+
+						@Override
+						public void handleProjectRemoved(int eventType, IProject project) {
+							invalidate();
+						}
+					});
+
+					delta.accept(visitor);
+				}
+			} catch (CoreException ex) {
+				PlatformLogUtil.logAsError(Activator.getDefault(), ex);
+			}
+		}
+	}
+
+	private final Map<IProject, Set<URI>> cache = new HashMap<IProject, Set<URI>>();
+	private InvalidationListener invalidationListener = null;
+
+	private final void buildCache(IProject project) {
+		try {
+			if (!cache.containsKey(project)) {
+				final Set<URI> resources = new HashSet<URI>();
+				if (project.exists() && project.isOpen()) {
+					project.accept(new IResourceVisitor() {
+
+						@Override
+						public boolean visit(IResource resource) throws CoreException {
+							if (resource instanceof IContainer) {
+								return true;
+							}
+							resources.add(EcorePlatformUtil.createURI(resource.getFullPath()));
+							return false;
+						}
+					});
+				}
+				cache.put(project, resources);
+
+			}
+			if (invalidationListener == null) {
+				invalidationListener = new InvalidationListener();
+				ResourcesPlugin.getWorkspace().addResourceChangeListener(invalidationListener);
+			}
+		} catch (CoreException ex) {
+			PlatformLogUtil.logAsError(Activator.getDefault(), ex);
+		}
+
+	}
+
+	private final void invalidate() {
+		if (invalidationListener != null) {
+			cache.clear();
+			ResourcesPlugin.getWorkspace().removeResourceChangeListener(invalidationListener);
+			invalidationListener = null;
+		}
+	}
+
+	public Set<URI> getResources(IProject project) {
+		buildCache(project);
+		return cache.containsKey(project) ? cache.get(project) : Collections.emptySet();
+	}
+
+}
diff --git a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceScope.java b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceScope.java
index 04df6ba..7481ec9 100644
--- a/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceScope.java
+++ b/plugins/org.eclipse.sphinx.emf/src/org/eclipse/sphinx/emf/scoping/ProjectResourceScope.java
@@ -1,178 +1,191 @@
-/**

- * <copyright>

- *

- * Copyright (c) 2008-2014 See4sys, itemis, BMW Car IT 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:

- *     See4sys - Initial API and implementation

- *     itemis - [346715] IMetaModelDescriptor methods of MetaModelDescriptorRegistry taking EObject or Resource arguments should not start new EMF transactions

- *     BMW Car IT - [373481] Performance optimizations for model loading. Added referenced projects cache.

- *     itemis - [421205] Model descriptor registry does not return correct model descriptor for (shared) plugin resources

- *     itemis - [425252] UML property section hangs when accessing reference property of a stereotype application

- *

- * </copyright>

- */

-package org.eclipse.sphinx.emf.scoping;

-

-import java.util.Collection;

-import java.util.Collections;

-

-import org.eclipse.core.resources.IFile;

-import org.eclipse.core.resources.IProject;

-import org.eclipse.core.resources.IResource;

-import org.eclipse.core.runtime.Assert;

-import org.eclipse.emf.common.util.URI;

-import org.eclipse.emf.ecore.resource.Resource;

-import org.eclipse.sphinx.emf.scoping.ProjectResourceScopeProvider.IReferencedProjectsProvider;

-import org.eclipse.sphinx.emf.scoping.ProjectResourceScopeProvider.ReferencedProjectsProvider;

-import org.eclipse.sphinx.emf.util.EcorePlatformUtil;

-import org.eclipse.sphinx.platform.util.ExtendedPlatform;

-

-public class ProjectResourceScope extends AbstractResourceScope {

-

-	protected IProject rootProject;

-

-	// Use a non-caching provider by default

-	protected IReferencedProjectsProvider referencedProjectsProvider = new ReferencedProjectsProvider();

-

-	public ProjectResourceScope(IResource resource) {

-		Assert.isNotNull(resource);

-		rootProject = resource.getProject();

-	}

-

-	protected void setReferencedProjectsProvider(IReferencedProjectsProvider referencedProjectsProvider) {

-		this.referencedProjectsProvider = referencedProjectsProvider;

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getRoot()

-	 */

-	@Override

-	public IResource getRoot() {

-		return rootProject;

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getReferencedRoots()

-	 */

-	@Override

-	@SuppressWarnings("unchecked")

-	public Collection<IResource> getReferencedRoots() {

-		if (rootProject != null) {

-			Collection<?> allReferencedProjects = referencedProjectsProvider.get(rootProject);

-			return (Collection<IResource>) allReferencedProjects;

-		} else {

-			return Collections.emptySet();

-		}

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getReferencingRoots()

-	 */

-	@Override

-	@SuppressWarnings("unchecked")

-	public Collection<IResource> getReferencingRoots() {

-		if (rootProject != null) {

-			Collection<?> allReferencingProjects = ExtendedPlatform.getAllReferencingProjects(rootProject);

-			return (Collection<IResource>) allReferencingProjects;

-		} else {

-			return Collections.emptySet();

-		}

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.core.resources.IFile, boolean)

-	 */

-	@Override

-	public boolean belongsTo(IFile file, boolean includeReferencedScopes) {

-		if (belongsToRootOrReferencedProjects(file, includeReferencedScopes)) {

-			return true;

-		}

-

-		if (isShared(file)) {

-			return true;

-		}

-

-		return false;

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.emf.ecore.resource.Resource, boolean)

-	 */

-	@Override

-	public boolean belongsTo(Resource resource, boolean includeReferencedScopes) {

-		IFile file = EcorePlatformUtil.getFile(resource);

-		if (belongsToRootOrReferencedProjects(file, includeReferencedScopes)) {

-			return true;

-		}

-

-		if (isShared(resource)) {

-			return true;

-		}

-

-		return false;

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.emf.common.util.URI, boolean)

-	 */

-	@Override

-	public boolean belongsTo(URI uri, boolean includeReferencedScopes) {

-		IFile file = EcorePlatformUtil.getFile(uri);

-		if (belongsToRootOrReferencedProjects(file, includeReferencedScopes)) {

-			return true;

-		}

-

-		if (isShared(uri)) {

-			return true;

-		}

-

-		return false;

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.core.resources.IFile, boolean)

-	 */

-	@Override

-	public boolean didBelongTo(IFile file, boolean includeReferencedScopes) {

-		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.emf.ecore.resource.Resource, boolean)

-	 */

-	@Override

-	public boolean didBelongTo(Resource resource, boolean includeReferencedScopes) {

-		IFile file = EcorePlatformUtil.getFile(resource);

-		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);

-	}

-

-	/*

-	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.emf.common.util.URI, boolean)

-	 */

-	@Override

-	public boolean didBelongTo(URI uri, boolean includeReferencedScopes) {

-		IFile file = EcorePlatformUtil.getFile(uri);

-		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);

-	}

-

-	protected boolean belongsToRootOrReferencedProjects(IFile file, boolean includeReferencedScopes) {

-		if (file != null) {

-			return rootProject.equals(file.getProject()) || includeReferencedScopes && getReferencedRoots().contains(file.getProject());

-		}

-		return false;

-	}

-

-	/**

-	 * @deprecated Use {@link #belongsToRootOrReferencedProjects(IFile, boolean)} instead.

-	 */

-	@Deprecated

-	protected boolean belongsToRootOrDependingProjects(IFile file, boolean includeReferencedScopes) {

-		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);

-	}

-

-}

+/**
+ * <copyright>
+ *
+ * Copyright (c) 2008-2014 See4sys, itemis, BMW Car IT 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:
+ *     See4sys - Initial API and implementation
+ *     itemis - [346715] IMetaModelDescriptor methods of MetaModelDescriptorRegistry taking EObject or Resource arguments should not start new EMF transactions
+ *     BMW Car IT - [373481] Performance optimizations for model loading. Added referenced projects cache.
+ *     itemis - [421205] Model descriptor registry does not return correct model descriptor for (shared) plugin resources
+ *     itemis - [425252] UML property section hangs when accessing reference property of a stereotype application
+ *
+ * </copyright>
+ */
+package org.eclipse.sphinx.emf.scoping;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.sphinx.emf.scoping.ProjectResourceScopeProvider.IReferencedProjectsProvider;
+import org.eclipse.sphinx.emf.scoping.ProjectResourceScopeProvider.ReferencedProjectsProvider;
+import org.eclipse.sphinx.platform.util.ExtendedPlatform;
+
+public class ProjectResourceScope extends AbstractResourceScope {
+
+	protected IProject rootProject;
+	private ProjectResourceCache resourceCache;
+
+	// Use a non-caching provider by default
+	protected IReferencedProjectsProvider referencedProjectsProvider = new ReferencedProjectsProvider();
+
+	public ProjectResourceScope(IResource resource) {
+		Assert.isNotNull(resource);
+		rootProject = resource.getProject();
+		resourceCache = new ProjectResourceCache();
+	}
+
+	protected void setReferencedProjectsProvider(IReferencedProjectsProvider referencedProjectsProvider) {
+		this.referencedProjectsProvider = referencedProjectsProvider;
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getRoot()
+	 */
+	@Override
+	public IResource getRoot() {
+		return rootProject;
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getReferencedRoots()
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public Collection<IResource> getReferencedRoots() {
+		if (rootProject != null) {
+			Collection<?> allReferencedProjects = referencedProjectsProvider.get(rootProject);
+			return (Collection<IResource>) allReferencedProjects;
+		} else {
+			return Collections.emptySet();
+		}
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#getReferencingRoots()
+	 */
+	@Override
+	@SuppressWarnings("unchecked")
+	public Collection<IResource> getReferencingRoots() {
+		if (rootProject != null) {
+			Collection<?> allReferencingProjects = ExtendedPlatform.getAllReferencingProjects(rootProject);
+			return (Collection<IResource>) allReferencingProjects;
+		} else {
+			return Collections.emptySet();
+		}
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.core.resources.IFile, boolean)
+	 */
+	@Override
+	public boolean belongsTo(IFile file, boolean includeReferencedScopes) {
+		if (belongsToRootOrReferencedProjects(file, includeReferencedScopes)) {
+			return true;
+		}
+
+		if (isShared(file)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.emf.ecore.resource.Resource, boolean)
+	 */
+	@Override
+	public boolean belongsTo(Resource resource, boolean includeReferencedScopes) {
+		if (belongsToRootOrReferencedProjects(resource.getURI(), includeReferencedScopes)) {
+			return true;
+		}
+
+		if (isShared(resource)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#belongsTo(org.eclipse.emf.common.util.URI, boolean)
+	 */
+	@Override
+	public boolean belongsTo(URI uri, boolean includeReferencedScopes) {
+		if (belongsToRootOrReferencedProjects(uri, includeReferencedScopes)) {
+			return true;
+		}
+
+		if (isShared(uri)) {
+			return true;
+		}
+
+		return false;
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.core.resources.IFile, boolean)
+	 */
+	@Override
+	public boolean didBelongTo(IFile file, boolean includeReferencedScopes) {
+		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.emf.ecore.resource.Resource, boolean)
+	 */
+	@Override
+	public boolean didBelongTo(Resource resource, boolean includeReferencedScopes) {
+		return belongsToRootOrReferencedProjects(resource.getURI(), includeReferencedScopes);
+	}
+
+	/*
+	 * @see org.eclipse.sphinx.emf.scoping.IResourceScope#didBelongTo(org.eclipse.emf.common.util.URI, boolean)
+	 */
+	@Override
+	public boolean didBelongTo(URI uri, boolean includeReferencedScopes) {
+		return belongsToRootOrReferencedProjects(uri, includeReferencedScopes);
+	}
+
+	protected boolean belongsToRootOrReferencedProjects(URI model, boolean includeReferencedScopes) {
+		if (model != null) {
+			if (resourceCache.getResources(rootProject).contains(model)) {
+				return true;
+			}
+			if (includeReferencedScopes) {
+				for (IResource referenced : getReferencedRoots()) {
+					if (resourceCache.getResources(referenced.getProject()).contains(model)) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	protected boolean belongsToRootOrReferencedProjects(IFile file, boolean includeReferencedScopes) {
+		if (file != null) {
+			return rootProject.equals(file.getProject()) || includeReferencedScopes && getReferencedRoots().contains(file.getProject());
+		}
+		return false;
+	}
+
+	/**
+	 * @deprecated Use {@link #belongsToRootOrReferencedProjects(IFile, boolean)} instead.
+	 */
+	@Deprecated
+	protected boolean belongsToRootOrDependingProjects(IFile file, boolean includeReferencedScopes) {
+		return belongsToRootOrReferencedProjects(file, includeReferencedScopes);
+	}
+
+}