blob: ce6ea626dde915e3b1778f8e0f01d4c75acb738e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 Willink Transformations 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:
* E.D.Willink - initial API and implementation
* E.D.Willink - Bug 360072
*******************************************************************************/
package org.eclipse.ocl.pivot.utilities;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.ENamedElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypeParameter;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.internal.labels.LabelSubstitutionLabelProvider;
import org.eclipse.ocl.pivot.labels.AbstractLabelGenerator;
//import org.eclipse.ocl.ecore.Constraint;
//import org.eclipse.ocl.ecore.delegate.InvocationBehavior;
//import org.eclipse.ocl.ecore.delegate.SettingBehavior;
//import org.eclipse.ocl.utilities.UMLReflection;
import org.eclipse.ocl.pivot.labels.ILabelGenerator;
import org.eclipse.ocl.pivot.labels.LabelGeneratorRegistry;
public class LabelUtil
{
/**
* The global QUALIFIED_NAME_REGISTRY is used by qualifiedNameFor to generate qualified names
* for objects; typically a :: separted hierarchical name. The QUALIFIED_NAME_REGISTRY delegates unsupported
* label generation to the SIMPLE_NAME_REGISTRY.
*/
public static ILabelGenerator.@NonNull Registry QUALIFIED_NAME_REGISTRY = new LabelGeneratorRegistry(ILabelGenerator.Registry.INSTANCE);
/**
* The global SIMPLE_NAME_REGISTRY is used by simpleNameFor to generate simple names
* for objects; typically the name property. The SIMPLE_NAME_REGISTRY delegates unsupported
* label generation to the global ILabelGenerator.Registry.INSTANCE.
*/
public static ILabelGenerator.@NonNull Registry SIMPLE_NAME_REGISTRY = new LabelGeneratorRegistry(ILabelGenerator.Registry.INSTANCE);
/**
* A SubstitutionLabelProvider instance that uses LaberlUtil.getLabel() to provide labels.
*/
public static EValidator.@NonNull SubstitutionLabelProvider SUBSTITUTION_LABEL_PROVIDER = new LabelSubstitutionLabelProvider();
static {
/**
* Install an ENamedElement label generator that suppresses hierarchy.
*/
SIMPLE_NAME_REGISTRY.install(ENamedElement.class, new AbstractLabelGenerator<ENamedElement>(ENamedElement.class)
{
@Override
public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull ENamedElement labelledObject) {
String name = labelledObject.getName();
if (name != null)
labelBuilder.appendString(name);
else {
labelBuilder.appendString("<null-named-");
labelBuilder.appendString(labelledObject.getClass().getSimpleName());
labelBuilder.appendString(">");
}
}
});
/**
* Install an ENamedElement label generator that :: separates hierarchical names.
*/
QUALIFIED_NAME_REGISTRY.install(ENamedElement.class, new AbstractLabelGenerator<ENamedElement>(ENamedElement.class)
{
@Override
public void buildLabelFor(@NonNull Builder labelBuilder, @NonNull ENamedElement labelledObject) {
String name = labelledObject.getName();
if (name != null)
labelBuilder.appendString(name);
else {
labelBuilder.appendString("<null-named-");
labelBuilder.appendString(labelledObject.getClass().getSimpleName());
labelBuilder.appendString(">");
}
}
});
}
public static <E extends EObject> E copy(E newObject) {
return EcoreUtil.copy(newObject);
}
/**
* Return a context map for use by EValidator.validate in which the EVlaidator.class key
* is mapped to the eValidator, and the EValidator.SubstitutionLabelProvider.class key
* is mapped to a SubstitutionLabelProvider that uses getLabel().
*/
public static @NonNull Map<Object, Object> createDefaultContext(EValidator eValidator) {
Map<Object, Object> context = new HashMap<Object, Object>();
context.put(EValidator.SubstitutionLabelProvider.class, LabelUtil.SUBSTITUTION_LABEL_PROVIDER);
context.put(EValidator.class, eValidator);
return context;
}
/**
* Convert the map return from EcoreUtil.UnresolvedProxyCrossReferencer.find(xx)
* into a textual diagnosis.
* <br>
* Returns null if there are no unresolved URIs.
* <br>
* Returns a String containing a title line containing the contextURI and
* subsequent lines identifying each distinct unresolved URI.
*/
public static @Nullable String diagnoseUnresolvedProxies(@NonNull URI contextURI, @NonNull Map<EObject, Collection<EStructuralFeature.Setting>> map) {
if (map.isEmpty())
return null;
Map<String, Map.Entry<EObject, Collection<EStructuralFeature.Setting>>> unresolvedURIs = new HashMap<String, Map.Entry<EObject, Collection<EStructuralFeature.Setting>>>(map.size());
for (Map.Entry<EObject, Collection<EStructuralFeature.Setting>> entry : map.entrySet()) {
EObject key = entry.getKey();
URI uri = EcoreUtil.getURI(key);
String uriString = uri.toString();
if (!unresolvedURIs.containsKey(uriString))
unresolvedURIs.put(uriString, entry);
}
StringBuilder s = new StringBuilder();
s.append("Unresolved URIs in '" + String.valueOf(contextURI) + "' :");
for (Map.Entry<String, Map.Entry<EObject, Collection<EStructuralFeature.Setting>>> unresolvedURI : unresolvedURIs.entrySet())
s.append("\n '" + unresolvedURI.getKey() + "'");
return s.toString();
}
public static @Nullable <T extends Adapter> T getAdapter(@Nullable Notifier notifier, Class<T> adapterClass) {
if (notifier == null)
return null;
return getAdapter(notifier.eAdapters(), adapterClass);
}
@SuppressWarnings("unchecked")
public static <T extends Adapter> T getAdapter(List<Adapter> eAdapters, Class<T> adapterClass) {
return (T) EcoreUtil.getAdapter(eAdapters, adapterClass);
}
/**
* Return the specialised value of feature.getEType() resolving any type parameters
* from the specialised type of the sourceObject of the feature.
*
* @param sourceObject
* @param feature
*/
public static EClassifier getEType(EObject sourceObject, @NonNull EStructuralFeature feature) {
EGenericType targetGenericType = feature.getEGenericType();
ETypeParameter targetTypeParameter = targetGenericType.getETypeParameter();
if ((targetTypeParameter != null) && (sourceObject != null)) {
EClass sourceGenericType = feature.getEContainingClass();
EObject typeParameterContainer = targetTypeParameter.eContainer();
EClass sourceClass = sourceObject.eClass();
EList<EGenericType> allSourceGenericSuperTypes = sourceClass.getEAllGenericSuperTypes();
for (EGenericType sourceGenericSuperType : allSourceGenericSuperTypes) {
if (sourceGenericSuperType.getERawType() == typeParameterContainer) {
EList<EGenericType> sourceTypeArguments = sourceGenericSuperType.getETypeArguments();
int i = sourceGenericType.getETypeParameters().indexOf(targetTypeParameter);
if ((0 <= i) && (i < sourceTypeArguments.size())) {
EGenericType sourceTypeArgument = sourceTypeArguments.get(i);
return sourceTypeArgument.getERawType();
}
}
}
}
return targetGenericType.getERawType();
}
/**
* Return the Ecore EStringToStringMapEntry that realises a given Constraint.
*
* @param constraint the constraint
* @return the annotation detail entry, null if not found
*
public static Map.Entry<String, String> getEAnnotationDetail(Constraint constraint) {
List<EModelElement> constrainedElements = constraint.getConstrainedElements();
if (constrainedElements.isEmpty()) {
return null;
}
EModelElement constrainedElement = constrainedElements.get(0);
String keyName;
String stereotype = constraint.getStereotype();
if (UMLReflection.INVARIANT.equals(stereotype)) {
keyName = constraint.getName();
if (constrainedElement instanceof EClass) {
EOperation apiOperation = EcoreUtils.getEcoreInvariant((EClass) constrainedElement, keyName);
if (apiOperation != null) {
constrainedElement = apiOperation;
keyName = InvocationBehavior.BODY_CONSTRAINT_KEY;
}
}
}
else if (UMLReflection.DERIVATION.equals(stereotype)){
keyName = SettingBehavior.DERIVATION_CONSTRAINT_KEY;
}
else if (UMLReflection.INITIAL.equals(stereotype)){
keyName = SettingBehavior.INITIAL_CONSTRAINT_KEY;
}
else if (UMLReflection.BODY.equals(stereotype)){
keyName = InvocationBehavior.BODY_CONSTRAINT_KEY;
}
// else if (UMLReflection.PRECONDITION.equals(stereotype)){
// node = InvocationBehavior.PRECONDITION_CONSTRAINT_KEY;
// }
// else if (UMLReflection.POSTCONDITION.equals(stereotype)){
// node = InvocationBehavior.POSTCONDITION_CONSTRAINT_KEY;
// }
else {
keyName = null;
}
EAnnotation eAnnotation = OCLCommon.getDelegateAnnotation(constrainedElement);
if (eAnnotation == null) {
return null;
}
EMap<String, String> details = eAnnotation.getDetails();
if (keyName != null) {
int indexOfKey = details.indexOfKey(keyName);
if (indexOfKey >= 0) {
return details.get(indexOfKey);
}
}
return null;
} */
/**
* Return the EOperation that realises the name invariant for eClass.
* @param eClass with invariant
* @param name of invariant
* @return the EOperation or null
*/
public static @Nullable EOperation getEcoreInvariant(@NonNull EClass eClass, @NonNull String name) {
for (EOperation eOperation : eClass.getEOperations()) {
if (ClassUtil.safeEquals(name, eOperation.getName()) && EcoreUtil.isInvariant(eOperation)) {
return eOperation;
}
}
return null;
}
public static <T> int getFeatureID(@NonNull Notification notification, @Nullable T expectedNotifier, @NonNull Class<T> featureClass) {
if (expectedNotifier == null)
return Notification.NO_FEATURE_ID;
Object notifier = notification.getNotifier();
if (notifier != expectedNotifier)
return Notification.NO_FEATURE_ID;
@Nullable T castNotifier = ClassUtil.asClassOrNull(notifier, featureClass);
if (castNotifier == null)
throw new IllegalArgumentException("EcoreUtils.getFeatureID: " + featureClass.getName() + " for a " + notifier.getClass().getName());
return notification.getFeatureID(featureClass);
}
/**
* Return a simple readable description of eObject using an IItemLabelProvider if possible.
*/
public static String getLabel(@Nullable Object object) {
if (object instanceof Labelable) {
String text = ((Labelable)object).getText();
if (text != null) {
return text;
}
}
return NameUtil.qualifiedNameFor(object);
}
/**
* Return a simple readable description of object. If non-null eClassifier
* identifies the type of object. If non-null context may provide an ESubstitutionLabelProvider.
*/
public static String getLabel(EClassifier eClassifier, Object object, Map<Object, Object> context) {
if (eClassifier instanceof EDataType) {
return EObjectValidator.getValueLabel((EDataType) eClassifier, object, context);
}
else if (object instanceof EObject) {
if (context != null) { // Use an ESubstitutionLabelProvider
return EObjectValidator.getObjectLabel((EObject)object, context);
}
else { // Use an ItemProvider rather than EcoreUtil.getIdentification
return LabelUtil.getLabel(object);
}
}
else { // Never happens
return String.valueOf(object);
}
}
}