001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.lang.reflect.Method;
014: import java.util.ArrayList;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.core.runtime.IAdaptable;
019: import org.eclipse.core.runtime.Platform;
020: import org.eclipse.jface.viewers.IStructuredSelection;
021: import org.eclipse.jface.viewers.StructuredSelection;
022: import org.eclipse.ui.internal.util.BundleUtility;
023: import org.osgi.framework.Bundle;
024:
025: /**
026: * Provides access to resource-specific classes, needed to provide
027: * backwards compatibility for resource-specific functions which
028: * could not be moved up from the generic workbench layer to the
029: * IDE layer.
030: */
031: public final class LegacyResourceSupport {
032:
033: private static String[] resourceClassNames = {
034: "org.eclipse.core.resources.IResource", //$NON-NLS-1$
035: "org.eclipse.core.resources.IContainer", //$NON-NLS-1$
036: "org.eclipse.core.resources.IFolder", //$NON-NLS-1$
037: "org.eclipse.core.resources.IProject", //$NON-NLS-1$
038: "org.eclipse.core.resources.IFile", //$NON-NLS-1$
039: };
040:
041: /**
042: * Cached value of
043: * <code>Class.forName("org.eclipse.core.resources.IResource")</code>;
044: * <code>null</code> if not initialized or not present.
045: * @since 3.0
046: */
047: private static Class iresourceClass = null;
048:
049: /**
050: * Cached value of
051: * <code>Class.forName("org.eclipse.core.resources.IFile")</code>;
052: * <code>null</code> if not initialized or not present.
053: * @since 3.1
054: */
055: private static Class ifileClass;
056:
057: /**
058: * Cached value of
059: * <code>Class.forName("org.eclipse.ui.IContributorResourceAdapter")</code>;
060: * <code>null</code> if not initialized or not present.
061: * @since 3.0
062: */
063: private static Class icontributorResourceAdapterClass = null;
064:
065: /**
066: * Cached value of </code> org.eclipse.ui.IContributorResourceAdapter.getAdaptedResource(IAdaptable) </code>
067: * <code>null</code> if not initialized or not present.
068: *
069: * @since 3.3
070: */
071: private static Method getAdaptedResourceMethod = null;
072:
073: /**
074: * Cached value of </code> org.eclipse.ui.IContributorResourceAdapter2.getAdaptedResourceMapping(IAdaptable) </code>
075: * <code>null</code> if not initialized or not present.
076: *
077: * @since 3.3
078: */
079: private static Method getAdaptedResourceMappingMethod = null;
080:
081: /**
082: * Cached value of
083: * <code>Class.forName("org.eclipse.ui.ide.IContributorResourceAdapter2")</code>;
084: * <code>null</code> if not initialized or not present.
085: * @since 3.1
086: */
087: private static Class icontributorResourceAdapter2Class = null;
088:
089: /**
090: * Cached value of
091: * <code>Class.forName("org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter")</code>;
092: * <code>null</code> if not initialized or not present.
093: * @since 3.0
094: */
095: private static Class defaultContributorResourceAdapterClass = null;
096:
097: /**
098: * Cached value for reflective result of <code>DefaultContributorRessourceAdapter.getDefault()</code>.
099: * <code>null</code> if not initialized or not present.
100: *
101: * @since 3.3
102: */
103: private static Object defaultContributorResourceAdapter = null;
104:
105: /**
106: * Cached value of
107: * <code>Class.forName("org.eclipse.core.resources.mapping.ResourceMappingr")</code>;
108: * <code>null</code> if not initialized or not present.
109: * @since 3.0
110: */
111: private static Class resourceMappingClass = null;
112:
113: /**
114: * Indicates whether the IDE plug-in (which supplies the
115: * resource contribution adapters) is even around.
116: */
117: private static boolean resourceAdapterPossible = true;
118:
119: /**
120: * Returns <code>IFile.class</code> or <code>null</code> if the
121: * class is not available.
122: * <p>
123: * This method exists to avoid explicit references from the generic
124: * workbench to the resources plug-in.
125: * </p>
126: *
127: * @return <code>IFile.class</code> or <code>null</code> if class
128: * not available
129: * @since 3.1
130: */
131: public static Class getFileClass() {
132: if (ifileClass != null) {
133: // tried before and succeeded
134: return ifileClass;
135: }
136: Class c = loadClass(
137: "org.eclipse.core.resources", "org.eclipse.core.resources.IFile"); //$NON-NLS-1$ //$NON-NLS-2$
138: if (c != null) {
139: // The class was found so record it
140: ifileClass = c;
141: }
142: return c;
143: }
144:
145: /**
146: * Returns <code>IResource.class</code> or <code>null</code> if the
147: * class is not available.
148: * <p>
149: * This method exists to avoid explicit references from the generic
150: * workbench to the resources plug-in.
151: * </p>
152: *
153: * @return <code>IResource.class</code> or <code>null</code> if class
154: * not available
155: * @since 3.0
156: */
157: public static Class getResourceClass() {
158: if (iresourceClass != null) {
159: // tried before and succeeded
160: return iresourceClass;
161: }
162: Class c = loadClass(
163: "org.eclipse.core.resources", "org.eclipse.core.resources.IResource"); //$NON-NLS-1$ //$NON-NLS-2$
164: if (c != null) {
165: // The class was found so record it
166: iresourceClass = c;
167: }
168: return c;
169: }
170:
171: /**
172: * Returns <code>ResourceMapping.class</code> or <code>null</code> if the
173: * class is not available.
174: * <p>
175: * This method exists to avoid explicit references from the generic
176: * workbench to the resources plug-in.
177: * </p>
178: *
179: * @return <code>ResourceMapping.class</code> or <code>null</code> if class
180: * not available
181: * @since 3.1
182: */
183: public static Class getResourceMappingClass() {
184: if (resourceMappingClass != null) {
185: // tried before and succeeded
186: return resourceMappingClass;
187: }
188: Class c = loadClass(
189: "org.eclipse.core.resources", "org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$ //$NON-NLS-2$
190: if (c != null) {
191: // The class was found so record it
192: resourceMappingClass = c;
193: }
194: return c;
195: }
196:
197: /**
198: * Returns <code>IContributorResourceAdapter.class</code> or
199: * <code>null</code> if the class is not available.
200: * <p>
201: * This method exists to avoid explicit references from the generic
202: * workbench to the IDE plug-in.
203: * </p>
204: *
205: * @return <code>IContributorResourceAdapter.class</code> or
206: * <code>null</code> if class not available
207: * @since 3.0
208: */
209: public static Class getIContributorResourceAdapterClass() {
210: if (icontributorResourceAdapterClass != null) {
211: // tried before and succeeded
212: return icontributorResourceAdapterClass;
213: }
214: Class c = loadClass(
215: "org.eclipse.ui.ide", "org.eclipse.ui.IContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$
216: if (c != null) {
217: // The class was found so record it
218: icontributorResourceAdapterClass = c;
219: }
220: return c;
221: }
222:
223: /**
224: * Returns <code>IContributorResourceAdapter2.class</code> or
225: * <code>null</code> if the class is not available.
226: * <p>
227: * This method exists to avoid explicit references from the generic
228: * workbench to the IDE plug-in.
229: * </p>
230: *
231: * @return <code>IContributorResourceAdapter.class</code> or
232: * <code>null</code> if class not available
233: * @since 3.1
234: */
235: public static Class getIContributorResourceAdapter2Class() {
236: if (icontributorResourceAdapter2Class != null) {
237: // tried before and succeeded
238: return icontributorResourceAdapter2Class;
239: }
240: Class c = loadClass(
241: "org.eclipse.ui.ide", "org.eclipse.ui.ide.IContributorResourceAdapter2"); //$NON-NLS-1$ //$NON-NLS-2$
242: if (c != null) {
243: // The class was found so record it
244: icontributorResourceAdapter2Class = c;
245: }
246: return c;
247: }
248:
249: private static Class loadClass(String bundleName, String className) {
250: if (!resourceAdapterPossible) {
251: // tried before and failed
252: return null;
253: }
254: Bundle bundle = Platform.getBundle(bundleName);
255: if (bundle == null) {
256: // Required plug-in is not around
257: // assume that it will never be around
258: resourceAdapterPossible = false;
259: return null;
260: }
261: // Required plug-in is around
262: // it's not our job to activate the plug-in
263: if (!BundleUtility.isActivated(bundle)) {
264: // assume it might come alive later
265: resourceAdapterPossible = true;
266: return null;
267: }
268: try {
269: return bundle.loadClass(className);
270: } catch (ClassNotFoundException e) {
271: // unable to load the class - sounds pretty serious
272: // treat as if the plug-in were unavailable
273: resourceAdapterPossible = false;
274: return null;
275: }
276: }
277:
278: /**
279: * Returns <code>DefaultContributorResourceAdapter.class</code> or
280: * <code>null</code> if the class is not available.
281: * <p>
282: * This method exists to avoid explicit references from the generic
283: * workbench to the IDE plug-in.
284: * </p>
285: *
286: * @return <code>DefaultContributorResourceAdapter.class</code> or
287: * <code>null</code> if class not available
288: * @since 3.0
289: */
290: public static Class getDefaultContributorResourceAdapterClass() {
291: if (defaultContributorResourceAdapterClass != null) {
292: // tried before and succeeded
293: return defaultContributorResourceAdapterClass;
294: }
295: Class c = loadClass(
296: "org.eclipse.ui.ide", "org.eclipse.ui.internal.ide.DefaultContributorResourceAdapter"); //$NON-NLS-1$ //$NON-NLS-2$
297: if (c != null) {
298: // The class was found so record it
299: defaultContributorResourceAdapterClass = c;
300: }
301: return c;
302: }
303:
304: private static Object getDefaultContributorResourceAdapter() {
305: if (defaultContributorResourceAdapter != null) {
306: return defaultContributorResourceAdapter;
307: }
308:
309: // reflective equivalent of
310: // resourceAdapter = DefaultContributorResourceAdapter.getDefault();
311:
312: Class c = LegacyResourceSupport
313: .getDefaultContributorResourceAdapterClass();
314: if (c != null) {
315: try {
316: Method m = c.getDeclaredMethod(
317: "getDefault", new Class[0]);//$NON-NLS-1$
318: defaultContributorResourceAdapter = m.invoke(null,
319: new Object[0]);
320: return defaultContributorResourceAdapter;
321: } catch (SecurityException e) {
322: // shouldn't happen - but play it safe
323: } catch (NoSuchMethodException e) {
324: // shouldn't happen - but play it safe
325: } catch (IllegalArgumentException e) {
326: // shouldn't happen - but play it safe
327: } catch (IllegalAccessException e) {
328: // shouldn't happen - but play it safe
329: } catch (InvocationTargetException e) {
330: // shouldn't happen - but play it safe
331: }
332:
333: }
334:
335: return null;
336:
337: }
338:
339: /**
340: * Returns <code>true</code> if the provided type name is an
341: * <code>IResource</code>, and <code>false</code> otherwise.
342: * @param objectClassName
343: * @return <code>true</code> if the provided type name is an
344: * <code>IResource</code>, and <code>false</code> otherwise.
345: *
346: * @since 3.1
347: */
348: public static boolean isResourceType(String objectClassName) {
349: for (int i = 0; i < resourceClassNames.length; i++) {
350: if (resourceClassNames[i].equals(objectClassName)) {
351: return true;
352: }
353: }
354: return false;
355: }
356:
357: /**
358: * Returns <code>true</code> if the provided type name is an
359: * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, and <code>false</code> otherwise.
360: * @param objectClassName
361: * @return <code>true</code> if the provided type name is an
362: * <code>"org.eclipse.core.resources.mapping.ResourceMapping"</code>, and <code>false</code> otherwise.
363: *
364: * @since 3.1
365: */
366: public static boolean isResourceMappingType(String objectClassName) {
367: return objectClassName
368: .equals("org.eclipse.core.resources.mapping.ResourceMapping"); //$NON-NLS-1$
369: }
370:
371: /**
372: * Returns the class search order starting with <code>extensibleClass</code>.
373: * The search order is defined in this class' comment.
374: *
375: * @since 3.1
376: */
377: private static boolean isInstanceOf(Class clazz, String type) {
378: if (clazz.getName().equals(type)) {
379: return true;
380: }
381: Class super Class = clazz.getSuperclass();
382: if (super Class != null && isInstanceOf(super Class, type)) {
383: return true;
384: }
385: Class[] interfaces = clazz.getInterfaces();
386: for (int i = 0; i < interfaces.length; i++) {
387: if (isInstanceOf(interfaces[i], type)) {
388: return true;
389: }
390: }
391: return false;
392: }
393:
394: /**
395: * Returns the adapted resource using the <code>IContributorResourceAdapter</code>
396: * registered for the given object. If the Resources plug-in is not loaded
397: * the object can not be adapted.
398: *
399: * @param object the object to adapt to <code>IResource</code>.
400: * @return returns the adapted resource using the <code>IContributorResourceAdapter</code>
401: * or <code>null</code> if the Resources plug-in is not loaded.
402: *
403: * @since 3.1
404: */
405: public static Object getAdaptedContributorResource(Object object) {
406: Class resourceClass = LegacyResourceSupport.getResourceClass();
407: if (resourceClass == null) {
408: return null;
409: }
410: if (resourceClass.isInstance(object)) {
411: return null;
412: }
413: if (object instanceof IAdaptable) {
414: IAdaptable adaptable = (IAdaptable) object;
415: Class contributorResourceAdapterClass = LegacyResourceSupport
416: .getIContributorResourceAdapterClass();
417: if (contributorResourceAdapterClass == null) {
418: return adaptable.getAdapter(resourceClass);
419: }
420: Object resourceAdapter = adaptable
421: .getAdapter(contributorResourceAdapterClass);
422: if (resourceAdapter == null) {
423: resourceAdapter = LegacyResourceSupport
424: .getDefaultContributorResourceAdapter();
425: if (resourceAdapter == null) {
426: return null;
427: }
428: }
429: // reflective equivalent of
430: // result = ((IContributorResourceAdapter) resourceAdapter).getAdaptedResource(adaptable);
431:
432: Method m = getContributorResourceAdapterGetAdaptedResourceMethod();
433: if (m != null) {
434: try {
435: return m.invoke(resourceAdapter,
436: new Object[] { adaptable });
437: } catch (IllegalArgumentException e) {
438: // shouldn't happen - but play it safe
439: } catch (IllegalAccessException e) {
440: // shouldn't happen - but play it safe
441: } catch (InvocationTargetException e) {
442: // shouldn't happen - but play it safe
443: }
444: }
445:
446: }
447: return null;
448: }
449:
450: private static Method getContributorResourceAdapterGetAdaptedResourceMethod() {
451: if (getAdaptedResourceMethod != null) {
452: return getAdaptedResourceMethod;
453: }
454:
455: Class c = getIContributorResourceAdapterClass();
456: if (c != null) {
457: try {
458: getAdaptedResourceMethod = c
459: .getDeclaredMethod(
460: "getAdaptedResource", new Class[] { IAdaptable.class }); //$NON-NLS-1$
461: return getAdaptedResourceMethod;
462: } catch (SecurityException e) {
463: // shouldn't happen - but play it safe
464: } catch (NoSuchMethodException e) {
465: // shouldn't happen - but play it safe
466: }
467:
468: }
469:
470: return null;
471: }
472:
473: private static Method getContributorResourceAdapter2GetAdaptedResourceMappingMethod() {
474: if (getAdaptedResourceMappingMethod != null) {
475: return getAdaptedResourceMappingMethod;
476: }
477:
478: Class c = getIContributorResourceAdapter2Class();
479: if (c != null) {
480: try {
481: getAdaptedResourceMappingMethod = c
482: .getDeclaredMethod(
483: "getAdaptedResourceMapping", new Class[] { IAdaptable.class }); //$NON-NLS-1$
484: return getAdaptedResourceMappingMethod;
485: } catch (SecurityException e) {
486: // do nothing - play it safe
487: } catch (NoSuchMethodException e) {
488: // do nothing - play it safe
489: }
490:
491: }
492:
493: return null;
494: }
495:
496: /**
497: * Returns the adapted resource mapping using the <code>IContributorResourceAdapter2</code>
498: * registered for the given object. If the Resources plug-in is not loaded
499: * the object can not be adapted.
500: *
501: * @param object the object to adapt to <code>ResourceMapping</code>.
502: * @return returns the adapted resource using the <code>IContributorResourceAdapter2</code>
503: * or <code>null</code> if the Resources plug-in is not loaded.
504: *
505: * @since 3.1
506: */
507: public static Object getAdaptedContributorResourceMapping(
508: Object object) {
509: Class resourceMappingClass = LegacyResourceSupport
510: .getResourceMappingClass();
511: if (resourceMappingClass == null) {
512: return null;
513: }
514: if (resourceMappingClass.isInstance(object)) {
515: return null;
516: }
517: if (object instanceof IAdaptable) {
518: IAdaptable adaptable = (IAdaptable) object;
519: Class contributorResourceAdapterClass = LegacyResourceSupport
520: .getIContributorResourceAdapterClass();
521: if (contributorResourceAdapterClass == null) {
522: return adaptable.getAdapter(resourceMappingClass);
523: }
524: Class contributorResourceAdapter2Class = LegacyResourceSupport
525: .getIContributorResourceAdapter2Class();
526: if (contributorResourceAdapter2Class == null) {
527: return adaptable.getAdapter(resourceMappingClass);
528: }
529: Object resourceAdapter = adaptable
530: .getAdapter(contributorResourceAdapterClass);
531: Object resourceMappingAdapter;
532: if (resourceAdapter != null
533: && contributorResourceAdapter2Class
534: .isInstance(resourceAdapter)) {
535: // The registered adapter also handles resource mappings
536: resourceMappingAdapter = resourceAdapter;
537: } else {
538: // Either there is no registered adapter or it doesn't handle resource mappings.
539: // In this case, we will use the default contribution adapter
540: resourceMappingAdapter = getDefaultContributorResourceAdapter();
541: if (resourceMappingAdapter == null) {
542: return null;
543: }
544: }
545:
546: // reflective equivalent of
547: // result = ((IContributorResourceAdapter2) resourceAdapter).getAdaptedResource(adaptable);
548:
549: Method m = getContributorResourceAdapter2GetAdaptedResourceMappingMethod();
550: if (m != null) {
551:
552: try {
553: Object result = m.invoke(resourceMappingAdapter,
554: new Object[] { adaptable });
555: if (result != null) {
556: return result;
557: }
558: } catch (IllegalArgumentException e) {
559: // shouldn't happen - but play it safe
560: } catch (IllegalAccessException e) {
561: // shouldn't happen - but play it safe
562: } catch (InvocationTargetException e) {
563: // shouldn't happen - but play it safe
564: }
565:
566: }
567:
568: // If we get here, that means that the object in question doesn't adapt to resource mapping
569: // and it's contributed adapter doesn't do the adaptation either.
570: // Before we fail, we will attempt to adapt the object to IResource and then to ResourceMapping
571: Object r = getAdaptedContributorResource(object);
572: if (r != null) {
573: return Platform.getAdapterManager().getAdapter(r,
574: resourceMappingClass);
575: }
576:
577: // we've exhausted every avenue so just return null
578: return null;
579: }
580: // Fallback to querying the adapter manager directly when the object isn't an IAdaptable
581: return Platform.getAdapterManager().getAdapter(object,
582: resourceMappingClass);
583: }
584:
585: /**
586: * Adapts a selection to the given objectClass considering the Legacy resource
587: * support. Non resource objectClasses are adapted using the <code>IAdapterManager</code>
588: * and this may load the plug-in that contributes the adapter factory.
589: * <p>
590: * The returned selection will only contain elements successfully adapted.
591: * </p>
592: * @param selection the selection to adapt
593: * @param objectClass the class name to adapt the selection to
594: * @return an adapted selection
595: *
596: * @since 3.1
597: */
598: public static IStructuredSelection adaptSelection(
599: IStructuredSelection selection, String objectClass) {
600: List newSelection = new ArrayList(10);
601: for (Iterator it = selection.iterator(); it.hasNext();) {
602: Object element = it.next();
603: Object adaptedElement = getAdapter(element, objectClass);
604: if (adaptedElement != null) {
605: newSelection.add(adaptedElement);
606: }
607: }
608: return new StructuredSelection(newSelection);
609: }
610:
611: /**
612: * Adapts an object to a specified objectClass considering the Legacy resource
613: * support. Non resource objectClasses are adapted using the <code>IAdapterManager</code>
614: * and this may load the plug-in that contributes the adapter factory.
615: * <p>
616: * The returned selection will be of the same size as the original, and elements that could
617: * not be adapted are added to the returned selection as is.
618: * </p>
619: * @param element the element to adapt
620: * @param objectClass the class name to adapt the selection to
621: * @return an adapted element or <code>null</code> if the
622: * element could not be adapted.
623: *
624: * @since 3.1
625: */
626: public static Object getAdapter(Object element, String objectClass) {
627: Object adaptedElement = null;
628: if (isInstanceOf(element.getClass(), objectClass)) {
629: adaptedElement = element;
630: } else {
631: // Handle IResource
632: if (LegacyResourceSupport.isResourceType(objectClass)) {
633: adaptedElement = getAdaptedResource(element);
634: } else if (LegacyResourceSupport
635: .isResourceMappingType(objectClass)) {
636: adaptedElement = getAdaptedResourceMapping(element);
637: if (adaptedElement == null) {
638: // The object doesn't adapt directly so check if it adapts transitively
639: Object resource = getAdaptedResource(element);
640: if (resource != null) {
641: adaptedElement = ((IAdaptable) resource)
642: .getAdapter(LegacyResourceSupport
643: .getResourceMappingClass());
644: }
645: }
646: } else {
647: // Handle all other types by using the adapter factory.
648: adaptedElement = Platform.getAdapterManager()
649: .loadAdapter(element, objectClass);
650: }
651: }
652: return adaptedElement;
653: }
654:
655: /**
656: * Adapt the given element to an <code>IResource</code> using the following
657: * search order:
658: * <ol>
659: * <li> using the IContributorResourceAdapter registered for the given element, or
660: * <li> directly asking the element if it adapts.
661: * </ol>
662: *
663: * @param element the element to adapt
664: * @return an <code>IResource</code> instance if the element could be adapted or <code>null</code>
665: * otherwise.
666: * @since 3.1
667: */
668: public static Object getAdaptedResource(Object element) {
669: Class resourceClass = LegacyResourceSupport.getResourceClass();
670: Object adaptedValue = null;
671: if (resourceClass != null) {
672: if (resourceClass.isInstance(element)) {
673: adaptedValue = element;
674: } else {
675: adaptedValue = LegacyResourceSupport
676: .getAdaptedContributorResource(element);
677: }
678: }
679: return adaptedValue;
680: }
681:
682: /**
683: * Adapt the given element to an <code>ResourceMapping</code> using the following
684: * search order:
685: * <ol>
686: * <li> using the IContributorResourceAdapter2 registered for the given element, or
687: * <li> directly asking the element if it adapts.
688: * </ol>
689: *
690: * @param element the element to adapt
691: * @return an <code>ResourceMapping</code> instance if the element could be adapted or <code>null</code>
692: * otherwise.
693: * @since 3.1
694: */
695: public static Object getAdaptedResourceMapping(Object element) {
696: Class resourceMappingClass = LegacyResourceSupport
697: .getResourceMappingClass();
698: Object adaptedValue = null;
699: if (resourceMappingClass != null) {
700: if (resourceMappingClass.isInstance(element)) {
701: adaptedValue = element;
702: } else {
703: adaptedValue = LegacyResourceSupport
704: .getAdaptedContributorResourceMapping(element);
705: }
706: }
707: return adaptedValue;
708: }
709:
710: /**
711: * Prevents construction
712: */
713: private LegacyResourceSupport() {
714: // do nothing
715: }
716:
717: }
|