blob: 762caf1f1988fac76e0eb221beb950d57e9f1a79 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
******************************************************************************/
package org.eclipse.emf.emfstore.client.model.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
/**
* Uses all registered extensions to create a wrapper for the given element. <br>
* The factories are processed in the following order:<br>
* <li>Factories by nsURI</li><br>
* <li>Default factories</li>
*/
public class ModelElementWrapperDescriptor {
private static final String EP_ID = "org.eclipse.emf.emfstore.client.wrapperfactories";
private static final String NON_URI = "NON_URI";
private static final String ATT_CLASS = "class";
private static final String ATT_URI = "nsURI";
private static final ModelElementWrapperDescriptor INSTANCE = new ModelElementWrapperDescriptor();
private static Map<String, List<IModelElementWrapperFactory>> factoriesMap;
/**
* Returns the instance of this class.
*
* @return the instance
*/
public static ModelElementWrapperDescriptor getInstance() {
return INSTANCE;
}
/**
* Returns all currently registered provider. The implementation does not track extensions which are added after
* this snapshot.
*
* @return the map from uri to factory
*/
public static synchronized Map<String, List<IModelElementWrapperFactory>> getFactories() {
if (factoriesMap != null) {
return factoriesMap;
}
factoriesMap = new HashMap<String, List<IModelElementWrapperFactory>>();
IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(EP_ID).getExtensions();
for (int i = 0; i < extensions.length; i++) {
IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
for (int j = 0; j < configElements.length; j++) {
IConfigurationElement configurationElement = configElements[j];
try {
IModelElementWrapperFactory factory = (IModelElementWrapperFactory) configurationElement
.createExecutableExtension(ATT_CLASS);
String nsURI = getNsURI(configurationElement);
if (!factoriesMap.containsKey(nsURI)) {
factoriesMap.put(nsURI, new ArrayList<IModelElementWrapperFactory>());
}
List<IModelElementWrapperFactory> list = factoriesMap.get(nsURI);
list.add(factory);
} catch (CoreException e) {
WorkspaceUtil.logException("Creating the wrapperfactories ", e);
}
}
}
return factoriesMap;
}
/**
* Returns the nsURI from the {@link IConfigurationElement}.
*
* @param configurationElement
* @return
*/
private static String getNsURI(IConfigurationElement configurationElement) {
String nsURI = configurationElement.getAttribute(ATT_URI);
return nsURI != null ? nsURI : NON_URI;
}
/**
* Wraps the given {@link EObject}.
*
* @param container the container for which the toWrap should be wrapped or <code>null</code>.
* @param toWrap the {@link EObject} which should be wrapped.
* @return the wrapped element
*/
public EObject wrap(EObject container, EObject toWrap) {
ensureFactories();
return wrap(container, toWrap, new DefaultWrapHelper());
}
/**
* Wraps the given {@link EObject} for import purpose.
*
* @param container the container for which the toWrap should be wrapped or <code>null</code>.
* @param toWrap the {@link EObject} which should be wrapped.
* @param resourceUri the {@link URI} of the resource to import.
* @param resourceIndex - the index of the element inside the eResource.
* @return the wrapped element
*/
public EObject wrapForImport(EObject container, EObject toWrap, URI resourceUri, int resourceIndex) {
ensureFactories();
return wrap(container, toWrap, new ImportWrapHelper(resourceUri, resourceIndex));
}
/**
* Loads the factories if not loaded yet.
*/
private void ensureFactories() {
getFactories();
}
/**
* Wraps the toWrap using the wrapHelper.
*
* @param container container the container for which the toWrap should be wrapped or <code>null</code>.
* @param toWrap the {@link EObject} which should be wrapped.
* @param helper a wrap helper
* @return
*/
private EObject wrap(EObject container, EObject toWrap, WrapHelper helper) {
EObject wrapped;
if (toWrap == null) {
return null;
}
// use the nsURI of the toWrap to find a factory
String nsURI = toWrap.eClass().getEPackage().getNsURI();
if (factoriesMap.containsKey(nsURI)) {
List<IModelElementWrapperFactory> factories = factoriesMap.get(nsURI);
// iterate all the factories registered for the nsURI. The first matching wins.
for (IModelElementWrapperFactory factory : factories) {
if (factory.isFor(container, toWrap)) {
wrapped = helper.wrap(factory, container, toWrap);
if (wrapped != null) {
return wrapped;
}
}
}
}
// if the element could not be wrapped by its nsURI, try the default factories
return wrapWithoutNsURI(container, toWrap, helper);
}
/**
* Uses the factories which did not specify a nsURI to create the wrapper.
*
* @param container
* @param toWrap
* @param helper a wrap helper
* @return
*/
private EObject wrapWithoutNsURI(EObject container, EObject toWrap, WrapHelper helper) {
EObject wrapped = null;
if (factoriesMap.containsKey(NON_URI)) {
List<IModelElementWrapperFactory> factories = factoriesMap.get(NON_URI);
// iterate all the factories registered for the nsURI. The first matching wins.
for (IModelElementWrapperFactory factory : factories) {
if (factory.isFor(container, toWrap)) {
wrapped = helper.wrap(factory, container, toWrap);
if (wrapped != null) {
break;
}
}
}
}
return wrapped;
}
/**
* An abstraction for the different wrapping types.
*/
private interface WrapHelper {
EObject wrap(IModelElementWrapperFactory factory, EObject container, EObject toWrap);
}
/**
* Is used to wrap imported elements.
*/
private final class ImportWrapHelper implements WrapHelper {
private final URI uri;
private final int resourceIndex;
private ImportWrapHelper(URI uri, int resourceIndex) {
this.uri = uri;
this.resourceIndex = resourceIndex;
}
public EObject wrap(IModelElementWrapperFactory factory, EObject container, EObject toWrap) {
return factory.wrapForImport(toWrap, uri, resourceIndex);
}
}
/**
* To wrap default elements.
*/
private class DefaultWrapHelper implements WrapHelper {
public EObject wrap(IModelElementWrapperFactory factory, EObject container, EObject toWrap) {
return factory.wrap(toWrap);
}
}
}