blob: 507e19bac9971dfdb88e75b8b63547705b778ca5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2013 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 - Initial API and implementation
* Oracle - Fix for bug 408506
******************************************************************************/
package org.eclipse.core.internal.adapter;
import java.util.ArrayList;
import org.eclipse.core.internal.registry.Handle;
import org.eclipse.core.internal.registry.RegistryMessages;
import org.eclipse.core.internal.runtime.IAdapterFactoryExt;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
/**
* Instances of this class represent adapter factories that have been
* contributed via the adapters extension point. The concrete factory is not
* loaded until the factory's plugin is loaded, AND until the factory is
* requested to supply an adapter.
*/
class AdapterFactoryProxy implements IAdapterFactory, IAdapterFactoryExt {
private IConfigurationElement element;
/**
* The real factory. Null until the factory is loaded.
*/
private IAdapterFactory factory;
private boolean factoryLoaded = false;
/**
* Store Id of the declaring extension. We might need it in case
* the owner goes away (in this case element becomes invalid).
*/
private String ownerId;
private int internalOwnerID = -1;
/**
* Creates a new factory proxy based on the given configuration element.
* Returns the new proxy, or null if the element could not be created.
*/
public static AdapterFactoryProxy createProxy(IConfigurationElement element) {
AdapterFactoryProxy result = new AdapterFactoryProxy();
result.element = element;
IExtension extension = element.getDeclaringExtension();
result.ownerId = extension.getUniqueIdentifier();
if (extension instanceof Handle)
result.internalOwnerID = ((Handle) extension).getId();
if ("factory".equals(element.getName())) //$NON-NLS-1$
return result;
result.logError();
return null;
}
public boolean originatesFrom(IExtension extension) {
String id = extension.getUniqueIdentifier();
if (id != null) // match by public ID declared in XML
return id.equals(ownerId);
if (!(extension instanceof Handle))
return false; // should never happen
return (internalOwnerID == ((Handle) extension).getId());
}
String getAdaptableType() {
//cannot return null because it can cause startup failure
String result = element.getAttribute("adaptableType"); //$NON-NLS-1$
if (result != null)
return result;
logError();
return ""; //$NON-NLS-1$
}
@Override
public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
if (!factoryLoaded)
loadFactory(false);
return factory == null ? null : factory.getAdapter(adaptableObject, adapterType);
}
@Override
public Class<?>[] getAdapterList() {
if (!factoryLoaded)
loadFactory(false);
return factory == null ? null : factory.getAdapterList();
}
@Override
public String[] getAdapterNames() {
IConfigurationElement[] children = element.getChildren();
ArrayList<String> adapters = new ArrayList<>(children.length);
for (int i = 0; i < children.length; i++) {
//ignore unknown children for forward compatibility
if ("adapter".equals(children[i].getName())) { //$NON-NLS-1$
String type = children[i].getAttribute("type"); //$NON-NLS-1$
if (type != null)
adapters.add(type);
}
}
if (adapters.isEmpty())
logError();
return adapters.toArray(new String[adapters.size()]);
}
IExtension getExtension() {
return element.getDeclaringExtension();
}
/**
* Loads the real adapter factory, but only if its associated plug-in is
* already loaded. Returns the real factory if it was successfully loaded.
* @param force if <code>true</code> the plugin providing the
* factory will be loaded if necessary, otherwise no plugin activations
* will occur.
*/
@Override
public synchronized IAdapterFactory loadFactory(boolean force) {
if (factory != null || factoryLoaded)
return factory;
String contributorName = element.getContributor().getName();
boolean isActive;
// Different VMs have different degrees of "laziness" for the class loading.
// To make sure that VM won't try to load EquinoxUtils before getting into
// this try-catch block, the fully qualified name is used (removing entry for
// the EquinoxUtils from the import list).
try {
isActive = org.eclipse.core.internal.registry.osgi.EquinoxUtils.isActive(contributorName);
} catch (NoClassDefFoundError noClass) {
// This block will only be triggered if VM loads classes in a very "eager" way.
isActive = true;
}
if (!force && !isActive)
return null;
try {
factory = (IAdapterFactory) element.createExecutableExtension("class"); //$NON-NLS-1$
} catch (CoreException e) {
String msg = NLS.bind(RegistryMessages.adapters_cantInstansiate, getAdaptableType(), element.getContributor().getName());
RuntimeLog.log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, msg, e));
} finally {
//set to true to prevent repeated attempts to load a broken factory
factoryLoaded = true;
}
return factory;
}
/**
* The factory extension was malformed. Log an appropriate exception
*/
private void logError() {
String msg = NLS.bind(RegistryMessages.adapters_badAdapterFactory, element.getContributor().getName());
RuntimeLog.log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, msg, null));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("AdapterFactoryProxy [contributor: "); //$NON-NLS-1$
sb.append(element.getContributor());
sb.append(", adaptableType: "); //$NON-NLS-1$
sb.append(getAdaptableType());
if (factory != null) {
sb.append(", factory: "); //$NON-NLS-1$
sb.append(factory);
}
sb.append("]"); //$NON-NLS-1$
return sb.toString();
}
}