/******************************************************************************* * Copyright (c) 2005, 2015 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.core.commands; import org.eclipse.core.commands.common.HandleObject; import org.eclipse.core.commands.common.NotDefinedException; import org.eclipse.core.internal.commands.util.Util; /** * <p> * Provides information about the type of a command parameter. Clients can use a * parameter type to check if an object matches the type of the parameter with * {@link #isCompatible(Object)} and can get an * {@link AbstractParameterValueConverter} to convert between objects matching * the parameter type and strings that encode the object's identity. * </p> * <p> * A command parameter is not required to declare a type. To determine if a * given parameter has a type, check if an {@link IParameter} implements * {@link ITypedParameter} and if so, use * {@link ITypedParameter#getParameterType()} like this: * </p> * * <pre> * IParameter parameter = // ... get IParameter from Command * if (parameter instanceof ITypedParameter) { * ParameterType type = ((ITypedParameter)parameter).getParameterType(); * if (type != null) { * // this parameter has a ParameterType * } * } * </pre> * * @see IParameter * @see ITypedParameter#getParameterType() * @since 3.2 */ @SuppressWarnings("rawtypes") public final class ParameterType extends HandleObject implements Comparable { /** * TODO: this was copied from * org.eclipse.core.internal.expressions.Expressions is there a better place * to reference this? * * @param element * The element to test; may be <code>null</code>. * @param type * The type against which we are testing;may be <code>null</code>. * @return <code>true</code> if the <code>element</code> is an instance * of <code>type</code>; <code>false</code> otherwise. */ private static final boolean isInstanceOf(final Object element, final String type) { // null isn't an instanceof of anything. if (element == null) { return false; } return isSubtype(element.getClass(), type); } /** * TODO: this was copied from * org.eclipse.core.internal.expressions.Expressions is there a better place * to reference this? * * @param clazz * The class to match; may be <code>null</code>. * @param type * The type against which we are testing;may be <code>null</code>. * @return <code>true</code> if the <code>element</code> is an instance * of <code>type</code>; <code>false</code> otherwise. */ private static final boolean isSubtype(final Class<?> clazz, final String type) { if (clazz.getName().equals(type)) { return true; } final Class<?> superClass = clazz.getSuperclass(); if (superClass != null && isSubtype(superClass, type)) { return true; } for (Class<?> classInterface : clazz.getInterfaces()) { if (isSubtype(classInterface, type)) { return true; } } return false; } /** * An {@link AbstractParameterValueConverter} for converting parameter * values between objects and strings. This may be <code>null</code>. */ private transient AbstractParameterValueConverter parameterTypeConverter; /** * A string specifying the object type of this parameter type. This will be * <code>null</code> when the parameter type is undefined but never null * when it is defined. */ private transient String type = null; /** * Constructs a new instance based on the given identifier. When a parameter * type is first constructed, it is undefined. Parameter types should only * be constructed by the {@link CommandManager} to ensure that the * identifier remains unique. * * @param id * The identifier for this type. This value must not be * <code>null</code>, and must be unique amongst all parameter * types. */ ParameterType(final String id) { super(id); } /** * Adds a listener to this parameter type that will be notified when its * state changes. * * @param listener * The listener to be added; must not be <code>null</code>. */ public final void addListener(final IParameterTypeListener listener) { addListenerObject(listener); } /** * Compares this parameter type with another object by comparing each of the * non-transient attributes. * * @param object * The object with which to compare; must be an instance of * {@link ParameterType}. * @return A negative integer, zero or a positive integer, if the object is * greater than, equal to or less than this parameter type. */ @Override public final int compareTo(final Object object) { final ParameterType castedObject = (ParameterType) object; int compareTo = Util.compare(defined, castedObject.defined); if (compareTo == 0) { compareTo = Util.compare(id, castedObject.id); } return compareTo; } /** * <p> * Defines this parameter type, setting the defined property to * <code>true</code>. * </p> * <p> * Notification is sent to all listeners that something has changed. * </p> * * @param type * a string identifying the Java object type for this parameter * type; <code>null</code> is interpreted as * <code>"java.lang.Object"</code> * @param parameterTypeConverter * an {@link AbstractParameterValueConverter} to perform * string/object conversions for parameter values; may be * <code>null</code> */ public final void define(final String type, final AbstractParameterValueConverter parameterTypeConverter) { final boolean definedChanged = !this.defined; this.defined = true; this.type = (type == null) ? Object.class.getName() : type; this.parameterTypeConverter = parameterTypeConverter; fireParameterTypeChanged(new ParameterTypeEvent(this, definedChanged)); } /** * Notifies all listeners that this parameter type has changed. This sends * the given event to all of the listeners, if any. * * @param event * The event to send to the listeners; must not be * <code>null</code>. */ private final void fireParameterTypeChanged(final ParameterTypeEvent event) { if (event == null) { throw new NullPointerException( "Cannot send a null event to listeners."); //$NON-NLS-1$ } if (!isListenerAttached()) { return; } for (Object listener : getListeners()) { final IParameterTypeListener parameterTypeListener = (IParameterTypeListener) listener; parameterTypeListener.parameterTypeChanged(event); } } /** * Returns the value converter associated with this parameter, if any. * * @return The parameter value converter, or <code>null</code> if there is * no value converter for this parameter. * @throws NotDefinedException * if the parameter type is not currently defined */ public final AbstractParameterValueConverter getValueConverter() throws NotDefinedException { if (!isDefined()) { throw new NotDefinedException( "Cannot use getValueConverter() with an undefined ParameterType"); //$NON-NLS-1$ } return parameterTypeConverter; } /** * Returns whether the provided value is compatible with this parameter * type. An object is compatible with a parameter type if the object is an * instance of the class defined as the parameter's type class. * * @param value * an object to check for compatibility with this parameter type; * may be <code>null</code>. * @return <code>true</code> if the value is compatible with this type, * <code>false</code> otherwise * @throws NotDefinedException * if the parameter type is not currently defined */ public boolean isCompatible(Object value) throws NotDefinedException { if (!isDefined()) { throw new NotDefinedException( "Cannot use isCompatible() with an undefined ParameterType"); //$NON-NLS-1$ } return isInstanceOf(value, type); } /** * Unregisters listener for changes to properties of this parameter type. * * @param listener * the instance to unregister. Must not be <code>null</code>. * If an attempt is made to unregister an instance which is not * already registered with this instance, no operation is * performed. */ public final void removeListener(final IParameterTypeListener listener) { removeListenerObject(listener); } /** * The string representation of this parameter type. For debugging purposes * only. This string should not be shown to an end user. * * @return The string representation; never <code>null</code>. */ @Override public final String toString() { if (string == null) { final StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("ParameterType("); //$NON-NLS-1$ stringBuffer.append(id); stringBuffer.append(','); stringBuffer.append(defined); stringBuffer.append(')'); string = stringBuffer.toString(); } return string; } /** * Makes this parameter type become undefined. Notification is sent to all * listeners. */ @Override public final void undefine() { string = null; final boolean definedChanged = defined; defined = false; type = null; parameterTypeConverter = null; fireParameterTypeChanged(new ParameterTypeEvent(this, definedChanged)); } }