blob: 5d127fbee61cd270cb1b631ff1fa4945ac173658 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.emf.clipboard.core.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.gmf.runtime.common.core.util.Proxy;
import org.eclipse.gmf.runtime.emf.clipboard.core.IClipboardSupportFactory;
import org.eclipse.gmf.runtime.emf.clipboard.core.IClipboardSupportPolicy;
import org.eclipse.gmf.runtime.emf.clipboard.core.internal.l10n.EMFClipboardCoreMessages;
import org.eclipse.osgi.util.NLS;
/**
* Manager for the <tt>clipboardSupport</tt> extension point.
*
* @author Christian W. Damus (cdamus), crevells
*/
public class ClipboardSupportManager {
public static final String EP_CLIPBOARD_SUPPORT = "org.eclipse.gmf.runtime.emf.clipboard.core.clipboardSupport"; //$NON-NLS-1$
static final String E_NSURI = "nsURI"; //$NON-NLS-1$
static final String E_CLASS = "class"; //$NON-NLS-1$
static final String E_POLICY = "policy"; //$NON-NLS-1$
/** @deprecated need a context-based solution */
static final String E_PRIORITY = "priority"; //$NON-NLS-1$
/** @deprecated need a context-based solution */
private static final List PRIORITIES = Arrays.asList(new String[] {
"lowest", "low", "medium", "high", "highest"}); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$
/** An array of lists of descriptors for each priority, index by priority. */
private static ArrayList[] descriptors;
/**
* Wraps an {@link EObject} to adapt it to the {@link IAdaptable} Eclipse
* platform API. This is useful for passing <code>EObject</code>s into APIs
* that consume adaptables.
*/
private static class EObjectAdapter extends Proxy implements IAdaptable {
public EObjectAdapter(EObject element) {
super(element);
}
/**
* Returns the wrapped {@link EObject} as the adapter when possible. The
* following adaptations are supported:
* <ul>
* <li>if the wrapped <code>EObject</code> conforms to the
* <code>adapter</code> type, then it is returned</li>
* <li>if this adapter, itself, conforms to the <code>adapter</code>
* type, then it is returned</li>
* <li>otherwise, there is no adapter (<code>null</code> returned)</li>
* </ul>
*/
public Object getAdapter(Class adapter) {
if (adapter.isInstance(getRealObject())) {
return getRealObject();
}
if (adapter.isInstance(this)) {
return this;
}
return null;
}
}
/** Not instantiable by clients. */
private ClipboardSupportManager() {
super();
}
/**
* Configures the extensions on the <tt>clipboardSupport</tt> extension
* point.
* <p>
* <b>Note</b> that this method must only be called by the plug-in class
* on initialization.
* </p>
*
* @param configs the configuration elements representing extensions
*/
public static void configureExtensions(IConfigurationElement[] configs) {
// initialize the arrays
descriptors = new ArrayList[PRIORITIES.size()];
for (int i = 0; i < PRIORITIES.size(); i++) {
descriptors[i] = new ArrayList(0);
}
// create each descriptor and add to appropriate list
for (int i = 0; i < configs.length; i++) {
try {
Descriptor desc = new Descriptor(configs[i]);
descriptors[desc.getPriority()].add(desc);
} catch (CoreException e) {
ClipboardPlugin.getPlugin().log(e.getStatus());
}
}
}
/**
* Retrieves the clipboard support factory (if any) that handles the
* specified <code>EPackage</code>.
* <p>
* <b>WARNING: DO NOT USE.</b> Calling this method does not support the full
* extensibility capabilities of the ClipboardSupport extension point. Use
* the method {@link #lookup(EObject)} instead.
*
* @param ePackage an <code>EPackage</code>
* @return the registered clipboard support factory, or <code>null</code>
* if none was registered or it could not be initialized
*/
public static IClipboardSupportFactory lookup(EPackage ePackage) {
for (int i = PRIORITIES.size() - 1; i >= 0; i--) {
List descriptorsAtPriorityN = descriptors[i];
int size = descriptorsAtPriorityN.size();
for (int j = 0; j < size; j++) {
Descriptor descriptor = (Descriptor) descriptorsAtPriorityN
.get(j);
if (descriptor.provides(ePackage)) {
return descriptor.getFactory();
}
}
}
return null;
}
/**
* Retrieves the clipboard support factory (if any) that handles the
* specified <code>EClass</code>.
* <p>
* <b>WARNING: DO NOT USE.</b> Calling this method does not support the full
* extensibility capabilities of the ClipboardSupport extension point. Use
* the method {@link #lookup(EObject)} instead.
*
* @param eClass an <code>EClass</code>
* @return the registered clipboard support factory, or <code>null</code>
* if none was registered or it could not be initialized
*/
public static IClipboardSupportFactory lookup(EClass eClass) {
return lookup(eClass.getEPackage());
}
/**
* Retrieves the clipboard support factory (if any) that handles the
* specified <code>EObject</code>.
*
* @param eObject an <code>EObject</code>
* @return the registered clipboard support factory, or <code>null</code>
* if none was registered or it could not be initialized
*/
public static IClipboardSupportFactory lookup(EObject eObject) {
for (int i = PRIORITIES.size() - 1; i >= 0; i--) {
List descriptorsAtPriorityN = descriptors[i];
int size = descriptorsAtPriorityN.size();
for (int j = 0; j < size; j++) {
Descriptor descriptor = (Descriptor) descriptorsAtPriorityN
.get(j);
if (descriptor.provides(eObject)) {
return descriptor.getFactory();
}
}
}
return null;
}
/**
* Creates an error status with the specified <code>message</code>.
*
* @param code the error code
* @param message the error message
* @return the status object
*/
static IStatus createErrorStatus(int code, String message) {
return createErrorStatus(
code,
message,
null);
}
/**
* Creates an error status with the specified <code>message</code>.
*
* @param code the error code
* @param message the error message
* @param exception an exception to log
* @return the status object
*/
static IStatus createErrorStatus(int code, String message, Throwable exception) {
return new Status(
IStatus.ERROR,
ClipboardPlugin.getPlugin().getSymbolicName(),
code,
message,
exception);
}
/**
* Descriptor for an extension on the <tt>clipboardSupport</tt> point.
* The descriptor is responsible for lazily initializing the
* {@link IClipboardSupportFactory} on its first access.
*
* @author Christian W. Damus (cdamus)
*/
private static final class Descriptor {
private EPackage ePackage = null;
private IClipboardSupportFactory factory;
private IClipboardSupportPolicy policy;
private IConfigurationElement config;
private int priority = 2;
private boolean factoryClassInitialized = false;
private boolean policyClassInitialized = false;
Descriptor(IConfigurationElement config) throws CoreException {
this.config = config;
String nsUri = config.getAttribute(E_NSURI);
if (nsUri != null && nsUri.length() > 0) {
ePackage = EPackage.Registry.INSTANCE.getEPackage(nsUri);
if (ePackage == null) {
throw new CoreException(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_UNRESOLVED_NSURI,
NLS.bind(EMFClipboardCoreMessages.unresolved_nsUri_ERROR_,
new Object[] {
ClipboardPlugin.EXTPT_CLIPBOARDSUPPORT,
nsUri,
config.getDeclaringExtension().getNamespaceIdentifier()})));
}
} else {
// there needs to be either an nsURI specified or a policy class
String policy = config.getAttribute(E_POLICY);
if ((policy == null) || (policy.length() == 0)) {
throw new CoreException(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_MISSING_CLASS,
NLS.bind(EMFClipboardCoreMessages.missing_nsUri_ERROR_,
new Object[] {
ClipboardPlugin.EXTPT_CLIPBOARDSUPPORT,
config.getDeclaringExtension().getNamespaceIdentifier()})));
}
}
String className = config.getAttribute(E_CLASS);
if ((className == null) || (className.length() == 0)) {
throw new CoreException(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_MISSING_CLASS,
NLS.bind(EMFClipboardCoreMessages.missing_class_ERROR_,
new Object[] {
ClipboardPlugin.EXTPT_CLIPBOARDSUPPORT,
config.getDeclaringExtension().getNamespaceIdentifier()})));
}
String priorityStr = config.getAttribute(E_PRIORITY);
if (priorityStr != null) {
priorityStr = priorityStr.toLowerCase();
if (PRIORITIES.contains(priorityStr)) {
priority = PRIORITIES.indexOf(priorityStr);
}
}
}
/**
* Determines if this descriptor provides for the given EPackage by
* comparing its nsURI with the nsURI attribute field. In this case, the
* policy class is not consulted at all.
*
* @param ePackage the ePackage in question
* @return true if this descriptor provides for the given ePackage
*/
private boolean provides(EPackage ePackage) {
return (ePackage != null && ePackage.equals(getEPackage()));
}
/**
* Determines if this descriptor provides for the given EObject by
* consulting the policy class if there is one provided. If there is no
* policy class provided, then the {@link #provides(EPackage)} method is
* called with the EPackage of the given EObject.
*
* @param eObject
* the eObject in question
* @return true if this descriptor provides for the given eObject
*/
private boolean provides(EObject eObject) {
policy = getPolicy();
if (policy != null) {
try {
return policy.provides(new EObjectAdapter(eObject));
} catch (Throwable e) {
ClipboardPlugin.getPlugin().log(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_MISSING_CLASS,
NLS.bind(EMFClipboardCoreMessages.missing_class_ERROR_,
new Object[] {
IClipboardSupportFactory.class.getName(),
config.getAttribute(E_POLICY)}),
e));
// re-throw fatal errors
if (e instanceof ThreadDeath) {
throw (ThreadDeath) e;
}
if (e instanceof VirtualMachineError) {
throw (VirtualMachineError) e;
}
return false;
}
}
return provides(eObject.eClass().getEPackage());
}
EPackage getEPackage() {
return ePackage;
}
/** @deprecated need a context-based solution */
int getPriority() {
return priority;
}
IClipboardSupportFactory getFactory() {
if (factory == null && !factoryClassInitialized) {
factoryClassInitialized = true;
factory = createFactory();
}
return factory;
}
IClipboardSupportPolicy getPolicy() {
if (policy == null && !policyClassInitialized) {
policyClassInitialized = true;
policy = createPolicy();
}
return policy;
}
private IClipboardSupportFactory createFactory() {
IClipboardSupportFactory result = null;
try {
result = (IClipboardSupportFactory) config.createExecutableExtension(E_CLASS);
} catch (CoreException e) {
ClipboardPlugin.getPlugin().log(e.getStatus());
} catch (Exception e) {
// log any other exception, too (such as ClassCastException)
ClipboardPlugin.getPlugin().log(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_FACTORY_FAILED,
NLS.bind(EMFClipboardCoreMessages.factory_failed_ERROR_,
new Object[] {
IClipboardSupportFactory.class.getName(),
config.getAttribute(E_CLASS)}),
e));
}
return result;
}
private IClipboardSupportPolicy createPolicy() {
IClipboardSupportPolicy result = null;
String policyClassName = config.getAttribute(E_POLICY);
if (policyClassName != null && policyClassName.length() > 0) {
try {
result = (IClipboardSupportPolicy) config.createExecutableExtension(E_POLICY);
} catch (CoreException e) {
ClipboardPlugin.getPlugin().log(e.getStatus());
} catch (Exception e) {
// log any other exception, too (such as ClassCastException)
ClipboardPlugin.getPlugin().log(createErrorStatus(
ClipboardStatusCodes.CLIPBOARDSUPPORT_MISSING_CLASS,
NLS.bind(EMFClipboardCoreMessages.missing_class_ERROR_,
new Object[] {
IClipboardSupportFactory.class.getName(),
config.getAttribute(E_POLICY)}),
e));
}
}
return result;
}
}
}