KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > commands > ParameterizedCommand


1 /*******************************************************************************
2  * Copyright (c) 2005, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.core.commands;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21
22 import org.eclipse.core.commands.common.NotDefinedException;
23 import org.eclipse.core.internal.commands.util.Util;
24
25 /**
26  * <p>
27  * A command that has had one or more of its parameters specified. This class
28  * serves as a utility class for developers that need to manipulate commands
29  * with parameters. It handles the behaviour of generating a parameter map and a
30  * human-readable name.
31  * </p>
32  *
33  * @since 3.1
34  */

35 public final class ParameterizedCommand implements Comparable JavaDoc {
36
37     /**
38      * The constant integer hash code value meaning the hash code has not yet
39      * been computed.
40      */

41     private static final int HASH_CODE_NOT_COMPUTED = -1;
42
43     /**
44      * A factor for computing the hash code for all parameterized commands.
45      */

46     private static final int HASH_FACTOR = 89;
47
48     /**
49      * The seed for the hash code for all parameterized commands.
50      */

51     private static final int HASH_INITIAL = ParameterizedCommand.class
52             .getName().hashCode();
53
54     /**
55      * The index of the parameter id in the parameter values.
56      *
57      * @deprecated no longer used
58      */

59     public static final int INDEX_PARAMETER_ID = 0;
60
61     /**
62      * The index of the human-readable name of the parameter itself, in the
63      * parameter values.
64      *
65      * @deprecated no longer used
66      */

67     public static final int INDEX_PARAMETER_NAME = 1;
68
69     /**
70      * The index of the human-readable name of the value of the parameter for
71      * this command.
72      *
73      * @deprecated no longer used
74      */

75     public static final int INDEX_PARAMETER_VALUE_NAME = 2;
76
77     /**
78      * The index of the value of the parameter that the command can understand.
79      *
80      * @deprecated no longer used
81      */

82     public static final int INDEX_PARAMETER_VALUE_VALUE = 3;
83
84     /**
85      * Escapes special characters in the command id, parameter ids and parameter
86      * values for {@link #serialize()}. The special characters
87      * {@link CommandManager#PARAMETER_START_CHAR},
88      * {@link CommandManager#PARAMETER_END_CHAR},
89      * {@link CommandManager#ID_VALUE_CHAR},
90      * {@link CommandManager#PARAMETER_SEPARATOR_CHAR} and
91      * {@link CommandManager#ESCAPE_CHAR} are escaped by prepending a
92      * {@link CommandManager#ESCAPE_CHAR} character.
93      *
94      * @param rawText
95      * a <code>String</code> to escape special characters in for
96      * serialization.
97      * @return a <code>String</code> representing <code>rawText</code> with
98      * special serialization characters escaped
99      * @see CommandManager#unescape(String)
100      * @since 3.2
101      */

102     private static final String JavaDoc escape(final String JavaDoc rawText) {
103
104         // defer initialization of a StringBuffer until we know we need one
105
StringBuffer JavaDoc buffer = null;
106
107         for (int i = 0; i < rawText.length(); i++) {
108
109             char c = rawText.charAt(i);
110             switch (c) {
111             case CommandManager.PARAMETER_START_CHAR:
112             case CommandManager.PARAMETER_END_CHAR:
113             case CommandManager.ID_VALUE_CHAR:
114             case CommandManager.PARAMETER_SEPARATOR_CHAR:
115             case CommandManager.ESCAPE_CHAR:
116                 if (buffer == null) {
117                     buffer = new StringBuffer JavaDoc(rawText.substring(0, i));
118                 }
119                 buffer.append(CommandManager.ESCAPE_CHAR);
120                 buffer.append(c);
121                 break;
122             default:
123                 if (buffer != null) {
124                     buffer.append(c);
125                 }
126                 break;
127             }
128
129         }
130
131         if (buffer == null) {
132             return rawText;
133         }
134         return buffer.toString();
135     }
136
137     /**
138      * Generates every possible combination of parameter values for the given
139      * parameters. Parameters values that cannot be initialized are just
140      * ignored. Optional parameters are considered.
141      *
142      * @param startIndex
143      * The index in the <code>parameters</code> that we should
144      * process. This must be a valid index.
145      * @param parameters
146      * The parameters in to process; must not be <code>null</code>.
147      * @return A collection (<code>Collection</code>) of combinations (<code>List</code>
148      * of <code>Parameterization</code>).
149      */

150     private static final Collection JavaDoc expandParameters(final int startIndex,
151             final IParameter[] parameters) {
152         final int nextIndex = startIndex + 1;
153         final boolean noMoreParameters = (nextIndex >= parameters.length);
154
155         final IParameter parameter = parameters[startIndex];
156         final List JavaDoc parameterizations = new ArrayList JavaDoc();
157         if (parameter.isOptional()) {
158             parameterizations.add(null);
159         }
160         
161         IParameterValues values = null;
162         try {
163             values = parameter.getValues();
164         } catch (final ParameterValuesException e) {
165             if (noMoreParameters) {
166                 return parameterizations;
167             }
168
169             // Make recursive call
170
return expandParameters(nextIndex, parameters);
171         }
172         final Map JavaDoc parameterValues = values.getParameterValues();
173         final Iterator JavaDoc parameterValueItr = parameterValues.entrySet()
174                 .iterator();
175         while (parameterValueItr.hasNext()) {
176             final Map.Entry JavaDoc entry = (Map.Entry JavaDoc) parameterValueItr.next();
177             final Parameterization parameterization = new Parameterization(
178                     parameter, (String JavaDoc) entry.getValue());
179             parameterizations.add(parameterization);
180         }
181
182         // Check if another iteration will produce any more names.
183
final int parameterizationCount = parameterizations.size();
184         if (noMoreParameters) {
185             // This is it, so just return the current parameterizations.
186
for (int i = 0; i < parameterizationCount; i++) {
187                 final Parameterization parameterization = (Parameterization) parameterizations
188                         .get(i);
189                 final List JavaDoc combination = new ArrayList JavaDoc(1);
190                 combination.add(parameterization);
191                 parameterizations.set(i, combination);
192             }
193             return parameterizations;
194         }
195
196         // Make recursive call
197
final Collection JavaDoc suffixes = expandParameters(nextIndex, parameters);
198         while (suffixes.remove(null)) {
199             // just keep deleting the darn things.
200
}
201         if (suffixes.isEmpty()) {
202             // This is it, so just return the current parameterizations.
203
for (int i = 0; i < parameterizationCount; i++) {
204                 final Parameterization parameterization = (Parameterization) parameterizations
205                         .get(i);
206                 final List JavaDoc combination = new ArrayList JavaDoc(1);
207                 combination.add(parameterization);
208                 parameterizations.set(i, combination);
209             }
210             return parameterizations;
211         }
212         final Collection JavaDoc returnValue = new ArrayList JavaDoc();
213         final Iterator JavaDoc suffixItr = suffixes.iterator();
214         while (suffixItr.hasNext()) {
215             final List JavaDoc combination = (List JavaDoc) suffixItr.next();
216             final int combinationSize = combination.size();
217             for (int i = 0; i < parameterizationCount; i++) {
218                 final Parameterization parameterization = (Parameterization) parameterizations
219                         .get(i);
220                 final List JavaDoc newCombination = new ArrayList JavaDoc(combinationSize + 1);
221                 newCombination.add(parameterization);
222                 newCombination.addAll(combination);
223                 returnValue.add(newCombination);
224             }
225         }
226
227         return returnValue;
228     }
229
230     /**
231      * <p>
232      * Generates all the possible combinations of command parameterizations for
233      * the given command. If the command has no parameters, then this is simply
234      * a parameterized version of that command. If a parameter is optional, both
235      * the included and not included cases are considered.
236      * </p>
237      * <p>
238      * If one of the parameters cannot be loaded due to a
239      * <code>ParameterValuesException</code>, then it is simply ignored.
240      * </p>
241      *
242      * @param command
243      * The command for which the parameter combinations should be
244      * generated; must not be <code>null</code>.
245      * @return A collection of <code>ParameterizedCommand</code> instances
246      * representing all of the possible combinations. This value is
247      * never empty and it is never <code>null</code>.
248      * @throws NotDefinedException
249      * If the command is not defined.
250      */

251     public static final Collection JavaDoc generateCombinations(final Command command)
252             throws NotDefinedException {
253         final IParameter[] parameters = command.getParameters();
254         if (parameters == null) {
255             return Collections
256                     .singleton(new ParameterizedCommand(command, null));
257         }
258
259         final Collection JavaDoc expansion = expandParameters(0, parameters);
260         final Collection JavaDoc combinations = new ArrayList JavaDoc(expansion.size());
261         final Iterator JavaDoc expansionItr = expansion.iterator();
262         while (expansionItr.hasNext()) {
263             final List JavaDoc combination = (List JavaDoc) expansionItr.next();
264             if (combination == null) {
265                 combinations.add(new ParameterizedCommand(command, null));
266             } else {
267                 while (combination.remove(null)) {
268                     // Just keep removing while there are null entries left.
269
}
270                 if (combination.isEmpty()) {
271                     combinations.add(new ParameterizedCommand(command, null));
272                 } else {
273                     final Parameterization[] parameterizations = (Parameterization[]) combination
274                             .toArray(new Parameterization[combination.size()]);
275                     combinations.add(new ParameterizedCommand(command,
276                             parameterizations));
277                 }
278             }
279         }
280         
281         return combinations;
282     }
283
284     /**
285      * The base command which is being parameterized. This value is never
286      * <code>null</code>.
287      */

288     private final Command command;
289
290     /**
291      * The hash code for this object. This value is computed lazily, and marked
292      * as invalid when one of the values on which it is based changes.
293      */

294     private transient int hashCode = HASH_CODE_NOT_COMPUTED;
295
296     /**
297      * This is an array of parameterization defined for this command. This value
298      * may be <code>null</code> if the command has no parameters.
299      */

300     private final Parameterization[] parameterizations;
301
302     private String JavaDoc name;
303
304     /**
305      * Constructs a new instance of <code>ParameterizedCommand</code> with
306      * specific values for zero or more of its parameters.
307      *
308      * @param command
309      * The command that is parameterized; must not be
310      * <code>null</code>.
311      * @param parameterizations
312      * An array of parameterizations binding parameters to values for
313      * the command. This value may be <code>null</code>. This
314      * argument is not copied; if you need to make changes to it
315      * after constructing this parameterized command, then make a
316      * copy yourself.
317      */

318     public ParameterizedCommand(final Command command,
319             final Parameterization[] parameterizations) {
320         if (command == null) {
321             throw new NullPointerException JavaDoc(
322                     "A parameterized command cannot have a null command"); //$NON-NLS-1$
323
}
324
325         this.command = command;
326         this.parameterizations = (parameterizations == null || parameterizations.length == 0) ? null
327                 : parameterizations;
328     }
329
330     /*
331      * (non-Javadoc)
332      *
333      * @see java.lang.Comparable#compareTo(java.lang.Object)
334      */

335     public final int compareTo(final Object JavaDoc object) {
336         final ParameterizedCommand command = (ParameterizedCommand) object;
337         final boolean thisDefined = this.command.isDefined();
338         final boolean otherDefined = command.command.isDefined();
339         if (!thisDefined || !otherDefined) {
340             return Util.compare(thisDefined, otherDefined);
341         }
342
343         try {
344             final int compareTo = getName().compareTo(command.getName());
345             if (compareTo == 0) {
346                 return getId().compareTo(command.getId());
347             }
348             return compareTo;
349         } catch (final NotDefinedException e) {
350             throw new Error JavaDoc(
351                     "Concurrent modification of a command's defined state"); //$NON-NLS-1$
352
}
353     }
354
355     /*
356      * (non-Javadoc)
357      *
358      * @see java.lang.Object#equals(java.lang.Object)
359      */

360     public final boolean equals(final Object JavaDoc object) {
361         if (this == object) {
362             return true;
363         }
364
365         if (!(object instanceof ParameterizedCommand)) {
366             return false;
367         }
368
369         final ParameterizedCommand command = (ParameterizedCommand) object;
370         if (!Util.equals(this.command, command.command)) {
371             return false;
372         }
373
374         return Util.equals(this.parameterizations, command.parameterizations);
375     }
376
377     /**
378      * Executes this command with its parameters. This method will succeed
379      * regardless of whether the command is enabled or defined. It is
380      * preferrable to use {@link #executeWithChecks(Object, Object)}.
381      *
382      * @param trigger
383      * The object that triggered the execution; may be
384      * <code>null</code>.
385      * @param applicationContext
386      * The state of the application at the time the execution was
387      * triggered; may be <code>null</code>.
388      * @return The result of the execution; may be <code>null</code>.
389      * @throws ExecutionException
390      * If the handler has problems executing this command.
391      * @throws NotHandledException
392      * If there is no handler.
393      * @deprecated Please use {@link #executeWithChecks(Object, Object)}
394      * instead.
395      */

396     public final Object JavaDoc execute(final Object JavaDoc trigger,
397             final Object JavaDoc applicationContext) throws ExecutionException,
398             NotHandledException {
399         return command.execute(new ExecutionEvent(command, getParameterMap(),
400                 trigger, applicationContext));
401     }
402
403     /**
404      * Executes this command with its parameters. This does extra checking to
405      * see if the command is enabled and defined. If it is not both enabled and
406      * defined, then the execution listeners will be notified and an exception
407      * thrown.
408      *
409      * @param trigger
410      * The object that triggered the execution; may be
411      * <code>null</code>.
412      * @param applicationContext
413      * The state of the application at the time the execution was
414      * triggered; may be <code>null</code>.
415      * @return The result of the execution; may be <code>null</code>.
416      * @throws ExecutionException
417      * If the handler has problems executing this command.
418      * @throws NotDefinedException
419      * If the command you are trying to execute is not defined.
420      * @throws NotEnabledException
421      * If the command you are trying to execute is not enabled.
422      * @throws NotHandledException
423      * If there is no handler.
424      * @since 3.2
425      */

426     public final Object JavaDoc executeWithChecks(final Object JavaDoc trigger,
427             final Object JavaDoc applicationContext) throws ExecutionException,
428             NotDefinedException, NotEnabledException, NotHandledException {
429         return command.executeWithChecks(new ExecutionEvent(command,
430                 getParameterMap(), trigger, applicationContext));
431     }
432
433     /**
434      * Returns the base command. It is possible for more than one parameterized
435      * command to have the same identifier.
436      *
437      * @return The command; never <code>null</code>, but may be undefined.
438      */

439     public final Command getCommand() {
440         return command;
441     }
442
443     /**
444      * Returns the command's base identifier. It is possible for more than one
445      * parameterized command to have the same identifier.
446      *
447      * @return The command id; never <code>null</code>.
448      */

449     public final String JavaDoc getId() {
450         return command.getId();
451     }
452
453     /**
454      * Returns a human-readable representation of this command with all of its
455      * parameterizations.
456      *
457      * @return The human-readable representation of this parameterized command;
458      * never <code>null</code>.
459      * @throws NotDefinedException
460      * If the underlying command is not defined.
461      */

462     public final String JavaDoc getName() throws NotDefinedException {
463         if (name == null) {
464             final StringBuffer JavaDoc nameBuffer = new StringBuffer JavaDoc();
465             nameBuffer.append(command.getName());
466             if (parameterizations != null) {
467                 nameBuffer.append(" ("); //$NON-NLS-1$
468
final int parameterizationCount = parameterizations.length;
469                 for (int i = 0; i < parameterizationCount; i++) {
470                     final Parameterization parameterization = parameterizations[i];
471                     nameBuffer
472                             .append(parameterization.getParameter().getName());
473                     nameBuffer.append(": "); //$NON-NLS-1$
474
try {
475                         nameBuffer.append(parameterization.getValueName());
476                     } catch (final ParameterValuesException e) {
477                         /*
478                          * Just let it go for now. If someone complains we can
479                          * add more info later.
480                          */

481                     }
482
483                     // If there is another item, append a separator.
484
if (i + 1 < parameterizationCount) {
485                         nameBuffer.append(", "); //$NON-NLS-1$
486
}
487                 }
488                 nameBuffer.append(')');
489             }
490             name = nameBuffer.toString();
491         }
492         return name;
493     }
494
495     /**
496      * Returns the parameter map, as can be used to construct an
497      * <code>ExecutionEvent</code>.
498      *
499      * @return The map of parameter ids (<code>String</code>) to parameter
500      * values (<code>String</code>). This map is never
501      * <code>null</code>, but may be empty.
502      */

503     public final Map JavaDoc getParameterMap() {
504         if ((parameterizations == null) || (parameterizations.length == 0)) {
505             return Collections.EMPTY_MAP;
506         }
507
508         final Map JavaDoc parameterMap = new HashMap JavaDoc();
509         for (int i = 0; i < parameterizations.length; i++) {
510             final Parameterization parameterization = parameterizations[i];
511             parameterMap.put(parameterization.getParameter().getId(),
512                     parameterization.getValue());
513         }
514         return parameterMap;
515     }
516
517     /* (non-Javadoc)
518      * @see java.lang.Object#hashCode()
519      */

520     public final int hashCode() {
521         if (hashCode == HASH_CODE_NOT_COMPUTED) {
522             hashCode = HASH_INITIAL * HASH_FACTOR + Util.hashCode(command);
523             hashCode = hashCode * HASH_FACTOR;
524             if (parameterizations!=null) {
525                 for (int i = 0; i < parameterizations.length; i++) {
526                     hashCode += Util.hashCode(parameterizations[i]);
527                 }
528             }
529             if (hashCode == HASH_CODE_NOT_COMPUTED) {
530                 hashCode++;
531             }
532         }
533         return hashCode;
534     }
535
536     /**
537      * Returns a {@link String} containing the command id, parameter ids and
538      * parameter values for this {@link ParameterizedCommand}. The returned
539      * {@link String} can be stored by a client and later used to reconstruct an
540      * equivalent {@link ParameterizedCommand} using the
541      * {@link CommandManager#deserialize(String)} method.
542      * <p>
543      * The syntax of the returned {@link String} is as follows:
544      * </p>
545      *
546      * <blockquote>
547      * <code>serialization = <u>commandId</u> [ '(' parameters ')' ]</code><br>
548      * <code>parameters = parameter [ ',' parameters ]</code><br>
549      * <code>parameter = <u>parameterId</u> [ '=' <u>parameterValue</u> ]</code>
550      * </blockquote>
551      *
552      * <p>
553      * In the syntax above, sections inside square-brackets are optional. The
554      * characters in single quotes (<code>(</code>, <code>)</code>,
555      * <code>,</code> and <code>=</code>) indicate literal characters.
556      * </p>
557      * <p>
558      * <code><u>commandId</u></code> represents the command id encoded with
559      * separator characters escaped. <code><u>parameterId</u></code> and
560      * <code><u>parameterValue</u></code> represent the parameter ids and
561      * values encoded with separator characters escaped. The separator
562      * characters <code>(</code>, <code>)</code>, <code>,</code> and
563      * <code>=</code> are escaped by prepending a <code>%</code>. This
564      * requires <code>%</code> to be escaped, which is also done by prepending
565      * a <code>%</code>.
566      * </p>
567      * <p>
568      * The order of the parameters is not defined (and not important). A missing
569      * <code><u>parameterValue</u></code> indicates that the value of the
570      * parameter is <code>null</code>.
571      * </p>
572      * <p>
573      * For example, the string shown below represents a serialized parameterized
574      * command that can be used to show the Resource perspective:
575      * </p>
576      * <p>
577      * <code>org.eclipse.ui.perspectives.showPerspective(org.eclipse.ui.perspectives.showPerspective.perspectiveId=org.eclipse.ui.resourcePerspective)</code>
578      * </p>
579      * <p>
580      * This example shows the more general form with multiple parameters,
581      * <code>null</code> value parameters, and escaped <code>=</code> in the
582      * third parameter value.
583      * </p>
584      * <p>
585      * <code>command.id(param1.id=value1,param2.id,param3.id=esc%=val3)</code>
586      * </p>
587      *
588      * @return A string containing the escaped command id, parameter ids and
589      * parameter values; never <code>null</code>.
590      * @see CommandManager#deserialize(String)
591      * @since 3.2
592      */

593     public final String JavaDoc serialize() {
594         final String JavaDoc escapedId = escape(getId());
595
596         if ((parameterizations == null) || (parameterizations.length == 0)) {
597             return escapedId;
598         }
599
600         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(escapedId);
601         buffer.append(CommandManager.PARAMETER_START_CHAR);
602
603         for (int i = 0; i < parameterizations.length; i++) {
604
605             if (i > 0) {
606                 // insert separator between parameters
607
buffer.append(CommandManager.PARAMETER_SEPARATOR_CHAR);
608             }
609
610             final Parameterization parameterization = parameterizations[i];
611             final String JavaDoc parameterId = parameterization.getParameter().getId();
612             final String JavaDoc escapedParameterId = escape(parameterId);
613
614             buffer.append(escapedParameterId);
615
616             final String JavaDoc parameterValue = parameterization.getValue();
617             if (parameterValue != null) {
618                 final String JavaDoc escapedParameterValue = escape(parameterValue);
619                 buffer.append(CommandManager.ID_VALUE_CHAR);
620                 buffer.append(escapedParameterValue);
621             }
622         }
623
624         buffer.append(CommandManager.PARAMETER_END_CHAR);
625
626         return buffer.toString();
627     }
628
629     public final String JavaDoc toString() {
630         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
631         buffer.append("ParameterizedCommand("); //$NON-NLS-1$
632
buffer.append(command);
633         buffer.append(',');
634         buffer.append(parameterizations);
635         buffer.append(')');
636         return buffer.toString();
637     }
638 }
639
Popular Tags