/*******************************************************************************
* Copyright (c) 2011, 2014 Wind River Systems, Inc. and others. All rights reserved.
* This program and the accompanying materials are made available under the terms
* of the Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.runtime.extensions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
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.tcf.te.runtime.activator.CoreBundleActivator;
import org.eclipse.tcf.te.runtime.nls.Messages;
/**
* Abstract extension point manager implementation.
*/
public abstract class AbstractExtensionPointManager<V> {
// Flag to mark the extension point manager initialized (extensions loaded).
private boolean initialized = false;
// The map of loaded extension listed by their unique id's
private Map<String, ExecutableExtensionProxy<V>> extensionsMap = new LinkedHashMap<String, ExecutableExtensionProxy<V>>();
// The extension point comparator
private ExtensionPointComparator comparator = null;
/**
* Constructor.
*/
public AbstractExtensionPointManager() {
}
/**
* Returns if or if not the extension point manager got initialized already.
* <p>
* Initialized means that the manager read the extensions for the managed extension point.
*
* @return <code>True</code> if already initialized, <code>false</code> otherwise.
*/
protected boolean isInitialized() {
return initialized;
}
/**
* Sets if or if not the extension point manager is initialized.
* <p>
* Initialized means that the manager has read the extensions for the managed extension point.
*
* @return <code>True</code> to set the extension point manager is initialized, <code>false</code> otherwise.
*/
protected void setInitialized(boolean initialized) {
this.initialized = initialized;
}
/**
* Returns the map of managed extensions. If not loaded before,
* this methods trigger the loading of the extensions to the managed
* extension point.
*
* @return The map of extensions.
*/
protected Map<String, ExecutableExtensionProxy<V>> getExtensions() {
// Load and store the extensions thread-safe!
synchronized (extensionsMap) {
if (!isInitialized()) { loadExtensions(); setInitialized(true); }
}
return extensionsMap;
}
/**
* Returns the extensions of the specified extension point sorted.
* <p>
* For the order of the extensions, see {@link ExtensionPointComparator}.
*
* @param point The extension point. Must not be <code>null</code>.
* @return The extensions in sorted order or an empty array if the extension point has no extensions.
*/
protected IExtension[] getExtensionsSorted(IExtensionPoint point) {
Assert.isNotNull(point);
List<IExtension> extensions = new ArrayList<IExtension>(Arrays.asList(point.getExtensions()));
if (extensions.size() > 0) {
Collections.sort(extensions, getExtensionPointComparator());
}
return extensions.toArray(new IExtension[extensions.size()]);
}
/**
* Returns the extension point comparator instance. If not available,
* {@link #doCreateExtensionPointComparator()} is called to create a new instance.
*
* @return The extension point comparator or <code>null</code> if the instance creation fails.
*/
protected final ExtensionPointComparator getExtensionPointComparator() {
if (comparator == null) {
comparator = doCreateExtensionPointComparator();
}
return comparator;
}
/**
* Creates a new extension point comparator instance.
*
* @return The extension point comparator instance.
*/
protected ExtensionPointComparator doCreateExtensionPointComparator() {
return new ExtensionPointComparator();
}
/**
* Returns the extension point id to read. The method
* must return never <code>null</code>.
*
* @return The extension point id.
*/
protected abstract String getExtensionPointId();
/**
* Returns the configuration element name. The method
* must return never <code>null</code>.
*
* @return The configuration element name.
*/
protected abstract String getConfigurationElementName();
/**
* Creates the extension proxy instance.
*
* @param element The configuration element of the extension. Must not be <code>null</code>.
* @return The extension proxy instance.
*
* @throws CoreException If the extension proxy instantiation failed.
*/
protected ExecutableExtensionProxy<V> doCreateExtensionProxy(IConfigurationElement element) throws CoreException {
Assert.isNotNull(element);
return new ExecutableExtensionProxy<V>(element);
}
/**
* Store the given extension to the given extensions store. Checks if an extension with the same id does exist
* already and throws an exception in this case.
*
* @param extensions The extensions store. Must not be <code>null</code>.
* @param candidate The extension. Must not be <code>null</code>.
* @param element The configuration element. Must not be <code>null</code>.
*
* @throws CoreException In case a extension with the same id as the given extension already exist.
*/
protected void doStoreExtensionTo(Map<String, ExecutableExtensionProxy<V>> extensions, ExecutableExtensionProxy<V> candidate, IConfigurationElement element) throws CoreException {
Assert.isNotNull(extensions);
Assert.isNotNull(candidate);
Assert.isNotNull(element);
// If no extension with this id had been registered before, register now.
if (!extensions.containsKey(candidate.getId())) {
extensions.put(candidate.getId(), candidate);
}
else {
throw new CoreException(new Status(IStatus.ERROR,
CoreBundleActivator.getUniqueIdentifier(),
0,
NLS.bind(Messages.Extension_error_duplicateExtension, candidate.getId(), element.getContributor().getName()),
null));
}
}
/**
* Loads the extensions for the managed extension point.
*/
protected void loadExtensions() {
// If already initialized, this method will do nothing.
if (isInitialized()) return;
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint point = registry.getExtensionPoint(getExtensionPointId());
if (point != null) {
IExtension[] extensions = getExtensionsSorted(point);
for (IExtension extension : extensions) {
IConfigurationElement[] elements = extension.getConfigurationElements();
for (IConfigurationElement element : elements) {
if (getConfigurationElementName().equals(element.getName())) {
try {
ExecutableExtensionProxy<V> candidate = doCreateExtensionProxy(element);
if (candidate.getId() != null) {
doStoreExtensionTo(extensionsMap, candidate, element);
} else {
throw new CoreException(new Status(IStatus.ERROR,
CoreBundleActivator.getUniqueIdentifier(),
0,
NLS.bind(Messages.Extension_error_missingRequiredAttribute, "id", element.getAttribute("label")), //$NON-NLS-1$ //$NON-NLS-2$
null));
}
} catch (CoreException e) {
Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(new Status(IStatus.ERROR,
CoreBundleActivator.getUniqueIdentifier(),
NLS.bind(Messages.Extension_error_invalidExtensionPoint, element.getDeclaringExtension().getUniqueIdentifier()), e));
}
}
}
}
}
}
}