001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.registry;
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.ui.internal.WorkbenchPlugin;
021:
022: /**
023: * Template implementation of a registry reader that creates objects
024: * representing registry contents. Typically, an extension
025: * contains one element, but this reader handles multiple
026: * elements per extension.
027: *
028: * To start reading the extensions from the registry for an
029: * extension point, call the method <code>readRegistry</code>.
030: *
031: * To read children of an IConfigurationElement, call the
032: * method <code>readElementChildren</code> from your implementation
033: * of the method <code>readElement</code>, as it will not be
034: * done by default.
035: */
036: public abstract class RegistryReader {
037:
038: // for dynamic UI - remove this cache to avoid inconsistency
039: //protected static Hashtable extensionPoints = new Hashtable();
040: /**
041: * The constructor.
042: */
043: protected RegistryReader() {
044: }
045:
046: /**
047: * Logs the error in the workbench log using the provided
048: * text and the information in the configuration element.
049: */
050: protected static void logError(IConfigurationElement element,
051: String text) {
052: IExtension extension = element.getDeclaringExtension();
053: StringBuffer buf = new StringBuffer();
054: buf
055: .append("Plugin " + extension.getNamespace() + ", extension " + extension.getExtensionPointUniqueIdentifier());//$NON-NLS-2$//$NON-NLS-1$
056: buf.append("\n" + text);//$NON-NLS-1$
057: WorkbenchPlugin.log(buf.toString());
058: }
059:
060: /**
061: * Logs a very common registry error when a required attribute is missing.
062: */
063: protected static void logMissingAttribute(
064: IConfigurationElement element, String attributeName) {
065: logError(
066: element,
067: "Required attribute '" + attributeName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
068: }
069:
070: /**
071: * Logs a very common registry error when a required child is missing.
072: */
073: protected static void logMissingElement(
074: IConfigurationElement element, String elementName) {
075: logError(
076: element,
077: "Required sub element '" + elementName + "' not defined");//$NON-NLS-2$//$NON-NLS-1$
078: }
079:
080: /**
081: * Logs a registry error when the configuration element is unknown.
082: */
083: protected static void logUnknownElement(
084: IConfigurationElement element) {
085: logError(element,
086: "Unknown extension tag found: " + element.getName());//$NON-NLS-1$
087: }
088:
089: /**
090: * Apply a reproducable order to the list of extensions
091: * provided, such that the order will not change as
092: * extensions are added or removed.
093: * @param extensions the extensions to order
094: * @return ordered extensions
095: */
096: public static IExtension[] orderExtensions(IExtension[] extensions) {
097: // By default, the order is based on plugin id sorted
098: // in ascending order. The order for a plugin providing
099: // more than one extension for an extension point is
100: // dependent in the order listed in the XML file.
101: IExtension[] sortedExtension = new IExtension[extensions.length];
102: System.arraycopy(extensions, 0, sortedExtension, 0,
103: extensions.length);
104: Comparator comparer = new Comparator() {
105: public int compare(Object arg0, Object arg1) {
106: String s1 = ((IExtension) arg0).getNamespace();
107: String s2 = ((IExtension) arg1).getNamespace();
108: return s1.compareToIgnoreCase(s2);
109: }
110: };
111: Collections.sort(Arrays.asList(sortedExtension), comparer);
112: return sortedExtension;
113: }
114:
115: /**
116: * Implement this method to read element's attributes.
117: * If children should also be read, then implementor
118: * is responsible for calling <code>readElementChildren</code>.
119: * Implementor is also responsible for logging missing
120: * attributes.
121: *
122: * @return true if element was recognized, false if not.
123: */
124: protected abstract boolean readElement(IConfigurationElement element);
125:
126: /**
127: * Read the element's children. This is called by
128: * the subclass' readElement method when it wants
129: * to read the children of the element.
130: */
131: protected void readElementChildren(IConfigurationElement element) {
132: readElements(element.getChildren());
133: }
134:
135: /**
136: * Read each element one at a time by calling the
137: * subclass implementation of <code>readElement</code>.
138: *
139: * Logs an error if the element was not recognized.
140: */
141: protected void readElements(IConfigurationElement[] elements) {
142: for (int i = 0; i < elements.length; i++) {
143: if (!readElement(elements[i])) {
144: logUnknownElement(elements[i]);
145: }
146: }
147: }
148:
149: /**
150: * Read one extension by looping through its
151: * configuration elements.
152: */
153: protected void readExtension(IExtension extension) {
154: readElements(extension.getConfigurationElements());
155: }
156:
157: /**
158: * Start the registry reading process using the
159: * supplied plugin ID and extension point.
160: *
161: * @param registry the registry to read from
162: * @param pluginId the plugin id of the extenion point
163: * @param extensionPoint the extension point id
164: */
165: public void readRegistry(IExtensionRegistry registry,
166: String pluginId, String extensionPoint) {
167: IExtensionPoint point = registry.getExtensionPoint(pluginId,
168: extensionPoint);
169: if (point == null) {
170: return;
171: }
172: IExtension[] extensions = point.getExtensions();
173: extensions = orderExtensions(extensions);
174: for (int i = 0; i < extensions.length; i++) {
175: readExtension(extensions[i]);
176: }
177: }
178:
179: /**
180: * Utility for extracting the description child of an element.
181: *
182: * @param configElement the element
183: * @return the description
184: * @since 3.1
185: */
186: public static String getDescription(
187: IConfigurationElement configElement) {
188: IConfigurationElement[] children = configElement
189: .getChildren(IWorkbenchRegistryConstants.TAG_DESCRIPTION);
190: if (children.length >= 1) {
191: return children[0].getValue();
192: }
193: return "";//$NON-NLS-1$
194: }
195:
196: /**
197: * Utility for extracting the value of a class attribute or a nested class
198: * element that follows the pattern set forth by
199: * {@link org.eclipse.core.runtime.IExecutableExtension}.
200: *
201: * @param configElement
202: * the element
203: * @param classAttributeName
204: * the name of the class attribute to check
205: * @return the value of the attribute or nested class element
206: * @since 3.1
207: */
208: public static String getClassValue(
209: IConfigurationElement configElement,
210: String classAttributeName) {
211: String className = configElement
212: .getAttribute(classAttributeName);
213: if (className != null) {
214: return className;
215: }
216: IConfigurationElement[] candidateChildren = configElement
217: .getChildren(classAttributeName);
218: if (candidateChildren.length == 0) {
219: return null;
220: }
221:
222: return candidateChildren[0]
223: .getAttribute(IWorkbenchRegistryConstants.ATT_CLASS);
224: }
225: }
|