All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.core.commands.ParameterizedCommand Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2005, 2010 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
 *     Benjamin Muskalla - bug 222861 [Commands] ParameterizedCommand#equals broken
 *******************************************************************************/

package org.eclipse.core.commands;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.internal.commands.util.Util;

/**
 * 

* A command that has had one or more of its parameters specified. This class * serves as a utility class for developers that need to manipulate commands * with parameters. It handles the behaviour of generating a parameter map and a * human-readable name. *

* * @since 3.1 */ public final class ParameterizedCommand implements Comparable { /** * The constant integer hash code value meaning the hash code has not yet * been computed. */ private static final int HASH_CODE_NOT_COMPUTED = -1; /** * A factor for computing the hash code for all parameterized commands. */ private static final int HASH_FACTOR = 89; /** * The seed for the hash code for all parameterized commands. */ private static final int HASH_INITIAL = ParameterizedCommand.class .getName().hashCode(); /** * The index of the parameter id in the parameter values. * * @deprecated no longer used */ public static final int INDEX_PARAMETER_ID = 0; /** * The index of the human-readable name of the parameter itself, in the * parameter values. * * @deprecated no longer used */ public static final int INDEX_PARAMETER_NAME = 1; /** * The index of the human-readable name of the value of the parameter for * this command. * * @deprecated no longer used */ public static final int INDEX_PARAMETER_VALUE_NAME = 2; /** * The index of the value of the parameter that the command can understand. * * @deprecated no longer used */ public static final int INDEX_PARAMETER_VALUE_VALUE = 3; /** * Escapes special characters in the command id, parameter ids and parameter * values for {@link #serialize()}. The special characters * {@link CommandManager#PARAMETER_START_CHAR}, * {@link CommandManager#PARAMETER_END_CHAR}, * {@link CommandManager#ID_VALUE_CHAR}, * {@link CommandManager#PARAMETER_SEPARATOR_CHAR} and * {@link CommandManager#ESCAPE_CHAR} are escaped by prepending a * {@link CommandManager#ESCAPE_CHAR} character. * * @param rawText * a String to escape special characters in for * serialization. * @return a String representing rawText with * special serialization characters escaped * @since 3.2 */ private static final String escape(final String rawText) { // defer initialization of a StringBuffer until we know we need one StringBuffer buffer = null; for (int i = 0; i < rawText.length(); i++) { char c = rawText.charAt(i); switch (c) { case CommandManager.PARAMETER_START_CHAR: case CommandManager.PARAMETER_END_CHAR: case CommandManager.ID_VALUE_CHAR: case CommandManager.PARAMETER_SEPARATOR_CHAR: case CommandManager.ESCAPE_CHAR: if (buffer == null) { buffer = new StringBuffer(rawText.substring(0, i)); } buffer.append(CommandManager.ESCAPE_CHAR); buffer.append(c); break; default: if (buffer != null) { buffer.append(c); } break; } } if (buffer == null) { return rawText; } return buffer.toString(); } /** * Generates every possible combination of parameter values for the given * parameters. Parameters values that cannot be initialized are just * ignored. Optional parameters are considered. * * @param startIndex * The index in the parameters that we should * process. This must be a valid index. * @param parameters * The parameters in to process; must not be null. * @return A collection (Collection) of combinations (List * of Parameterization). */ private static final Collection expandParameters(final int startIndex, final IParameter[] parameters) { final int nextIndex = startIndex + 1; final boolean noMoreParameters = (nextIndex >= parameters.length); final IParameter parameter = parameters[startIndex]; final List parameterizations = new ArrayList(); if (parameter.isOptional()) { parameterizations.add(null); } IParameterValues values = null; try { values = parameter.getValues(); } catch (final ParameterValuesException e) { if (noMoreParameters) { return parameterizations; } // Make recursive call return expandParameters(nextIndex, parameters); } final Map parameterValues = values.getParameterValues(); final Iterator parameterValueItr = parameterValues.entrySet() .iterator(); while (parameterValueItr.hasNext()) { final Map.Entry entry = (Map.Entry) parameterValueItr.next(); final Parameterization parameterization = new Parameterization( parameter, (String) entry.getValue()); parameterizations.add(parameterization); } // Check if another iteration will produce any more names. final int parameterizationCount = parameterizations.size(); if (noMoreParameters) { // This is it, so just return the current parameterizations. for (int i = 0; i < parameterizationCount; i++) { final Parameterization parameterization = (Parameterization) parameterizations .get(i); final List combination = new ArrayList(1); combination.add(parameterization); parameterizations.set(i, combination); } return parameterizations; } // Make recursive call final Collection suffixes = expandParameters(nextIndex, parameters); while (suffixes.remove(null)) { // just keep deleting the darn things. } if (suffixes.isEmpty()) { // This is it, so just return the current parameterizations. for (int i = 0; i < parameterizationCount; i++) { final Parameterization parameterization = (Parameterization) parameterizations .get(i); final List combination = new ArrayList(1); combination.add(parameterization); parameterizations.set(i, combination); } return parameterizations; } final Collection returnValue = new ArrayList(); final Iterator suffixItr = suffixes.iterator(); while (suffixItr.hasNext()) { final List combination = (List) suffixItr.next(); final int combinationSize = combination.size(); for (int i = 0; i < parameterizationCount; i++) { final Parameterization parameterization = (Parameterization) parameterizations .get(i); final List newCombination = new ArrayList(combinationSize + 1); newCombination.add(parameterization); newCombination.addAll(combination); returnValue.add(newCombination); } } return returnValue; } /** *

* Generates all the possible combinations of command parameterizations for * the given command. If the command has no parameters, then this is simply * a parameterized version of that command. If a parameter is optional, both * the included and not included cases are considered. *

*

* If one of the parameters cannot be loaded due to a * ParameterValuesException, then it is simply ignored. *

* * @param command * The command for which the parameter combinations should be * generated; must not be null. * @return A collection of ParameterizedCommand instances * representing all of the possible combinations. This value is * never empty and it is never null. * @throws NotDefinedException * If the command is not defined. */ public static final Collection generateCombinations(final Command command) throws NotDefinedException { final IParameter[] parameters = command.getParameters(); if (parameters == null) { return Collections .singleton(new ParameterizedCommand(command, null)); } final Collection expansion = expandParameters(0, parameters); final Collection combinations = new ArrayList(expansion.size()); final Iterator expansionItr = expansion.iterator(); while (expansionItr.hasNext()) { final List combination = (List) expansionItr.next(); if (combination == null) { combinations.add(new ParameterizedCommand(command, null)); } else { while (combination.remove(null)) { // Just keep removing while there are null entries left. } if (combination.isEmpty()) { combinations.add(new ParameterizedCommand(command, null)); } else { final Parameterization[] parameterizations = (Parameterization[]) combination .toArray(new Parameterization[combination.size()]); combinations.add(new ParameterizedCommand(command, parameterizations)); } } } return combinations; } /** * Take a command and a map of parameter IDs to values, and generate the * appropriate parameterized command. * * @param command * The command object. Must not be null. * @param parameters * A map of String parameter ids to objects. May be * null. * @return the parameterized command, or null if it could not * be generated * @since 3.4 */ public static final ParameterizedCommand generateCommand(Command command, Map parameters) { // no parameters if (parameters == null || parameters.isEmpty()) { return new ParameterizedCommand(command, null); } try { ArrayList parms = new ArrayList(); Iterator i = parameters.keySet().iterator(); // iterate over given parameters while (i.hasNext()) { String key = (String) i.next(); IParameter parameter = null; // get the parameter from the command parameter = command.getParameter(key); // if the parameter is defined add it to the parameter list if (parameter == null) { return null; } ParameterType parameterType = command.getParameterType(key); if (parameterType == null) { parms.add(new Parameterization(parameter, (String) parameters.get(key))); } else { AbstractParameterValueConverter valueConverter = parameterType .getValueConverter(); if (valueConverter != null) { String val = valueConverter.convertToString(parameters .get(key)); parms.add(new Parameterization(parameter, val)); } else { parms.add(new Parameterization(parameter, (String) parameters.get(key))); } } } // convert the parameters to an Parameterization array and create // the command return new ParameterizedCommand(command, (Parameterization[]) parms .toArray(new Parameterization[parms.size()])); } catch (NotDefinedException e) { } catch (ParameterValueConversionException e) { } return null; } /** * The base command which is being parameterized. This value is never * null. */ private final Command command; /** * The hash code for this object. This value is computed lazily, and marked * as invalid when one of the values on which it is based changes. */ private transient int hashCode = HASH_CODE_NOT_COMPUTED; /** * This is an array of parameterization defined for this command. This value * may be null if the command has no parameters. */ private final Parameterization[] parameterizations; private String name; /** * Constructs a new instance of ParameterizedCommand with * specific values for zero or more of its parameters. * * @param command * The command that is parameterized; must not be * null. * @param parameterizations * An array of parameterizations binding parameters to values for * the command. This value may be null. */ public ParameterizedCommand(final Command command, final Parameterization[] parameterizations) { if (command == null) { throw new NullPointerException( "A parameterized command cannot have a null command"); //$NON-NLS-1$ } this.command = command; IParameter[] parms = null; try { parms = command.getParameters(); } catch (NotDefinedException e) { // This should not happen. } if (parameterizations != null && parameterizations.length>0 && parms != null) { int parmIndex = 0; Parameterization[] params = new Parameterization[parameterizations.length]; for (int j = 0; j < parms.length; j++) { for (int i = 0; i < parameterizations.length; i++) { Parameterization pm = parameterizations[i]; if (parms[j].equals(pm.getParameter())) { params[parmIndex++] = pm; } } } this.parameterizations = params; } else { this.parameterizations = null; } } /* * (non-Javadoc) * * @see java.lang.Comparable#compareTo(java.lang.Object) */ public final int compareTo(final Object object) { final ParameterizedCommand command = (ParameterizedCommand) object; final boolean thisDefined = this.command.isDefined(); final boolean otherDefined = command.command.isDefined(); if (!thisDefined || !otherDefined) { return Util.compare(thisDefined, otherDefined); } try { final int compareTo = getName().compareTo(command.getName()); if (compareTo == 0) { return getId().compareTo(command.getId()); } return compareTo; } catch (final NotDefinedException e) { throw new Error( "Concurrent modification of a command's defined state"); //$NON-NLS-1$ } } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public final boolean equals(final Object object) { if (this == object) { return true; } if (!(object instanceof ParameterizedCommand)) { return false; } final ParameterizedCommand command = (ParameterizedCommand) object; if (!Util.equals(this.command, command.command)) { return false; } return Util.equals(this.parameterizations, command.parameterizations); } /** * Executes this command with its parameters. This method will succeed * regardless of whether the command is enabled or defined. It is * preferrable to use {@link #executeWithChecks(Object, Object)}. * * @param trigger * The object that triggered the execution; may be * null. * @param applicationContext * The state of the application at the time the execution was * triggered; may be null. * @return The result of the execution; may be null. * @throws ExecutionException * If the handler has problems executing this command. * @throws NotHandledException * If there is no handler. * @deprecated Please use {@link #executeWithChecks(Object, Object)} * instead. */ public final Object execute(final Object trigger, final Object applicationContext) throws ExecutionException, NotHandledException { return command.execute(new ExecutionEvent(command, getParameterMap(), trigger, applicationContext)); } /** * Executes this command with its parameters. This does extra checking to * see if the command is enabled and defined. If it is not both enabled and * defined, then the execution listeners will be notified and an exception * thrown. * * @param trigger * The object that triggered the execution; may be * null. * @param applicationContext * The state of the application at the time the execution was * triggered; may be null. * @return The result of the execution; may be null. * @throws ExecutionException * If the handler has problems executing this command. * @throws NotDefinedException * If the command you are trying to execute is not defined. * @throws NotEnabledException * If the command you are trying to execute is not enabled. * @throws NotHandledException * If there is no handler. * @since 3.2 */ public final Object executeWithChecks(final Object trigger, final Object applicationContext) throws ExecutionException, NotDefinedException, NotEnabledException, NotHandledException { return command.executeWithChecks(new ExecutionEvent(command, getParameterMap(), trigger, applicationContext)); } /** * Returns the base command. It is possible for more than one parameterized * command to have the same identifier. * * @return The command; never null, but may be undefined. */ public final Command getCommand() { return command; } /** * Returns the command's base identifier. It is possible for more than one * parameterized command to have the same identifier. * * @return The command id; never null. */ public final String getId() { return command.getId(); } /** * Returns a human-readable representation of this command with all of its * parameterizations. * * @return The human-readable representation of this parameterized command; * never null. * @throws NotDefinedException * If the underlying command is not defined. */ public final String getName() throws NotDefinedException { if (name == null) { final StringBuffer nameBuffer = new StringBuffer(); nameBuffer.append(command.getName()); if (parameterizations != null) { nameBuffer.append(" ("); //$NON-NLS-1$ final int parameterizationCount = parameterizations.length; if(parameterizationCount == 1) { appendParameter(nameBuffer, parameterizations[0], false); }else { for (int i = 0; i < parameterizationCount; i++) { appendParameter(nameBuffer, parameterizations[i], true); // If there is another item, append a separator. if (i + 1 < parameterizationCount) { nameBuffer.append(", "); //$NON-NLS-1$ } } } nameBuffer.append(')'); } name = nameBuffer.toString(); } return name; } private void appendParameter(final StringBuffer nameBuffer, final Parameterization parameterization, boolean shouldAppendName) { if(shouldAppendName) { nameBuffer .append(parameterization.getParameter().getName()); nameBuffer.append(": "); //$NON-NLS-1$ } try { nameBuffer.append(parameterization.getValueName()); } catch (final ParameterValuesException e) { /* * Just let it go for now. If someone complains we can * add more info later. */ } } /** * Returns the parameter map, as can be used to construct an * ExecutionEvent. * * @return The map of parameter ids (String) to parameter * values (String). This map is never * null, but may be empty. */ public final Map getParameterMap() { if ((parameterizations == null) || (parameterizations.length == 0)) { return Collections.EMPTY_MAP; } final Map parameterMap = new HashMap(); for (int i = 0; i < parameterizations.length; i++) { final Parameterization parameterization = parameterizations[i]; parameterMap.put(parameterization.getParameter().getId(), parameterization.getValue()); } return parameterMap; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public final int hashCode() { if (hashCode == HASH_CODE_NOT_COMPUTED) { hashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(command); hashCode = hashCode * HASH_FACTOR; if (parameterizations != null) { for (int i = 0; i < parameterizations.length; i++) { hashCode += Util.hashCode(parameterizations[i]); } } if (hashCode == HASH_CODE_NOT_COMPUTED) { hashCode++; } } return hashCode; } /** * Returns a {@link String} containing the command id, parameter ids and * parameter values for this {@link ParameterizedCommand}. The returned * {@link String} can be stored by a client and later used to reconstruct an * equivalent {@link ParameterizedCommand} using the * {@link CommandManager#deserialize(String)} method. *

* The syntax of the returned {@link String} is as follows: *

* *
* serialization = commandId [ '(' parameters ')' ]
* parameters = parameter [ ',' parameters ]
* parameter = parameterId [ '=' parameterValue ] *
* *

* In the syntax above, sections inside square-brackets are optional. The * characters in single quotes ((, ), * , and =) indicate literal characters. *

*

* commandId represents the command id encoded with * separator characters escaped. parameterId and * parameterValue represent the parameter ids and * values encoded with separator characters escaped. The separator * characters (, ), , and * = are escaped by prepending a %. This * requires % to be escaped, which is also done by prepending * a %. *

*

* The order of the parameters is not defined (and not important). A missing * parameterValue indicates that the value of the * parameter is null. *

*

* For example, the string shown below represents a serialized parameterized * command that can be used to show the Resource perspective: *

*

* org.eclipse.ui.perspectives.showPerspective(org.eclipse.ui.perspectives.showPerspective.perspectiveId=org.eclipse.ui.resourcePerspective) *

*

* This example shows the more general form with multiple parameters, * null value parameters, and escaped = in the * third parameter value. *

*

* command.id(param1.id=value1,param2.id,param3.id=esc%=val3) *

* * @return A string containing the escaped command id, parameter ids and * parameter values; never null. * @see CommandManager#deserialize(String) * @since 3.2 */ public final String serialize() { final String escapedId = escape(getId()); if ((parameterizations == null) || (parameterizations.length == 0)) { return escapedId; } final StringBuffer buffer = new StringBuffer(escapedId); buffer.append(CommandManager.PARAMETER_START_CHAR); for (int i = 0; i < parameterizations.length; i++) { if (i > 0) { // insert separator between parameters buffer.append(CommandManager.PARAMETER_SEPARATOR_CHAR); } final Parameterization parameterization = parameterizations[i]; final String parameterId = parameterization.getParameter().getId(); final String escapedParameterId = escape(parameterId); buffer.append(escapedParameterId); final String parameterValue = parameterization.getValue(); if (parameterValue != null) { final String escapedParameterValue = escape(parameterValue); buffer.append(CommandManager.ID_VALUE_CHAR); buffer.append(escapedParameterValue); } } buffer.append(CommandManager.PARAMETER_END_CHAR); return buffer.toString(); } public final String toString() { final StringBuffer buffer = new StringBuffer(); buffer.append("ParameterizedCommand("); //$NON-NLS-1$ buffer.append(command); buffer.append(','); buffer.append(parameterizations); buffer.append(')'); return buffer.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy