blob: ce3abbdbf6c8b5153848ed340d1050b39966e47e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ui.registry;
import java.util.Hashtable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.internal.ui.Utils.Sorter;
import org.osgi.framework.Bundle;
public abstract class RegistryReader {
protected static final String TAG_DESCRIPTION = "description"; //$NON-NLS-1$
protected static Hashtable<String, IExtension[]> extensionPoints = new Hashtable<>();
/**
* Creates an extension. If the extension plugin has not
* been loaded a busy cursor will be activated during the duration of
* the load.
*
* @param element the configuration element defining the extension
* @param classAttribute the name of the attribute carrying the class
* @return the extension object
* @throws CoreException if the extension cannot be created
*/
public static Object createExtension(final IConfigurationElement element,
final String classAttribute) throws CoreException {
try {
// If plugin has been loaded create extension.
// Otherwise, show busy cursor then create extension.
if (isActivated(element.getDeclaringExtension()
.getContributor().getName())) {
return element.createExecutableExtension(classAttribute);
}
final Object[] ret = new Object[1];
final CoreException[] exc = new CoreException[1];
BusyIndicator.showWhile(null, () -> {
try {
ret[0] = element
.createExecutableExtension(classAttribute);
} catch (CoreException e) {
exc[0] = e;
}
});
if (exc[0] != null) {
throw exc[0];
}
return ret[0];
} catch (CoreException core) {
throw core;
} catch (Exception e) {
throw new CoreException(new Status(IStatus.ERROR, TeamUIPlugin.ID,
IStatus.ERROR, NLS.bind(TeamUIMessages.RegistryReader_0, element.getNamespaceIdentifier(), element.getName()),e));
}
}
private static boolean isActivated(String bundleId) {
return isActivated(Platform.getBundle(bundleId));
}
private static boolean isActivated(Bundle bundle) {
return bundle != null && (bundle.getState() & (Bundle.ACTIVE | Bundle.STOPPING)) != 0;
}
/**
* The constructor.
*/
protected RegistryReader() {
}
/**
* This method extracts description as a sub-element of the given element.
*
* @return description string if defined, or empty string if not.
*/
protected String getDescription(IConfigurationElement config) {
IConfigurationElement[] children = config.getChildren(TAG_DESCRIPTION);
if (children.length >= 1) {
return children[0].getValue();
}
return ""; //$NON-NLS-1$
}
/**
* Logs the error in the workbench log using the provided text and the
* information in the configuration element.
*/
protected void logError(IConfigurationElement element, String text) {
IExtension extension = element.getDeclaringExtension();
StringBuilder buf = new StringBuilder();
buf.append("Plugin " + extension.getContributor().getName() + ", extension " + extension.getExtensionPointUniqueIdentifier()); //$NON-NLS-2$//$NON-NLS-1$
buf.append("\n" + text); //$NON-NLS-1$
TeamUIPlugin.log(IStatus.ERROR, buf.toString(), null);
}
/**
* Logs a very common registry error when a required attribute is missing.
*/
protected void logMissingAttribute(IConfigurationElement element, String attributeName) {
logError(element, "Required attribute '" + attributeName + "' not defined"); //$NON-NLS-2$//$NON-NLS-1$
}
/**
* Logs a very common registry error when a required child is missing.
*/
protected void logMissingElement(IConfigurationElement element, String elementName) {
logError(element, "Required sub element '" + elementName + "' not defined"); //$NON-NLS-2$//$NON-NLS-1$
}
/**
* Logs a registry error when the configuration element is unknown.
*/
protected void logUnknownElement(IConfigurationElement element) {
logError(element, "Unknown extension tag found: " + element.getName()); //$NON-NLS-1$
}
/**
* Apply a reproducible order to the list of extensions provided, such that
* the order will not change as extensions are added or removed.
*/
protected IExtension[] orderExtensions(IExtension[] extensions) {
// By default, the order is based on plugin id sorted
// in ascending order. The order for a plugin providing
// more than one extension for an extension point is
// dependent in the order listed in the XML file.
Sorter sorter = new Sorter() {
@Override
public boolean compare(Object extension1, Object extension2) {
String s1 = ((IExtension) extension1).getContributor().getName();
String s2 = ((IExtension) extension2).getContributor().getName();
//Return true if elementTwo is 'greater than' elementOne
return s2.compareToIgnoreCase(s1) > 0;
}
};
Object[] sorted = sorter.sort(extensions);
IExtension[] sortedExtension = new IExtension[sorted.length];
System.arraycopy(sorted, 0, sortedExtension, 0, sorted.length);
return sortedExtension;
}
/**
* Implement this method to read element's attributes. If children should
* also be read, then implementor is responsible for calling <code>readElementChildren</code>.
* Implementor is also responsible for logging missing attributes.
*
* @return true if element was recognized, false if not.
*/
protected abstract boolean readElement(IConfigurationElement element);
/**
* Read the element's children. This is called by the subclass' readElement
* method when it wants to read the children of the element.
*/
protected void readElementChildren(IConfigurationElement element) {
readElements(element.getChildren());
}
/**
* Read each element one at a time by calling the subclass implementation
* of <code>readElement</code>.
*
* Logs an error if the element was not recognized.
*/
protected void readElements(IConfigurationElement[] elements) {
for (int i = 0; i < elements.length; i++) {
if (!readElement(elements[i]))
logUnknownElement(elements[i]);
}
}
/**
* Read one extension by looping through its configuration elements.
*/
protected void readExtension(IExtension extension) {
readElements(extension.getConfigurationElements());
}
/**
* Start the registry reading process using the supplied plugin ID and
* extension point.
* @param registry the registry
* @param pluginId the plug-in id
* @param extensionPoint the extension point
*/
public void readRegistry(IExtensionRegistry registry, String pluginId, String extensionPoint) {
String pointId = pluginId + "-" + extensionPoint; //$NON-NLS-1$
IExtension[] extensions = extensionPoints.get(pointId);
if (extensions == null) {
IExtensionPoint point = registry.getExtensionPoint(pluginId, extensionPoint);
if (point == null)
return;
extensions = point.getExtensions();
extensionPoints.put(pointId, extensions);
}
for (int i = 0; i < extensions.length; i++)
readExtension(extensions[i]);
}
}