blob: 91f70179df4a8bfc57a3467e2dd4e1c4b58e56bc [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.emf.core.internal.util;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.ResourceLocator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.gmf.runtime.common.core.util.Trace;
import org.eclipse.gmf.runtime.emf.core.internal.plugin.EMFCoreDebugOptions;
import org.eclipse.gmf.runtime.emf.core.internal.plugin.EMFCorePlugin;
/**
* This class manages meta-models and provide localization of meta-class names.
*
* @author rafikj
* @author Christian W. Damus (cdamus)
*/
public class MetamodelManager {
// used to get resource locators when none are provided to us
private static final ComposedAdapterFactory adapterFactory =
new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
private final static Map METAMODEL_MAP = new HashMap();
private final static Map REVERSE_METAMODEL_MAP = new HashMap();
/**
* Register meta-model object.
*/
public static void register(ENamedElement element) {
register(element, null);
}
/**
* Register meta-model object.
*/
public static void register(ENamedElement element,
ResourceLocator resourceLocator) {
if (element instanceof EOperation)
return;
if (element instanceof EParameter)
return;
String id = getNonCachedID(element);
String name = element.getName();
String displayName = null;
if ((resourceLocator == null) && (element instanceof EPackage)) {
// get a resource locator from the adapter factory registered
// against the IItemLabelProvider adapter type
resourceLocator = findResourceLocator((EPackage) element);
}
if (resourceLocator != null) {
if (element instanceof EClass) {
displayName = resourceLocator.getString("_UI_" + name //$NON-NLS-1$
+ "_type"); //$NON-NLS-1$
} else if (element instanceof EStructuralFeature) {
EClass eClass = ((EStructuralFeature) element)
.getEContainingClass();
if (eClass != null)
displayName = resourceLocator.getString("_UI_" //$NON-NLS-1$
+ eClass.getName() + "_" + name + "_feature"); //$NON-NLS-1$//$NON-NLS-2$
} else if (element instanceof EEnumLiteral) {
EEnum eEnum = ((EEnumLiteral) element).getEEnum();
if (eEnum != null)
displayName = resourceLocator.getString("_UI_" //$NON-NLS-1$
+ eEnum.getName() + "_" + name + "_literal"); //$NON-NLS-1$//$NON-NLS-2$
}
}
if (displayName == null)
displayName = name;
METAMODEL_MAP.put(element, new MetaModelDescriptor(id, displayName));
REVERSE_METAMODEL_MAP.put(id, element);
for (Iterator i = element.eContents().iterator(); i.hasNext();) {
Object child = i.next();
if (child instanceof ENamedElement)
register((ENamedElement) child, resourceLocator);
}
}
/**
* Attempts to find a resource locator for the specified metamodel package,
* using a heuristic that assumes that item-provider adapters implement
* the ResourceLocator interface (which is the default code generation).
*
* @param pkg a package for which we need a resource locator
*
* @return the resource locator if we could find one; <code>null</code> otherwise
*/
private static ResourceLocator findResourceLocator(EPackage pkg) {
ResourceLocator result = null;
// the compased adapter factory has a registry of pairs by EPackage
// and adapter class
List types = new java.util.ArrayList(2);
types.add(pkg);
types.add(IItemLabelProvider.class);
AdapterFactory factory = adapterFactory.getFactoryForTypes(types);
if (factory != null) {
// find some EClass to instantiate to get an item provider for it
EObject instance = null;
for (Iterator iter = pkg.getEClassifiers().iterator(); iter.hasNext();) {
Object next = iter.next();
if ((next instanceof EClass) && !((EClass) next).isAbstract()) {
instance = pkg.getEFactoryInstance().create((EClass) next);
break;
}
}
if (instance != null) {
Object adapter = factory.adapt(instance, IItemLabelProvider.class);
if (adapter instanceof ResourceLocator) {
result = (ResourceLocator) adapter;
}
}
}
return result;
}
/**
* Get the ID of a meta-model object.
*/
public static String getID(ENamedElement element) {
if (element instanceof EOperation) {
RuntimeException e = new IllegalArgumentException(
"EOperation does not support IDs"); //$NON-NLS-1$
Trace.throwing(EMFCorePlugin.getDefault(),
EMFCoreDebugOptions.EXCEPTIONS_THROWING, MetamodelManager.class,
"getID", e); //$NON-NLS-1$
throw e;
}
if (element instanceof EParameter) {
RuntimeException e = new IllegalArgumentException(
"EParameter does not support IDs"); //$NON-NLS-1$
Trace.throwing(EMFCorePlugin.getDefault(),
EMFCoreDebugOptions.EXCEPTIONS_THROWING, MetamodelManager.class,
"getID", e); //$NON-NLS-1$
throw e;
}
MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP
.get(element);
if (descriptor != null)
return descriptor.id;
return getNonCachedID(element);
}
/**
* Get the localized name of a meta-model object. Name does not contain
* spaces.
*/
public static String getLocalName(ENamedElement element) {
tryRegisterElement(element);
MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP
.get(element);
if (descriptor != null)
return descriptor.localName;
return element.getName();
}
/**
* Get the localized name of a meta-model object. Name may contain spaces.
*/
public static String getDisplayName(ENamedElement element) {
tryRegisterElement(element);
MetaModelDescriptor descriptor = (MetaModelDescriptor) METAMODEL_MAP
.get(element);
if (descriptor != null)
return descriptor.displayName;
return element.getName();
}
/**
* Find meta-model object given its ID.
*/
public static ENamedElement getElement(String id) {
ENamedElement result = (ENamedElement) REVERSE_METAMODEL_MAP.get(id);
if ((result == null) && (id != null)) {
// not registered, yet. Look it up in the registry
result = findInPackageRegistry(id);
}
return result;
}
/**
* Find the specified named element by ID in the global package registry.
* <b>Side-effect:</b> registers the package when found so that we don't
* need to do this again.
*
* @param id the ID to find. Must not be <code>null</code>
* @return the named element, or <code>null</code> if not found
*/
private static ENamedElement findInPackageRegistry(String id) {
ENamedElement result = null;
int dot = id.indexOf('.');
String pkgName = (dot >= 0)? id.substring(0, dot) : id;
for (Iterator iter = EPackage.Registry.INSTANCE.values().iterator(); iter.hasNext();) {
Object next = iter.next();
if (next instanceof EPackage) {
// skip descriptors because if the EPackage hasn't been
// instantiated then it cannot be in use by the client
EPackage pkg = (EPackage) next;
if (pkgName.equals(pkg.getName())) {
result = findElement(pkg, id);
if (result != null) {
// register the package for subsequent look-ups
register(pkg, null);
break;
}
}
}
}
return result;
}
private static ENamedElement findElement(ENamedElement element, String id) {
ENamedElement result = null;
int dot = id.indexOf('.');
if (dot < 0) {
if (id.equals(element.getName())) {
// got the final result
result = element;
} // else the element is not found here
} else {
String name = id.substring(0, dot);
if (name.equals(element.getName())) {
// search recursively in the sub-tree
id = id.substring(dot + 1);
for (Iterator iter = element.eContents().iterator();
(result == null) && iter.hasNext();) {
Object next = iter.next();
if (next instanceof ENamedElement) {
result = findElement((ENamedElement) next, id);
}
}
}
}
return result;
}
/**
* Get the non-cached ID of a meta-model object.
*/
private static String getNonCachedID(ENamedElement element) {
StringBuffer id = new StringBuffer();
ENamedElement current = element;
while (current != null) {
id.insert(0, current.getName());
EObject container = current.eContainer();
current = null;
if (container != null) {
if ((container instanceof ENamedElement)) {
current = (ENamedElement) container;
id.insert(0, '.');
} else {
// ENamedElements not contained by named elements (e.g.,
// contained in annotations) are not supported
return null;
}
}
}
return id.toString();
}
/**
* This class describes a meta-model object.
*/
private static class MetaModelDescriptor {
public String id = null;
public String localName = null;
public String displayName = null;
public MetaModelDescriptor(String id, String displayName) {
super();
this.id = id.intern();
this.localName = displayName.replaceAll(" ", "").intern(); //$NON-NLS-1$//$NON-NLS-2$
this.displayName = displayName.intern();
}
}
/**
* Registers the package an element belongs to. All elements of the package
* are registered with the package
*
* @param element An element that will be tried to get registered
*/
private static void tryRegisterElement(ENamedElement element)
{
// EOperation and EParameter can't have ids and hence cannot be registered
if (element instanceof EOperation || element instanceof EParameter)
return;
String id = getID(element);
if (id == null)
return;
int dot = id.indexOf('.');
// It is assumed that package names are equal to their IDs
String pkgName = (dot >= 0)? id.substring(0, dot) : id;
// If package is registered than no need to register it again
if (REVERSE_METAMODEL_MAP.get(pkgName)!=null)
return;
for (Iterator iter = EPackage.Registry.INSTANCE.values().iterator(); iter.hasNext();) {
Object next = iter.next();
if (next instanceof EPackage) {
// skip descriptors because if the EPackage hasn't been
// instantiated then it cannot be in use by the client
EPackage pkg = (EPackage) next;
if (pkgName.equals(pkg.getName())) {
register(pkg, null);
}
}
}
}
}