/******************************************************************************* * Copyright (c) 2000, 2007 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.ui.internal; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; 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", new Class[0]);//$NON-NLS-1$ defaultContributorResourceAdapter = m.invoke(null, new Object[0]); return defaultContributorResourceAdapter; } catch (SecurityException e) { // shouldn't happen - but play it safe } catch (NoSuchMethodException e) { // shouldn't happen - but play it safe } catch (IllegalArgumentException e) { // shouldn't happen - but play it safe } catch (IllegalAccessException e) { // shouldn't happen - but play it safe } catch (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 (int i = 0; i < resourceClassNames.length; i++) { if (resourceClassNames[i].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 (int i= 0; i < interfaces.length; i++) { if (isInstanceOf(interfaces[i], 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, new Object[]{adaptable}); } catch (IllegalArgumentException e) { // shouldn't happen - but play it safe } catch (IllegalAccessException e) { // shouldn't happen - but play it safe } catch (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 e) { // shouldn't happen - but play it safe } catch (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", new Class[]{IAdaptable.class}); //$NON-NLS-1$ return getAdaptedResourceMappingMethod; } catch (SecurityException e) { // do nothing - play it safe } catch (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, new Object[]{adaptable}); if (result != null) { return result; } } catch (IllegalArgumentException e) { // shouldn't happen - but play it safe } catch (IllegalAccessException e) { // shouldn't happen - but play it safe } catch (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 newSelection = new ArrayList(10); for (Iterator it = selection.iterator(); it.hasNext();) { Object element = it.next(); 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 } }