KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > services > RegistryPersistence


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.ui.internal.services;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.List JavaDoc;
17
18 import org.eclipse.core.commands.Command;
19 import org.eclipse.core.commands.IParameter;
20 import org.eclipse.core.commands.Parameterization;
21 import org.eclipse.core.commands.ParameterizedCommand;
22 import org.eclipse.core.commands.common.NotDefinedException;
23 import org.eclipse.core.expressions.ElementHandler;
24 import org.eclipse.core.expressions.EvaluationResult;
25 import org.eclipse.core.expressions.Expression;
26 import org.eclipse.core.expressions.ExpressionConverter;
27 import org.eclipse.core.expressions.IEvaluationContext;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IConfigurationElement;
30 import org.eclipse.core.runtime.IExtensionRegistry;
31 import org.eclipse.core.runtime.IRegistryChangeEvent;
32 import org.eclipse.core.runtime.IRegistryChangeListener;
33 import org.eclipse.core.runtime.IStatus;
34 import org.eclipse.core.runtime.MultiStatus;
35 import org.eclipse.core.runtime.Platform;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.swt.widgets.Display;
38 import org.eclipse.ui.commands.ICommandService;
39 import org.eclipse.ui.internal.WorkbenchPlugin;
40 import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
41 import org.eclipse.ui.internal.util.Util;
42 import org.eclipse.ui.services.IDisposable;
43
44 /**
45  * <p>
46  * A manager for items parsed from the registry. This attaches a listener to the
47  * registry after the first read, and monitors the registry for changes from
48  * that point on. When {@link #dispose()} is called, the listener is detached.
49  * </p>
50  * <p>
51  * This class is only intended for internal use within the
52  * <code>org.eclipse.ui.workbench</code> plug-in.
53  * </p>
54  *
55  * @since 3.2
56  */

57 public abstract class RegistryPersistence implements IDisposable,
58         IWorkbenchRegistryConstants {
59
60     /**
61      * The expression to return when there is an error. Never <code>null</code>.
62      */

63     protected static final Expression ERROR_EXPRESSION = new Expression() {
64         public final EvaluationResult evaluate(final IEvaluationContext context) {
65             return null;
66         }
67     };
68
69     /**
70      * Inserts the given element into the indexed two-dimensional array in the
71      * array at the index. The array is grown as necessary.
72      *
73      * @param elementToAdd
74      * The element to add to the indexed array; may be
75      * <code>null</code>
76      * @param indexedArray
77      * The two-dimensional array that is indexed by element type;
78      * must not be <code>null</code>.
79      * @param index
80      * The index at which the element should be added; must be a
81      * valid index.
82      * @param currentCount
83      * The current number of items in the array at the index.
84      */

85     protected static final void addElementToIndexedArray(
86             final IConfigurationElement elementToAdd,
87             final IConfigurationElement[][] indexedArray, final int index,
88             final int currentCount) {
89         final IConfigurationElement[] elements;
90         if (currentCount == 0) {
91             elements = new IConfigurationElement[1];
92             indexedArray[index] = elements;
93         } else {
94             if (currentCount >= indexedArray[index].length) {
95                 final IConfigurationElement[] copy = new IConfigurationElement[indexedArray[index].length * 2];
96                 System.arraycopy(indexedArray[index], 0, copy, 0, currentCount);
97                 elements = copy;
98                 indexedArray[index] = elements;
99             } else {
100                 elements = indexedArray[index];
101             }
102         }
103         elements[currentCount] = elementToAdd;
104     }
105
106     /**
107      * Adds a warning to be logged at some later point in time.
108      *
109      * @param warningsToLog
110      * The collection of warnings to be logged; must not be
111      * <code>null</code>.
112      * @param message
113      * The mesaage to log; must not be <code>null</code>.
114      * @param element
115      * The element from which the warning originates; may be
116      * <code>null</code>.
117      */

118     protected static final void addWarning(final List JavaDoc warningsToLog,
119             final String JavaDoc message, final IConfigurationElement element) {
120         addWarning(warningsToLog, message, element, null, null, null);
121     }
122
123     /**
124      * Adds a warning to be logged at some later point in time. This logs the
125      * identifier of the item.
126      *
127      * @param warningsToLog
128      * The collection of warnings to be logged; must not be
129      * <code>null</code>.
130      * @param message
131      * The mesaage to log; must not be <code>null</code>.
132      * @param element
133      * The element from which the warning originates; may be
134      * <code>null</code>.
135      * @param id
136      * The identifier of the item for which a warning is being
137      * logged; may be <code>null</code>.
138      */

139     protected static final void addWarning(final List JavaDoc warningsToLog,
140             final String JavaDoc message, final IConfigurationElement element,
141             final String JavaDoc id) {
142         addWarning(warningsToLog, message, element, id, null, null);
143     }
144
145     /**
146      * Adds a warning to be logged at some later point in time. This logs the
147      * identifier of the item, as well as an extra attribute.
148      *
149      * @param warningsToLog
150      * The collection of warnings to be logged; must not be
151      * <code>null</code>.
152      * @param message
153      * The mesaage to log; must not be <code>null</code>.
154      * @param element
155      * The element from which the warning originates; may be
156      * <code>null</code>.
157      * @param id
158      * The identifier of the item for which a warning is being
159      * logged; may be <code>null</code>.
160      * @param extraAttributeName
161      * The name of extra attribute to be logged; may be
162      * <code>null</code>.
163      * @param extraAttributeValue
164      * The value of the extra attribute to be logged; may be
165      * <code>null</code>.
166      */

167     protected static final void addWarning(final List JavaDoc warningsToLog,
168             final String JavaDoc message, final IConfigurationElement element,
169             final String JavaDoc id, final String JavaDoc extraAttributeName,
170             final String JavaDoc extraAttributeValue) {
171         String JavaDoc statusMessage = message;
172         if (element != null) {
173             statusMessage = statusMessage
174                     + ": plug-in='" + element.getNamespace() + '\''; //$NON-NLS-1$
175
}
176         if (id != null) {
177             if (element != null) {
178                 statusMessage = statusMessage + ',';
179             } else {
180                 statusMessage = statusMessage + ':';
181             }
182             statusMessage = statusMessage + " id='" + id + '\''; //$NON-NLS-1$
183
}
184         if (extraAttributeName != null) {
185             if ((element != null) || (id != null)) {
186                 statusMessage = statusMessage + ',';
187             } else {
188                 statusMessage = statusMessage + ':';
189             }
190             statusMessage = statusMessage + ' ' + extraAttributeName + "='" //$NON-NLS-1$
191
+ extraAttributeValue + '\'';
192         }
193
194         final IStatus status = new Status(IStatus.WARNING,
195                 WorkbenchPlugin.PI_WORKBENCH, 0, statusMessage, null);
196         warningsToLog.add(status);
197     }
198
199     /**
200      * Checks that the class attribute or element exists for this element. This
201      * is used for executable extensions that are being read in.
202      *
203      * @param configurationElement
204      * The configuration element which should contain a class
205      * attribute or a class child element; must not be
206      * <code>null</code>.
207      * @param warningsToLog
208      * The list of warnings to be logged; never <code>null</code>.
209      * @param message
210      * The message to log if something goes wrong; may be
211      * <code>null</code>.
212      * @param id
213      * The identifier of the handle object; may be <code>null</code>.
214      * @return <code>true</code> if the class attribute or element exists;
215      * <code>false</code> otherwise.
216      */

217     protected static final boolean checkClass(
218             final IConfigurationElement configurationElement,
219             final List JavaDoc warningsToLog, final String JavaDoc message, final String JavaDoc id) {
220         // Check to see if we have a handler class.
221
if ((configurationElement.getAttribute(ATT_CLASS) == null)
222                 && (configurationElement.getChildren(TAG_CLASS).length == 0)) {
223             addWarning(warningsToLog, message, configurationElement, id);
224             return false;
225         }
226
227         return true;
228     }
229
230     /**
231      * Checks to see whether the configuration element represents a pulldown
232      * action. This involves reading the <code>style</code> and
233      * <code>pulldown</code> attributes.
234      *
235      * @param element
236      * The element to check; must not be <code>null</code>.
237      * @return <code>true</code> if the element is a pulldown action;
238      * <code>false</code> otherwise.
239      */

240     protected static final boolean isPulldown(
241             final IConfigurationElement element) {
242         final String JavaDoc style = readOptional(element, ATT_STYLE);
243         final boolean pulldown = readBoolean(element, ATT_PULLDOWN, false);
244         return (pulldown || STYLE_PULLDOWN.equals(style));
245     }
246
247     /**
248      * Logs any warnings in <code>warningsToLog</code>.
249      *
250      * @param warningsToLog
251      * The warnings to log; may be <code>null</code>.
252      * @param message
253      * The message to include in the log entry; must not be
254      * <code>null</code>.
255      */

256     protected static final void logWarnings(final List JavaDoc warningsToLog,
257             final String JavaDoc message) {
258         // If there were any warnings, then log them now.
259
if ((warningsToLog != null) && (!warningsToLog.isEmpty())) {
260             final IStatus status = new MultiStatus(
261                     WorkbenchPlugin.PI_WORKBENCH, 0, (IStatus[]) warningsToLog
262                             .toArray(new IStatus[warningsToLog.size()]),
263                     message, null);
264             WorkbenchPlugin.log(status);
265         }
266     }
267
268     /**
269      * Reads a boolean attribute from an element.
270      *
271      * @param configurationElement
272      * The configuration element from which to read the attribute;
273      * must not be <code>null</code>.
274      * @param attribute
275      * The attribute to read; must not be <code>null</code>.
276      * @param defaultValue
277      * The default boolean value.
278      * @return The attribute's value; may be <code>null</code> if none.
279      */

280     protected static final boolean readBoolean(
281             final IConfigurationElement configurationElement,
282             final String JavaDoc attribute, final boolean defaultValue) {
283         final String JavaDoc value = configurationElement.getAttribute(attribute);
284         if (value == null) {
285             return defaultValue;
286         }
287
288         if (defaultValue) {
289             return !value.equalsIgnoreCase("false"); //$NON-NLS-1$
290
}
291
292         return value.equalsIgnoreCase("true"); //$NON-NLS-1$
293
}
294
295     /**
296      * Reads an optional attribute from an element. This converts zero-length
297      * strings into <code>null</code>.
298      *
299      * @param configurationElement
300      * The configuration element from which to read the attribute;
301      * must not be <code>null</code>.
302      * @param attribute
303      * The attribute to read; must not be <code>null</code>.
304      * @return The attribute's value; may be <code>null</code> if none.
305      */

306     protected static final String JavaDoc readOptional(
307             final IConfigurationElement configurationElement,
308             final String JavaDoc attribute) {
309         String JavaDoc value = configurationElement.getAttribute(attribute);
310         if ((value != null) && (value.length() == 0)) {
311             value = null;
312         }
313
314         return value;
315     }
316
317     /**
318      * Reads the parameterized command from a parent configuration element. This
319      * is used to read the parameter sub-elements from a key element, as well as
320      * the command id. Each parameter is guaranteed to be valid. If invalid
321      * parameters are found, then a warning status will be appended to the
322      * <code>warningsToLog</code> list. The command id is required, or a
323      * warning will be logged.
324      *
325      * @param configurationElement
326      * The configuration element from which the parameters should be
327      * read; must not be <code>null</code>.
328      * @param commandService
329      * The service providing commands for the workbench; must not be
330      * <code>null</code>.
331      * @param warningsToLog
332      * The list of warnings found during parsing. Warnings found will
333      * parsing the parameters will be appended to this list. This
334      * value must not be <code>null</code>.
335      * @param message
336      * The message to print if the command identifier is not present;
337      * must not be <code>null</code>.
338      * @return The array of parameters found for this configuration element;
339      * <code>null</code> if none can be found.
340      */

341     protected static final ParameterizedCommand readParameterizedCommand(
342             final IConfigurationElement configurationElement,
343             final ICommandService commandService, final List JavaDoc warningsToLog,
344             final String JavaDoc message, final String JavaDoc id) {
345         final String JavaDoc commandId = readRequired(configurationElement,
346                 ATT_COMMAND_ID, warningsToLog, message, id);
347         if (commandId == null) {
348             return null;
349         }
350
351         final Command command = commandService.getCommand(commandId);
352         final ParameterizedCommand parameterizedCommand = readParameters(
353                 configurationElement, warningsToLog, command);
354
355         return parameterizedCommand;
356     }
357
358     /**
359      * Reads the parameters from a parent configuration element. This is used to
360      * read the parameter sub-elements from a key element. Each parameter is
361      * guaranteed to be valid. If invalid parameters are found, then a warning
362      * status will be appended to the <code>warningsToLog</code> list.
363      *
364      * @param configurationElement
365      * The configuration element from which the parameters should be
366      * read; must not be <code>null</code>.
367      * @param warningsToLog
368      * The list of warnings found during parsing. Warnings found will
369      * parsing the parameters will be appended to this list. This
370      * value must not be <code>null</code>.
371      * @param command
372      * The command around which the parameterization should be
373      * created; must not be <code>null</code>.
374      * @return The array of parameters found for this configuration element;
375      * <code>null</code> if none can be found.
376      */

377     protected static final ParameterizedCommand readParameters(
378             final IConfigurationElement configurationElement,
379             final List JavaDoc warningsToLog, final Command command) {
380         final IConfigurationElement[] parameterElements = configurationElement
381                 .getChildren(TAG_PARAMETER);
382         if ((parameterElements == null) || (parameterElements.length == 0)) {
383             return new ParameterizedCommand(command, null);
384         }
385
386         final Collection JavaDoc parameters = new ArrayList JavaDoc();
387         for (int i = 0; i < parameterElements.length; i++) {
388             final IConfigurationElement parameterElement = parameterElements[i];
389
390             // Read out the id.
391
final String JavaDoc id = parameterElement.getAttribute(ATT_ID);
392             if ((id == null) || (id.length() == 0)) {
393                 // The name should never be null. This is invalid.
394
addWarning(warningsToLog, "Parameters need a name", //$NON-NLS-1$
395
configurationElement);
396                 continue;
397             }
398
399             // Find the parameter on the command.
400
IParameter parameter = null;
401             try {
402                 final IParameter[] commandParameters = command.getParameters();
403                 if (parameters != null) {
404                     for (int j = 0; j < commandParameters.length; j++) {
405                         final IParameter currentParameter = commandParameters[j];
406                         if (Util.equals(currentParameter.getId(), id)) {
407                             parameter = currentParameter;
408                             break;
409                         }
410                     }
411
412                 }
413             } catch (final NotDefinedException e) {
414                 // This should not happen.
415
}
416             if (parameter == null) {
417                 // The name should never be null. This is invalid.
418
addWarning(warningsToLog,
419                         "Could not find a matching parameter", //$NON-NLS-1$
420
configurationElement, id);
421                 continue;
422             }
423
424             // Read out the value.
425
final String JavaDoc value = parameterElement.getAttribute(ATT_VALUE);
426             if ((value == null) || (value.length() == 0)) {
427                 // The name should never be null. This is invalid.
428
addWarning(warningsToLog, "Parameters need a value", //$NON-NLS-1$
429
configurationElement, id);
430                 continue;
431             }
432
433             parameters.add(new Parameterization(parameter, value));
434         }
435
436         if (parameters.isEmpty()) {
437             return new ParameterizedCommand(command, null);
438         }
439
440         return new ParameterizedCommand(command,
441                 (Parameterization[]) parameters
442                         .toArray(new Parameterization[parameters.size()]));
443     }
444
445     /**
446      * Reads a required attribute from the configuration element.
447      *
448      * @param configurationElement
449      * The configuration element from which to read; must not be
450      * <code>null</code>.
451      * @param attribute
452      * The attribute to read; must not be <code>null</code>.
453      * @param warningsToLog
454      * The list of warnings; must not be <code>null</code>.
455      * @param message
456      * The warning message to use if the attribute is missing; must
457      * not be <code>null</code>.
458      * @return The required attribute; may be <code>null</code> if missing.
459      */

460     protected static final String JavaDoc readRequired(
461             final IConfigurationElement configurationElement,
462             final String JavaDoc attribute, final List JavaDoc warningsToLog,
463             final String JavaDoc message) {
464         return readRequired(configurationElement, attribute, warningsToLog,
465                 message, null);
466     }
467
468     /**
469      * Reads a required attribute from the configuration element. This logs the
470      * identifier of the item if this required element cannot be found.
471      *
472      * @param configurationElement
473      * The configuration element from which to read; must not be
474      * <code>null</code>.
475      * @param attribute
476      * The attribute to read; must not be <code>null</code>.
477      * @param warningsToLog
478      * The list of warnings; must not be <code>null</code>.
479      * @param message
480      * The warning message to use if the attribute is missing; must
481      * not be <code>null</code>.
482      * @param id
483      * The identifier of the element for which this is a required
484      * attribute; may be <code>null</code>.
485      * @return The required attribute; may be <code>null</code> if missing.
486      */

487     protected static final String JavaDoc readRequired(
488             final IConfigurationElement configurationElement,
489             final String JavaDoc attribute, final List JavaDoc warningsToLog,
490             final String JavaDoc message, final String JavaDoc id) {
491         final String JavaDoc value = configurationElement.getAttribute(attribute);
492         if ((value == null) || (value.length() == 0)) {
493             addWarning(warningsToLog, message, configurationElement, id);
494             return null;
495         }
496
497         return value;
498     }
499
500     /**
501      * Reads a <code>when</code> child element from the given configuration
502      * element. Warnings will be appended to <code>warningsToLog</code>.
503      *
504      * @param parentElement
505      * The configuration element which might have a <code>when</code>
506      * element as a child; never <code>null</code>.
507      * @param whenElementName
508      * The name of the when element to find; never <code>null</code>.
509      * @param id
510      * The identifier of the menu element whose <code>when</code>
511      * expression is being read; never <code>null</code>.
512      * @param warningsToLog
513      * The list of warnings while parsing the extension point; never
514      * <code>null</code>.
515      * @return The <code>when</code> expression for the
516      * <code>configurationElement</code>, if any; otherwise,
517      * <code>null</code>.
518      */

519     protected static final Expression readWhenElement(
520             final IConfigurationElement parentElement,
521             final String JavaDoc whenElementName, final String JavaDoc id,
522             final List JavaDoc warningsToLog) {
523         // Check to see if we have an when expression.
524
final IConfigurationElement[] whenElements = parentElement
525                 .getChildren(whenElementName);
526         Expression whenExpression = null;
527         if (whenElements.length > 0) {
528             // Check if we have too many when elements.
529
if (whenElements.length > 1) {
530                 // There should only be one when element
531
addWarning(warningsToLog,
532                         "There should only be one when element", parentElement, //$NON-NLS-1$
533
id, "whenElementName", //$NON-NLS-1$
534
whenElementName);
535                 return ERROR_EXPRESSION;
536             }
537
538             final IConfigurationElement whenElement = whenElements[0];
539             final IConfigurationElement[] expressionElements = whenElement
540                     .getChildren();
541             if (expressionElements.length > 0) {
542                 // Check if we have too many expression elements
543
if (expressionElements.length > 1) {
544                     // There should only be one expression element
545
addWarning(
546                             warningsToLog,
547                             "There should only be one expression element", parentElement, //$NON-NLS-1$
548
id, "whenElementName", //$NON-NLS-1$
549
whenElementName);
550                     return ERROR_EXPRESSION;
551                 }
552
553                 // Convert the activeWhen element into an expression.
554
final ElementHandler elementHandler = ElementHandler
555                         .getDefault();
556                 final ExpressionConverter converter = ExpressionConverter
557                         .getDefault();
558                 final IConfigurationElement expressionElement = expressionElements[0];
559                 try {
560                     whenExpression = elementHandler.create(converter,
561                             expressionElement);
562                 } catch (final CoreException e) {
563                     // There when expression could not be created.
564
addWarning(
565                             warningsToLog,
566                             "Problem creating when element", //$NON-NLS-1$
567
parentElement, id,
568                             "whenElementName", whenElementName); //$NON-NLS-1$
569
return ERROR_EXPRESSION;
570                 }
571             }
572         }
573
574         return whenExpression;
575     }
576
577     /**
578      * The registry change listener for this class.
579      */

580     private final IRegistryChangeListener registryChangeListener;
581
582     /**
583      * Whether the preference and registry change listeners have been attached
584      * yet.
585      */

586     protected boolean registryListenerAttached = false;
587
588     /**
589      * Constructs a new instance of {@link RegistryPersistence}. A registry
590      * change listener is created.
591      */

592     protected RegistryPersistence() {
593         registryChangeListener = new IRegistryChangeListener() {
594             public final void registryChanged(final IRegistryChangeEvent event) {
595                 if (isChangeImportant(event)) {
596                     Display.getDefault().asyncExec(new Runnable JavaDoc() {
597                         public final void run() {
598                             read();
599                         }
600                     });
601                 }
602             }
603         };
604     }
605
606     /**
607      * Detaches the registry change listener from the registry.
608      */

609     public void dispose() {
610         final IExtensionRegistry registry = Platform.getExtensionRegistry();
611         registry.removeRegistryChangeListener(registryChangeListener);
612         registryListenerAttached = false;
613     }
614
615     /**
616      * Checks whether the registry change could affect this persistence class.
617      *
618      * @param event
619      * The event indicating the registry change; must not be
620      * <code>null</code>.
621      * @return <code>true</code> if the persistence instance is affected by
622      * this change; <code>false</code> otherwise.
623      */

624     protected abstract boolean isChangeImportant(
625             final IRegistryChangeEvent event);
626
627     /**
628      * Reads the various elements from the registry. Subclasses should extend,
629      * but must not override.
630      */

631     protected void read() {
632         if (!registryListenerAttached) {
633             final IExtensionRegistry registry = Platform.getExtensionRegistry();
634             registry.addRegistryChangeListener(registryChangeListener);
635             registryListenerAttached = true;
636         }
637     }
638 }
639
Popular Tags