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