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.texteditor;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.Comparator;
015: import java.util.HashMap;
016: import java.util.HashSet;
017: import java.util.Iterator;
018: import java.util.List;
019: import java.util.Map;
020: import java.util.Set;
021:
022: import org.osgi.framework.Bundle;
023: import org.osgi.framework.BundleException;
024: import org.osgi.framework.Constants;
025:
026: import org.eclipse.core.runtime.Assert;
027: import org.eclipse.core.runtime.IConfigurationElement;
028: import org.eclipse.core.runtime.IExtension;
029: import org.eclipse.core.runtime.IStatus;
030: import org.eclipse.core.runtime.Platform;
031: import org.eclipse.core.runtime.Status;
032:
033: import org.eclipse.osgi.util.ManifestElement;
034:
035: import org.eclipse.ui.internal.texteditor.TextEditorPlugin;
036:
037: /**
038: * Allows to sort an array based on their elements' configuration elements
039: * according to the prerequisite relation of their defining plug-ins.
040: * <p>
041: * This class may be subclassed.
042: * </p>
043: *
044: * @since 3.0
045: */
046: public abstract class ConfigurationElementSorter {
047:
048: /**
049: * Sorts the given array based on its elements' configuration elements
050: * according to the prerequisite relation of their defining plug-ins.
051: *
052: * @param elements the array to be sorted
053: */
054: public final void sort(Object[] elements) {
055: Arrays.sort(elements, new ConfigurationElementComparator(
056: elements));
057: }
058:
059: /**
060: * Returns the configuration element for the given object.
061: *
062: * @param object the object
063: * @return the object's configuration element, must not be <code>null</code>
064: */
065: public abstract IConfigurationElement getConfigurationElement(
066: Object object);
067:
068: /**
069: * Compare configuration elements according to the prerequisite relation
070: * of their defining plug-ins.
071: */
072: private class ConfigurationElementComparator implements Comparator {
073:
074: private Map fDescriptorMapping;
075: private Map fPrereqsMapping;
076:
077: public ConfigurationElementComparator(Object[] elements) {
078: Assert.isNotNull(elements);
079: initialize(elements);
080: }
081:
082: /*
083: * @see Comparator#compare(java.lang.Object, java.lang.Object)
084: * @since 2.0
085: */
086: public int compare(Object object0, Object object1) {
087:
088: if (dependsOn(object0, object1))
089: return -1;
090:
091: if (dependsOn(object1, object0))
092: return +1;
093:
094: return 0;
095: }
096:
097: /**
098: * Returns whether one configuration element depends on the other element.
099: * This is done by checking the dependency chain of the defining plug-ins.
100: *
101: * @param element0 the first element
102: * @param element1 the second element
103: * @return <code>true</code> if <code>element0</code> depends on <code>element1</code>.
104: * @since 2.0
105: */
106: private boolean dependsOn(Object element0, Object element1) {
107: if (element0 == null || element1 == null)
108: return false;
109:
110: String pluginDesc0 = (String) fDescriptorMapping
111: .get(element0);
112: String pluginDesc1 = (String) fDescriptorMapping
113: .get(element1);
114:
115: // performance tuning - code below would give same result
116: if (pluginDesc0.equals(pluginDesc1))
117: return false;
118:
119: Set prereqUIds0 = (Set) fPrereqsMapping.get(pluginDesc0);
120:
121: return prereqUIds0.contains(pluginDesc1);
122: }
123:
124: /**
125: * Initialize this comparator.
126: *
127: * @param elements an array of Java editor hover descriptors
128: */
129: private void initialize(Object[] elements) {
130: int length = elements.length;
131: fDescriptorMapping = new HashMap(length);
132: fPrereqsMapping = new HashMap(length);
133: Set fBundleSet = new HashSet(length);
134:
135: for (int i = 0; i < length; i++) {
136: IConfigurationElement configElement = getConfigurationElement(elements[i]);
137: Bundle bundle = Platform.getBundle(configElement
138: .getContributor().getName());
139: fDescriptorMapping.put(elements[i], bundle
140: .getSymbolicName());
141: fBundleSet.add(bundle);
142: }
143:
144: Iterator iter = fBundleSet.iterator();
145: while (iter.hasNext()) {
146: Bundle bundle = (Bundle) iter.next();
147: List toTest = new ArrayList(fBundleSet);
148: toTest.remove(bundle);
149: Set prereqUIds = new HashSet(Math.max(0,
150: toTest.size() - 1));
151: fPrereqsMapping.put(bundle.getSymbolicName(),
152: prereqUIds);
153:
154: String requires = (String) bundle.getHeaders().get(
155: Constants.REQUIRE_BUNDLE);
156: ManifestElement[] manifestElements;
157: try {
158: manifestElements = ManifestElement.parseHeader(
159: Constants.REQUIRE_BUNDLE, requires);
160: } catch (BundleException e) {
161: String uid = getExtensionPointUniqueIdentifier(bundle);
162: String message = "ConfigurationElementSorter for '" + uid + "': getting required plug-ins for '" + bundle.getSymbolicName() + "' failed"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
163: Status status = new Status(IStatus.ERROR,
164: TextEditorPlugin.PLUGIN_ID, IStatus.OK,
165: message, e);
166: TextEditorPlugin.getDefault().getLog().log(status);
167: continue;
168: }
169:
170: if (manifestElements == null)
171: continue;
172:
173: int i = 0;
174: while (i < manifestElements.length && !toTest.isEmpty()) {
175: String prereqUId = manifestElements[i].getValue();
176: for (int j = 0; j < toTest.size();) {
177: Bundle toTest_j = (Bundle) toTest.get(j);
178: if (toTest_j.getSymbolicName()
179: .equals(prereqUId)) {
180: toTest.remove(toTest_j);
181: prereqUIds.add(toTest_j.getSymbolicName());
182: } else
183: j++;
184: }
185: i++;
186: }
187: }
188: }
189:
190: /**
191: * Returns the unique extension point identifier for the
192: * configuration element which belongs to the given bundle.
193: *
194: * @param bundle the bundle
195: * @return the unique extension point identifier or "unknown" if not found
196: * @since 3.0.1
197: */
198: private String getExtensionPointUniqueIdentifier(Bundle bundle) {
199: if (bundle != null) {
200: String bundleName = bundle.getSymbolicName();
201: if (bundleName != null) {
202: Set entries = fDescriptorMapping.entrySet();
203: Iterator iter = entries.iterator();
204: while (iter.hasNext()) {
205: Map.Entry entry = (Map.Entry) iter.next();
206: if (bundleName.equals(entry.getValue())) {
207: IExtension extension = getConfigurationElement(
208: entry.getKey())
209: .getDeclaringExtension();
210: return extension
211: .getExtensionPointUniqueIdentifier();
212: }
213: }
214: }
215: }
216: return "unknown"; //$NON-NLS-1$
217: }
218:
219: }
220: }
|