001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.navigator.extensions;
011:
012: import java.util.Arrays;
013: import java.util.Collections;
014: import java.util.Comparator;
015:
016: import org.eclipse.core.runtime.IConfigurationElement;
017: import org.eclipse.core.runtime.IExtension;
018: import org.eclipse.core.runtime.IExtensionPoint;
019: import org.eclipse.core.runtime.IExtensionRegistry;
020: import org.eclipse.core.runtime.Platform;
021: import org.eclipse.ui.internal.navigator.NavigatorPlugin;
022:
023: /**
024: * Template implementation of a registry reader that creates objects representing registry contents.
025: * Typically, an extension contains one element, but this reader handles multiple elements per
026: * extension.
027: *
028: * To start reading the extensions from the registry for an extension point, call the method
029: * <code>readRegistry</code>.
030: *
031: * To read children of an IConfigurationElement, call the method <code>readElementChildren</code>
032: * from your implementation of the method <code>readElement</code>, as it will not be done by
033: * default.
034: * <p>
035: * <strong>EXPERIMENTAL</strong>. This class or interface has been added as part of a work in
036: * progress. There is a guarantee neither that this API will work nor that it will remain the same.
037: * Please do not use this API without consulting with the Platform/UI team.
038: * </p>
039: *
040: * @since 3.2
041: */
042: public abstract class RegistryReader {
043:
044: protected static final String TAG_DESCRIPTION = "description"; //$NON-NLS-1$
045:
046: private boolean isInitialized;
047: private final String extensionPointId;
048: private final String pluginId;
049: private final IExtensionRegistry registry;
050:
051: /**
052: * The constructor.
053: */
054: protected RegistryReader(String aPluginId, String anExtensionPoint) {
055: this .registry = Platform.getExtensionRegistry();
056: this .pluginId = aPluginId;
057: this .extensionPointId = anExtensionPoint;
058: }
059:
060: /**
061: * This method extracts description as a subelement of the given element.
062: *
063: * @return description string if defined, or empty string if not.
064: */
065: protected String getDescription(IConfigurationElement config) {
066: IConfigurationElement[] children = config
067: .getChildren(TAG_DESCRIPTION);
068: if (children.length >= 1) {
069: return children[0].getValue();
070: }
071: return "";//$NON-NLS-1$
072: }
073:
074: /**
075: * Logs the error in the workbench log using the provided text and the information in the
076: * configuration element.
077: */
078: protected static void logError(IConfigurationElement element,
079: String text) {
080: IExtension extension = element.getDeclaringExtension();
081: StringBuffer buf = new StringBuffer();
082: buf
083: .append("Plugin " + extension.getNamespaceIdentifier() + ", extension " + extension.getExtensionPointUniqueIdentifier());//$NON-NLS-2$//$NON-NLS-1$
084: buf.append("\n" + text);//$NON-NLS-1$
085: NavigatorPlugin.logError(0, buf.toString(), null);
086: }
087:
088: /**
089: * Logs a very common registry error when a required attribute is missing.
090: */
091: protected static void logMissingAttribute(
092: IConfigurationElement element, String attributeName) {
093: logError(
094: element,
095: "Required attribute '" + attributeName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
096: }
097:
098: /**
099: * Logs a very common registry error when a required child is missing.
100: */
101: protected static void logMissingElement(
102: IConfigurationElement element, String elementName) {
103: logError(
104: element,
105: "Required sub element '" + elementName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
106: }
107:
108: /**
109: * Logs a registry error when the configuration element is unknown.
110: */
111: protected static void logUnknownElement(
112: IConfigurationElement element) {
113: logError(element,
114: "Unknown extension tag found: " + element.getName());//$NON-NLS-1$
115: }
116:
117: /**
118: * Apply a reproducable order to the list of extensions provided, such that the order will not
119: * change as extensions are added or removed.
120: */
121: protected IExtension[] orderExtensions(IExtension[] extensions) {
122: // By default, the order is based on plugin id sorted
123: // in ascending order. The order for a plugin providing
124: // more than one extension for an extension point is
125: // dependent in the order listed in the XML file.
126: IExtension[] sortedExtension = new IExtension[extensions.length];
127: System.arraycopy(extensions, 0, sortedExtension, 0,
128: extensions.length);
129: Comparator comparer = new Comparator() {
130: public int compare(Object arg0, Object arg1) {
131: String s1 = ((IExtension) arg0)
132: .getNamespaceIdentifier();
133: String s2 = ((IExtension) arg1)
134: .getNamespaceIdentifier();
135: return s1.compareToIgnoreCase(s2);
136: }
137: };
138: Collections.sort(Arrays.asList(sortedExtension), comparer);
139: return sortedExtension;
140: }
141:
142: /**
143: * Implement this method to read element's attributes. If children should also be read, then
144: * implementor is responsible for calling <code>readElementChildren</code>. Implementor is
145: * also responsible for logging missing attributes.
146: *
147: * @return true if element was recognized, false if not.
148: */
149: protected abstract boolean readElement(IConfigurationElement element);
150:
151: /**
152: * Read the element's children. This is called by the subclass' readElement method when it wants
153: * to read the children of the element.
154: */
155: protected void readElementChildren(IConfigurationElement element) {
156: readElements(element.getChildren());
157: }
158:
159: /**
160: * Read each element one at a time by calling the subclass implementation of
161: * <code>readElement</code>.
162: *
163: * Logs an error if the element was not recognized.
164: */
165: protected void readElements(IConfigurationElement[] elements) {
166: for (int i = 0; i < elements.length; i++) {
167: if (!readElement(elements[i])) {
168: logUnknownElement(elements[i]);
169: }
170: }
171: }
172:
173: /**
174: * Read one extension by looping through its configuration elements.
175: */
176: protected void readExtension(IExtension extension) {
177: readElements(extension.getConfigurationElements());
178: }
179:
180: /**
181: * Start the registry reading process using the supplied plugin ID and extension point.
182: */
183: public void readRegistry() {
184: if (isInitialized) {
185: return;
186: }
187: synchronized (this ) {
188: if (!isInitialized) {
189: IExtensionPoint point = registry.getExtensionPoint(
190: pluginId, extensionPointId);
191: if (point == null) {
192: return;
193: }
194: IExtension[] extensions = point.getExtensions();
195: extensions = orderExtensions(extensions);
196: for (int i = 0; i < extensions.length; i++) {
197: readExtension(extensions[i]);
198: }
199: isInitialized = true;
200: }
201:
202: }
203: }
204: }
|