/******************************************************************************* * 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); } } }