| /******************************************************************************* |
| * Copyright (c) 2000, 2018 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.ui.internal; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.ui.internal.util.BundleUtility; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * Provides access to resource-specific classes, needed to provide backwards |
| * compatibility for resource-specific functions which could not be moved up |
| * from the generic workbench layer to the IDE layer. |
| */ |
| public final class LegacyResourceSupport { |
| |
| private static String[] resourceClassNames = { "org.eclipse.core.resources.IResource", //$NON-NLS-1$ |
| "org.eclipse.core.resources.IContainer", //$NON-NLS-1$ |
| "org.eclipse.core.resources.IFolder", //$NON-NLS-1$ |
| "org.eclipse.core.resources.IProject", //$NON-NLS-1$ |
| "org.eclipse.core.resources.IFile", //$NON-NLS-1$ |
| }; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.core.resources.IResource")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.0 |
| */ |
| private static Class<?> iresourceClass = null; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.core.resources.IFile")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.1 |
| */ |
| private static Class<?> ifileClass; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.ui.IContributorResourceAdapter")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.0 |
| */ |
| private static Class<?> icontributorResourceAdapterClass = null; |
| |
| /** |
| * Cached value of <code> |
| * org.eclipse.ui.IContributorResourceAdapter.getAdaptedResource(IAdaptable) |
| * </code> <code>null</code> if not initialized or not present. |
| * |
| * @since 3.3 |
| */ |
| private static Method getAdaptedResourceMethod = null; |
| |
| /** |
| * Cached value of <code> |
| * org.eclipse.ui.IContributorResourceAdapter2.getAdaptedResourceMapping(IAdaptable) |
| * </code> <code>null</code> if not initialized or not present. |
| * |
| * @since 3.3 |
| */ |
| private static Method getAdaptedResourceMappingMethod = null; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.ui.ide.IContributorResourceAdapter2")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.1 |
| */ |
| private static Class<?> icontributorResourceAdapter2Class = null; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.0 |
| */ |
| private static Class<?> defaultContributorResourceAdapterClass = null; |
| |
| /** |
| * Cached value for reflective result of |
| * <code>DefaultContributorRessourceAdapter.getDefault()</code>. |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.3 |
| */ |
| private static Object defaultContributorResourceAdapter = null; |
| |
| /** |
| * Cached value of |
| * <code>Class.forName("org.eclipse.core.resources.mapping.ResourceMappingr")</code>; |
| * <code>null</code> if not initialized or not present. |
| * |
| * @since 3.0 |
| */ |
| private static Class<?> resourceMappingClass = null; |
| |
| /** |
| * Indicates whether the IDE plug-in (which supplies the resource contribution |
| * adapters) is even around. |
| */ |
| private static boolean resourceAdapterPossible = true; |
| |
| /** |
| * Returns <code>IFile.class</code> or <code>null</code> if the class is not |
| * available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the resources plug-in. |
| * </p> |
| * |
| * @return <code>IFile.class</code> or <code>null</code> if class not available |
| * @since 3.1 |
| */ |
| public static Class<?> getFileClass() { |
| if (ifileClass != null) { |
| // tried before and succeeded |
| return ifileClass; |
| } |
| Class<?> c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.IFile"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| ifileClass = c; |
| } |
| return c; |
| } |
| |
| /** |
| * Returns <code>IResource.class</code> or <code>null</code> if the class is not |
| * available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the resources plug-in. |
| * </p> |
| * |
| * @return <code>IResource.class</code> or <code>null</code> if class not |
| * available |
| * @since 3.0 |
| */ |
| public static Class<?> getResourceClass() { |
| if (iresourceClass != null) { |
| // tried before and succeeded |
| return iresourceClass; |
| } |
| Class<?> c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.IResource"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| iresourceClass = c; |
| } |
| return c; |
| } |
| |
| /** |
| * Returns <code>ResourceMapping.class</code> or <code>null</code> if the class |
| * is not available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the resources plug-in. |
| * </p> |
| * |
| * @return <code>ResourceMapping.class</code> or <code>null</code> if class not |
| * available |
| * @since 3.1 |
| */ |
| public static Class<?> getResourceMappingClass() { |
| if (resourceMappingClass != null) { |
| // tried before and succeeded |
| return resourceMappingClass; |
| } |
| Class<?> c = loadClass("org.eclipse.core.resources", "org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| resourceMappingClass = c; |
| } |
| return c; |
| } |
| |
| /** |
| * Returns <code>IContributorResourceAdapter.class</code> or <code>null</code> |
| * if the class is not available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the IDE plug-in. |
| * </p> |
| * |
| * @return <code>IContributorResourceAdapter.class</code> or <code>null</code> |
| * if class not available |
| * @since 3.0 |
| */ |
| public static Class<?> getIContributorResourceAdapterClass() { |
| if (icontributorResourceAdapterClass != null) { |
| // tried before and succeeded |
| return icontributorResourceAdapterClass; |
| } |
| Class<?> c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.IContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| icontributorResourceAdapterClass = c; |
| } |
| return c; |
| } |
| |
| /** |
| * Returns <code>IContributorResourceAdapter2.class</code> or <code>null</code> |
| * if the class is not available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the IDE plug-in. |
| * </p> |
| * |
| * @return <code>IContributorResourceAdapter.class</code> or <code>null</code> |
| * if class not available |
| * @since 3.1 |
| */ |
| public static Class<?> getIContributorResourceAdapter2Class() { |
| if (icontributorResourceAdapter2Class != null) { |
| // tried before and succeeded |
| return icontributorResourceAdapter2Class; |
| } |
| Class<?> c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.ide.IContributorResourceAdapter2"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| icontributorResourceAdapter2Class = c; |
| } |
| return c; |
| } |
| |
| private static Class<?> loadClass(String bundleName, String className) { |
| if (!resourceAdapterPossible) { |
| // tried before and failed |
| return null; |
| } |
| Bundle bundle = Platform.getBundle(bundleName); |
| if (bundle == null) { |
| // Required plug-in is not around |
| // assume that it will never be around |
| resourceAdapterPossible = false; |
| return null; |
| } |
| // Required plug-in is around |
| // it's not our job to activate the plug-in |
| if (!BundleUtility.isActivated(bundle)) { |
| // assume it might come alive later |
| resourceAdapterPossible = true; |
| return null; |
| } |
| try { |
| return bundle.loadClass(className); |
| } catch (ClassNotFoundException e) { |
| // unable to load the class - sounds pretty serious |
| // treat as if the plug-in were unavailable |
| resourceAdapterPossible = false; |
| return null; |
| } |
| } |
| |
| /** |
| * Returns <code>DefaultContributorResourceAdapter.class</code> or |
| * <code>null</code> if the class is not available. |
| * <p> |
| * This method exists to avoid explicit references from the generic workbench to |
| * the IDE plug-in. |
| * </p> |
| * |
| * @return <code>DefaultContributorResourceAdapter.class</code> or |
| * <code>null</code> if class not available |
| * @since 3.0 |
| */ |
| public static Class<?> getDefaultContributorResourceAdapterClass() { |
| if (defaultContributorResourceAdapterClass != null) { |
| // tried before and succeeded |
| return defaultContributorResourceAdapterClass; |
| } |
| Class<?> c = loadClass("org.eclipse.ui.ide", "org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$ |
| if (c != null) { |
| // The class was found so record it |
| defaultContributorResourceAdapterClass = c; |
| } |
| return c; |
| } |
| |
| private static Object getDefaultContributorResourceAdapter() { |
| if (defaultContributorResourceAdapter != null) { |
| return defaultContributorResourceAdapter; |
| } |
| |
| // reflective equivalent of |
| // resourceAdapter = DefaultContributorResourceAdapter.getDefault(); |
| |
| Class<?> c = LegacyResourceSupport.getDefaultContributorResourceAdapterClass(); |
| if (c != null) { |
| try { |
| Method m = c.getDeclaredMethod("getDefault");//$NON-NLS-1$ |
| defaultContributorResourceAdapter = m.invoke(null); |
| return defaultContributorResourceAdapter; |
| } catch (SecurityException | NoSuchMethodException | IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { |
| // shouldn't happen - but play it safe |
| } |
| |
| } |
| |
| return null; |
| |
| } |
| |
| /** |
| * Returns <code>true</code> if the provided type name is an |
| * <code>IResource</code>, and <code>false</code> otherwise. |
| * |
| * @param objectClassName |
| * @return <code>true</code> if the provided type name is an |
| * <code>IResource</code>, and <code>false</code> otherwise. |
| * |
| * @since 3.1 |
| */ |
| public static boolean isResourceType(String objectClassName) { |
| for (String resourceClassName : resourceClassNames) { |
| if (resourceClassName.equals(objectClassName)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns <code>true</code> if the provided type name is an |
| * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, and |
| * <code>false</code> otherwise. |
| * |
| * @param objectClassName |
| * @return <code>true</code> if the provided type name is an |
| * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, |
| * and <code>false</code> otherwise. |
| * |
| * @since 3.1 |
| */ |
| public static boolean isResourceMappingType(String objectClassName) { |
| return objectClassName.equals("org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns the class search order starting with <code>extensibleClass</code>. |
| * The search order is defined in this class' comment. |
| * |
| * @since 3.1 |
| */ |
| private static boolean isInstanceOf(Class<?> clazz, String type) { |
| if (clazz.getName().equals(type)) { |
| return true; |
| } |
| Class<?> superClass = clazz.getSuperclass(); |
| if (superClass != null && isInstanceOf(superClass, type)) { |
| return true; |
| } |
| Class<?>[] interfaces = clazz.getInterfaces(); |
| for (Class<?> currentInterface : interfaces) { |
| if (isInstanceOf(currentInterface, type)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the adapted resource using the |
| * <code>IContributorResourceAdapter</code> registered for the given object. If |
| * the Resources plug-in is not loaded the object can not be adapted. |
| * |
| * @param object the object to adapt to <code>IResource</code>. |
| * @return returns the adapted resource using the |
| * <code>IContributorResourceAdapter</code> or <code>null</code> if the |
| * Resources plug-in is not loaded. |
| * |
| * @since 3.1 |
| */ |
| public static Object getAdaptedContributorResource(Object object) { |
| Class<?> resourceClass = LegacyResourceSupport.getResourceClass(); |
| if (resourceClass == null) { |
| return null; |
| } |
| if (resourceClass.isInstance(object)) { |
| return null; |
| } |
| if (object instanceof IAdaptable) { |
| IAdaptable adaptable = (IAdaptable) object; |
| Class<?> contributorResourceAdapterClass = LegacyResourceSupport.getIContributorResourceAdapterClass(); |
| if (contributorResourceAdapterClass == null) { |
| return adaptable.getAdapter(resourceClass); |
| } |
| Object resourceAdapter = adaptable.getAdapter(contributorResourceAdapterClass); |
| if (resourceAdapter == null) { |
| resourceAdapter = LegacyResourceSupport.getDefaultContributorResourceAdapter(); |
| if (resourceAdapter == null) { |
| return null; |
| } |
| } |
| // reflective equivalent of |
| // result = ((IContributorResourceAdapter) |
| // resourceAdapter).getAdaptedResource(adaptable); |
| |
| Method m = getContributorResourceAdapterGetAdaptedResourceMethod(); |
| if (m != null) { |
| try { |
| return m.invoke(resourceAdapter, adaptable); |
| } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { |
| // shouldn't happen - but play it safe |
| } |
| } |
| |
| } |
| return null; |
| } |
| |
| private static Method getContributorResourceAdapterGetAdaptedResourceMethod() { |
| if (getAdaptedResourceMethod != null) { |
| return getAdaptedResourceMethod; |
| } |
| |
| Class<?> c = getIContributorResourceAdapterClass(); |
| if (c != null) { |
| try { |
| getAdaptedResourceMethod = c.getDeclaredMethod("getAdaptedResource", new Class[] { IAdaptable.class }); //$NON-NLS-1$ |
| return getAdaptedResourceMethod; |
| } catch (SecurityException | NoSuchMethodException e) { |
| // shouldn't happen - but play it safe |
| } |
| |
| } |
| |
| return null; |
| } |
| |
| private static Method getContributorResourceAdapter2GetAdaptedResourceMappingMethod() { |
| if (getAdaptedResourceMappingMethod != null) { |
| return getAdaptedResourceMappingMethod; |
| } |
| |
| Class<?> c = getIContributorResourceAdapter2Class(); |
| if (c != null) { |
| try { |
| getAdaptedResourceMappingMethod = c.getDeclaredMethod("getAdaptedResourceMapping", //$NON-NLS-1$ |
| new Class<?>[] { IAdaptable.class }); |
| return getAdaptedResourceMappingMethod; |
| } catch (SecurityException | NoSuchMethodException e) { |
| // do nothing - play it safe |
| } |
| |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns the adapted resource mapping using the |
| * <code>IContributorResourceAdapter2</code> registered for the given object. If |
| * the Resources plug-in is not loaded the object can not be adapted. |
| * |
| * @param object the object to adapt to <code>ResourceMapping</code>. |
| * @return returns the adapted resource using the |
| * <code>IContributorResourceAdapter2</code> or <code>null</code> if the |
| * Resources plug-in is not loaded. |
| * |
| * @since 3.1 |
| */ |
| public static Object getAdaptedContributorResourceMapping(Object object) { |
| Class<?> resourceMappingClass = LegacyResourceSupport.getResourceMappingClass(); |
| if (resourceMappingClass == null) { |
| return null; |
| } |
| if (resourceMappingClass.isInstance(object)) { |
| return null; |
| } |
| if (object instanceof IAdaptable) { |
| IAdaptable adaptable = (IAdaptable) object; |
| Class<?> contributorResourceAdapterClass = LegacyResourceSupport.getIContributorResourceAdapterClass(); |
| if (contributorResourceAdapterClass == null) { |
| return adaptable.getAdapter(resourceMappingClass); |
| } |
| Class<?> contributorResourceAdapter2Class = LegacyResourceSupport.getIContributorResourceAdapter2Class(); |
| if (contributorResourceAdapter2Class == null) { |
| return adaptable.getAdapter(resourceMappingClass); |
| } |
| Object resourceAdapter = adaptable.getAdapter(contributorResourceAdapterClass); |
| Object resourceMappingAdapter; |
| if (resourceAdapter != null && contributorResourceAdapter2Class.isInstance(resourceAdapter)) { |
| // The registered adapter also handles resource mappings |
| resourceMappingAdapter = resourceAdapter; |
| } else { |
| // Either there is no registered adapter or it doesn't handle resource mappings. |
| // In this case, we will use the default contribution adapter |
| resourceMappingAdapter = getDefaultContributorResourceAdapter(); |
| if (resourceMappingAdapter == null) { |
| return null; |
| } |
| } |
| |
| // reflective equivalent of |
| // result = ((IContributorResourceAdapter2) |
| // resourceAdapter).getAdaptedResource(adaptable); |
| |
| Method m = getContributorResourceAdapter2GetAdaptedResourceMappingMethod(); |
| if (m != null) { |
| |
| try { |
| Object result = m.invoke(resourceMappingAdapter, adaptable); |
| if (result != null) { |
| return result; |
| } |
| } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { |
| // shouldn't happen - but play it safe |
| } |
| |
| } |
| |
| // If we get here, that means that the object in question doesn't adapt to |
| // resource mapping |
| // and it's contributed adapter doesn't do the adaptation either. |
| // Before we fail, we will attempt to adapt the object to IResource and then to |
| // ResourceMapping |
| Object r = getAdaptedContributorResource(object); |
| if (r != null) { |
| return Platform.getAdapterManager().getAdapter(r, resourceMappingClass); |
| } |
| |
| // we've exhausted every avenue so just return null |
| return null; |
| } |
| // Fallback to querying the adapter manager directly when the object isn't an |
| // IAdaptable |
| return Platform.getAdapterManager().getAdapter(object, resourceMappingClass); |
| } |
| |
| /** |
| * Adapts a selection to the given objectClass considering the Legacy resource |
| * support. Non resource objectClasses are adapted using the |
| * <code>IAdapterManager</code> and this may load the plug-in that contributes |
| * the adapter factory. |
| * <p> |
| * The returned selection will only contain elements successfully adapted. |
| * </p> |
| * |
| * @param selection the selection to adapt |
| * @param objectClass the class name to adapt the selection to |
| * @return an adapted selection |
| * |
| * @since 3.1 |
| */ |
| public static IStructuredSelection adaptSelection(IStructuredSelection selection, String objectClass) { |
| List<Object> newSelection = new ArrayList<>(10); |
| for (Object element : selection) { |
| Object adaptedElement = getAdapter(element, objectClass); |
| if (adaptedElement != null) { |
| newSelection.add(adaptedElement); |
| } |
| } |
| return new StructuredSelection(newSelection); |
| } |
| |
| /** |
| * Adapts an object to a specified objectClass considering the Legacy resource |
| * support. Non resource objectClasses are adapted using the |
| * <code>IAdapterManager</code> and this may load the plug-in that contributes |
| * the adapter factory. |
| * <p> |
| * The returned selection will be of the same size as the original, and elements |
| * that could not be adapted are added to the returned selection as is. |
| * </p> |
| * |
| * @param element the element to adapt |
| * @param objectClass the class name to adapt the selection to |
| * @return an adapted element or <code>null</code> if the element could not be |
| * adapted. |
| * |
| * @since 3.1 |
| */ |
| public static Object getAdapter(Object element, String objectClass) { |
| Object adaptedElement = null; |
| if (isInstanceOf(element.getClass(), objectClass)) { |
| adaptedElement = element; |
| } else // Handle IResource |
| if (LegacyResourceSupport.isResourceType(objectClass)) { |
| adaptedElement = getAdaptedResource(element); |
| } else if (LegacyResourceSupport.isResourceMappingType(objectClass)) { |
| adaptedElement = getAdaptedResourceMapping(element); |
| if (adaptedElement == null) { |
| // The object doesn't adapt directly so check if it adapts transitively |
| Object resource = getAdaptedResource(element); |
| if (resource != null) { |
| adaptedElement = ((IAdaptable) resource) |
| .getAdapter(LegacyResourceSupport.getResourceMappingClass()); |
| } |
| } |
| } else { |
| // Handle all other types by using the adapter factory. |
| adaptedElement = Platform.getAdapterManager().loadAdapter(element, objectClass); |
| } |
| return adaptedElement; |
| } |
| |
| /** |
| * Adapt the given element to an <code>IResource</code> using the following |
| * search order: |
| * <ol> |
| * <li>using the IContributorResourceAdapter registered for the given element, |
| * or |
| * <li>directly asking the element if it adapts. |
| * </ol> |
| * |
| * @param element the element to adapt |
| * @return an <code>IResource</code> instance if the element could be adapted or |
| * <code>null</code> otherwise. |
| * @since 3.1 |
| */ |
| public static Object getAdaptedResource(Object element) { |
| Class<?> resourceClass = LegacyResourceSupport.getResourceClass(); |
| Object adaptedValue = null; |
| if (resourceClass != null) { |
| if (resourceClass.isInstance(element)) { |
| adaptedValue = element; |
| } else { |
| adaptedValue = LegacyResourceSupport.getAdaptedContributorResource(element); |
| } |
| } |
| return adaptedValue; |
| } |
| |
| /** |
| * Adapt the given element to an <code>ResourceMapping</code> using the |
| * following search order: |
| * <ol> |
| * <li>using the IContributorResourceAdapter2 registered for the given element, |
| * or |
| * <li>directly asking the element if it adapts. |
| * </ol> |
| * |
| * @param element the element to adapt |
| * @return an <code>ResourceMapping</code> instance if the element could be |
| * adapted or <code>null</code> otherwise. |
| * @since 3.1 |
| */ |
| public static Object getAdaptedResourceMapping(Object element) { |
| Class<?> resourceMappingClass = LegacyResourceSupport.getResourceMappingClass(); |
| Object adaptedValue = null; |
| if (resourceMappingClass != null) { |
| if (resourceMappingClass.isInstance(element)) { |
| adaptedValue = element; |
| } else { |
| adaptedValue = LegacyResourceSupport.getAdaptedContributorResourceMapping(element); |
| } |
| } |
| return adaptedValue; |
| } |
| |
| /** |
| * Prevents construction |
| */ |
| private LegacyResourceSupport() { |
| // do nothing |
| } |
| |
| } |