| /******************************************************************************* |
| * Copyright (c) 2010, 2014 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 |
| *******************************************************************************/ |
| package org.eclipse.ocl.pivot.labels; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.plugin.EcorePlugin; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.internal.labels.BooleanLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.DynamicEObjectImplLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.EAnnotationLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.EGenericTypeLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.ENamedElementLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.EObjectLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.EcoreURILabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.ElementIdLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.ExpressionInOCLLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.ModelLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.NameableLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.NumberLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.StringLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.labels.ValueLabelGenerator; |
| import org.eclipse.ocl.pivot.internal.plugin.LabelGeneratorRegistryReader; |
| import org.eclipse.ocl.pivot.labels.ILabelGenerator.Descriptor; |
| |
| /** |
| * DebugString supports generation of debug identification of objects, determining a name usuing |
| * the following alternatives. |
| * <br>The null object is identified as <null-Object> |
| * <br>Implementers of IDebugString are identified by IDebugString.toDebugString(); |
| * <br>MethodCall registrations in DebugUtils are identified by MethodCall.invoke(). |
| * <br>Other objects are identified as <unknown-'class-name' 'object.toString()'> |
| * <p> |
| * MethodCall registrations may be made via registerInstanceMethod or registerStaticMethod. |
| * <p> |
| * A debug string may be obtained via DebugString.toDebug(object). |
| * <p> |
| * DebugString providers string formatters for simple classes such as String, Number, Boolean |
| * and Ecore components such as EObject, Resource and ResourceSet. |
| * <p> |
| * User extensions should be registered prior to use. Beware that late registration can |
| * give misleading results since in the absence of an exact MethodCall registration the |
| * class hierarchy is search first for base classes then for instances for which there |
| * is an exact MethodCall match. This result is then cached and so may occlude a late |
| * registration. |
| */ |
| public class LabelGeneratorRegistry implements ILabelGenerator.Registry |
| { |
| public static class Global extends LabelGeneratorRegistry |
| { |
| private boolean initialized = false; |
| |
| public Global() {} |
| |
| public void initialize() { |
| initialized = true; |
| if (EcorePlugin.IS_ECLIPSE_RUNNING) { |
| new LabelGeneratorRegistryReader(this).readRegistry(); |
| } |
| else { |
| initialize(this); |
| } |
| } |
| |
| @Override |
| public @Nullable ILabelGenerator<?> get(@NonNull Class<?> labelledClass) { |
| if (!initialized) { |
| initialize(); |
| } |
| return super.get(labelledClass); |
| } |
| |
| @Override |
| public @Nullable Object install(@NonNull Class<?> labelledClass, @NonNull Descriptor labelDescriptor) { |
| if (!initialized) { |
| initialize(); |
| } |
| return super.install(labelledClass, labelDescriptor); |
| } |
| |
| @Override |
| public @Nullable Object install(@NonNull Class<?> labelledClass, @NonNull ILabelGenerator<?> labelGenerator) { |
| if (!initialized) { |
| initialize(); |
| } |
| return super.install(labelledClass, labelGenerator); |
| } |
| |
| @Override |
| public void uninstall(@NonNull Class<?> labelledClass) { |
| if (!initialized) { |
| initialize(); |
| } |
| super.uninstall(labelledClass); |
| } |
| } |
| |
| public static @NonNull String debugLabelFor(@NonNull Object object) { |
| Map<ILabelGenerator.Option<?>, Object> options = new HashMap<ILabelGenerator.Option<?>, Object>(); |
| options.put(ILabelGenerator.Builder.SHOW_CLASS_SIMPLE_NAME, Boolean.TRUE); |
| ILabelGenerator.Builder result = new DefaultLabelGeneratorBuilder(INSTANCE, object, options); |
| result.buildLabelFor(object); |
| return result.toString(); |
| } |
| |
| public static @NonNull LabelGeneratorRegistry init() { |
| return new LabelGeneratorRegistry.Global(); |
| } |
| |
| public static void initialize(@NonNull ILabelGenerator.Registry registry) { |
| BooleanLabelGenerator.initialize(registry); |
| DynamicEObjectImplLabelGenerator.initialize(registry); |
| EAnnotationLabelGenerator.initialize(registry); |
| EGenericTypeLabelGenerator.initialize(registry); |
| ENamedElementLabelGenerator.initialize(registry); |
| EObjectLabelGenerator.initialize(registry); |
| EcoreURILabelGenerator.initialize(registry); |
| ElementIdLabelGenerator.initialize(registry); |
| ExpressionInOCLLabelGenerator.initialize(registry); |
| ModelLabelGenerator.initialize(registry); |
| NameableLabelGenerator.initialize(registry); |
| NumberLabelGenerator.initialize(registry); |
| StringLabelGenerator.initialize(registry); |
| ValueLabelGenerator.initialize(registry); |
| } |
| |
| protected final @Nullable ILabelGenerator.Registry delegate; |
| private final @NonNull Map<Class<?>, Object> map = new HashMap<Class<?>, Object>(); |
| |
| /** |
| * Construct a registry that resolves label generators locally. |
| */ |
| private LabelGeneratorRegistry() { |
| this.delegate = null; |
| } |
| |
| /** |
| * Construct a registry that resolves label generators locally when possible |
| * but which delegates to delegate otherwise. |
| */ |
| public LabelGeneratorRegistry(@Nullable ILabelGenerator.Registry delegate) { |
| this.delegate = delegate; |
| } |
| |
| @Override |
| public <T> void buildLabelFor(@NonNull ILabelGenerator.Builder s, @Nullable T labelledObject) { |
| if (labelledObject == null) { |
| s.appendString("<null-Object>"); |
| return; |
| } |
| Boolean showClassName = s.getOption(ILabelGenerator.Builder.SHOW_CLASS_NAME); |
| if ((showClassName != null) && (showClassName == Boolean.TRUE)) { |
| s.appendString(labelledObject.getClass().getName()); |
| s.appendString(" "); |
| } |
| else { |
| Boolean showClassSimpleName = s.getOption(ILabelGenerator.Builder.SHOW_CLASS_SIMPLE_NAME); |
| if ((showClassSimpleName != null) && (showClassSimpleName == Boolean.TRUE)) { |
| s.appendString(labelledObject.getClass().getSimpleName()); |
| s.appendString(" "); |
| } |
| } |
| if (labelledObject instanceof EObject) { |
| EObject eContainer = ((EObject)labelledObject).eContainer(); |
| if (eContainer != null) { |
| String showQualifier = s.getOption(ILabelGenerator.Builder.SHOW_QUALIFIER); |
| if (showQualifier != null) { |
| buildLabelFor(s, eContainer); |
| if (s.toString().length() > 0) { |
| s.appendString(showQualifier); |
| } |
| } |
| } |
| } |
| if (labelledObject instanceof ILabelGenerator.Self) { |
| ((ILabelGenerator.Self)labelledObject).buildLabel(s); |
| return; |
| } |
| buildSubLabelFor(s, labelledObject); |
| } |
| |
| @Override |
| public <T> void buildSubLabelFor(@NonNull ILabelGenerator.Builder labelBuilder, @Nullable T labelledObject) { |
| if (labelledObject == null) { |
| labelBuilder.appendString("<null-Object>"); |
| return; |
| } |
| @SuppressWarnings("null")@NonNull Class<? extends Object> labelledObjectClass = labelledObject.getClass(); |
| ILabelGenerator<?> labelGenerator = get(labelledObjectClass); |
| if (labelGenerator == null) { |
| labelGenerator = getLabelGenerator(labelledObjectClass); |
| if (labelGenerator != null) |
| install(labelledObjectClass, labelGenerator); |
| } |
| if (labelGenerator != null) { |
| @SuppressWarnings("unchecked") |
| ILabelGenerator<T> castLabelGenerator = (ILabelGenerator<T>) labelGenerator; |
| castLabelGenerator.buildLabelFor(labelBuilder, labelledObject); |
| return; |
| } |
| else { |
| getLabelGenerator(labelledObjectClass); // Debugging |
| } |
| labelBuilder.appendString("<unknown-"); |
| labelBuilder.appendString(labelledObjectClass.getSimpleName()); |
| labelBuilder.appendString(" "); |
| labelBuilder.appendString(labelledObject.toString()); |
| labelBuilder.appendString(">"); |
| } |
| |
| public @NonNull ILabelGenerator.Builder createDefaultLabelBuilder(@Nullable Object labelledObject, @Nullable Map<ILabelGenerator.Option<?>, Object> options) { |
| return new DefaultLabelGeneratorBuilder(this, labelledObject, options); |
| } |
| |
| @Override |
| public @Nullable ILabelGenerator<?> get(@NonNull Class<?> labelledClass) { |
| Object object; |
| synchronized(map) { |
| object = map.get(labelledClass); |
| if (object instanceof ILabelGenerator.Descriptor) { |
| object = ((ILabelGenerator.Descriptor)object).getLabelGenerator(); |
| map.put(labelledClass, object); |
| } |
| } |
| if (object != null) { |
| return (ILabelGenerator<?>)object; |
| } |
| else if (delegate != null) { |
| return delegate.get(labelledClass); |
| } |
| else { |
| return null; |
| } |
| } |
| |
| protected @Nullable ILabelGenerator<?> getLabelGenerator(@NonNull Class<?> cls) { |
| for (Class<?> sCls = cls; sCls != null; sCls = sCls.getSuperclass()) { |
| ILabelGenerator<?> labelGenerator = get(sCls); |
| if (labelGenerator != null) |
| return labelGenerator; |
| } |
| for (@SuppressWarnings("null")@NonNull Class<?> iCls : cls.getInterfaces()) { |
| ILabelGenerator<?> labelGenerator = get(iCls); |
| if (labelGenerator != null) |
| return labelGenerator; |
| } |
| for (@SuppressWarnings("null")@NonNull Class<?> iCls : cls.getInterfaces()) { |
| ILabelGenerator<?> labelGenerator = getLabelGenerator(iCls); |
| if (labelGenerator != null) |
| return labelGenerator; |
| } |
| Class<?> sCls = cls.getSuperclass(); |
| if (sCls != null) |
| return getLabelGenerator(sCls); |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object install(@NonNull Class<?> labelledClass, @NonNull Descriptor labelDescriptor) { |
| synchronized(map) { |
| return map.put(labelledClass, labelDescriptor); |
| } |
| } |
| |
| @Override |
| public @Nullable Object install(@NonNull Class<?> labelledClass, @NonNull ILabelGenerator<?> labelGenerator) { |
| synchronized(map) { |
| return map.put(labelledClass, labelGenerator); |
| } |
| } |
| |
| @Override |
| public @NonNull String labelFor(@Nullable Object labelledObject) { |
| ILabelGenerator.Builder labelBuilder = createDefaultLabelBuilder(labelledObject, null); |
| labelBuilder.buildLabelFor(labelledObject); |
| return labelBuilder.toString(); |
| } |
| |
| @Override |
| public @NonNull String labelFor(@Nullable Object labelledObject, @Nullable Map<ILabelGenerator.Option<?>, Object> options) { |
| ILabelGenerator.Builder labelBuilder = createDefaultLabelBuilder(labelledObject, options); |
| labelBuilder.buildLabelFor(labelledObject); |
| return labelBuilder.toString(); |
| } |
| |
| @Override |
| public void uninstall(@NonNull Class<?> labelledClass) { |
| synchronized(map) { |
| for (Class<?> aClass : new ArrayList<Class<?>>(map.keySet())) |
| { |
| if (labelledClass.isAssignableFrom(aClass)) { |
| map.remove(aClass); |
| } |
| } |
| } |
| } |
| } |