Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/ui/internal/ObjectContributorManager.java


1   /*******************************************************************************
2    * Copyright (c) 2000, 2003 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  package org.eclipse.ui.internal;
12  
13  import java.lang.reflect.Method;
14  import java.util.ArrayList;
15  import java.util.Arrays;
16  import java.util.Collection;
17  import java.util.Collections;
18  import java.util.HashMap;
19  import java.util.Hashtable;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Vector;
24  
25  import org.eclipse.core.runtime.IAdaptable;
26  
27  import org.eclipse.jface.viewers.IStructuredSelection;
28  
29  /**
30   * This class is a default implementation of <code>IObjectContributorManager</code>.
31   * It provides fast merging of contributions with the following semantics:
32   * <ul>
33   * <li> All of the matching contributors will be invoked per property lookup
34   * <li> The search order from a class with the definition<br>
35   *      <code>class X extends Y implements A, B</code><br>
36   *    is as follows:
37   *     <il>
38   *      <li>the target's class: X
39   *      <li>X's superclasses in order to <code>Object</code>
40   *      <li>a depth-first traversal of the target class's interaces in the order 
41   *        returned by <code>getInterfaces()</code> (in the example, A and 
42   *        its superinterfaces then B and its superinterfaces)
43   *    </il>
44   * </ul>
45   *
46   * @see IObjectContributor
47   * @see IObjectContributorManager
48   */
49  public abstract class ObjectContributorManager {
50    // Empty list that is immutable
51    private static final List EMPTY_LIST = Arrays.asList(new Object[0]);
52  
53    /** Table of contributors. */
54    protected Map contributors;
55  
56    /** Cache of object class contributor search paths; <code>null</code> if none. */
57    protected Map objectLookup;
58  
59    /** Cache of resource adapter class contributor search paths; <code>null</code> if none. */
60    protected Map adapterLookup;
61  
62    /** 
63     * Constructs a new contributor manager.
64     */
65    public ObjectContributorManager() {
66      contributors = new Hashtable(5);
67      objectLookup = null;
68      adapterLookup = null;
69    }
70    /**
71     * Adds contributors for the given types to the result list.
72     */
73    private void addContributorsFor(List types, List result) {
74      for (Iterator classes = types.iterator(); classes.hasNext();) {
75        Class clazz = (Class) classes.next();
76        List contributorList = (List) contributors.get(clazz.getName());
77        if (contributorList != null)
78          result.addAll(contributorList);
79      }
80    }
81    /**
82     * Returns the class search order starting with <code>extensibleClass</code>.
83     * The search order is defined in this class' comment.
84     */
85    protected final List computeClassOrder(Class extensibleClass) {
86      ArrayList result = new ArrayList(4);
87      Class clazz = extensibleClass;
88      while (clazz != null) {
89        result.add(clazz);
90        clazz = clazz.getSuperclass();
91      }
92      return result;
93    }
94    /**
95     * Returns the interface search order for the class hierarchy described
96     * by <code>classList</code>.
97     * The search order is defined in this class' comment.
98     */
99    protected final List computeInterfaceOrder(List classList) {
100     ArrayList result = new ArrayList(4);
101     Map seen = new HashMap(4);
102     for (Iterator list = classList.iterator(); list.hasNext();) {
103       Class[] interfaces = ((Class) list.next()).getInterfaces();
104       internalComputeInterfaceOrder(interfaces, result, seen);
105     }
106     return result;
107   }
108 
109   /**
110    * Flushes the cache of contributor search paths.  This is generally required
111    * whenever a contributor is added or removed.  
112    * <p>
113    * It is likely easier to just toss the whole cache rather than trying to be
114    * smart and remove only those entries affected.
115    */
116   public void flushLookup() {
117     objectLookup = null;
118     adapterLookup = null;
119   }
120   /**
121    * Cache the resource adapter class contributor search path.
122    */
123   private void cacheAdapterLookup(Class adapterClass, List results) {
124     if (adapterLookup == null)
125       adapterLookup = new HashMap();
126     adapterLookup.put(adapterClass, results);
127   }
128   /**
129    * Cache the object class contributor search path.
130    */
131   private void cacheObjectLookup(Class objectClass, List results) {
132     if (objectLookup == null)
133       objectLookup = new HashMap();
134     objectLookup.put(objectClass, results);
135   }
136     
137     /**
138     * Get the contributions registered to this manager.
139     * 
140     * @return an unmodifiable <code>Collection</code> containing all registered
141     * contributions.  The objects in this <code>Collection</code> will be 
142     * <code>List</code>s containing the actual contributions.
143     * @since 3.0
144     */
145     public Collection getContributors() {
146         return Collections.unmodifiableCollection(contributors.values());
147     }  
148     
149   /**
150    * Returns all the contributors registered against
151    * the given object class.
152    */
153   protected List getContributors(Class objectClass) {
154 
155     List objectList = null;
156 
157     // Lookup the results in the cache first
158     if (objectLookup != null) {
159       objectList = (List) objectLookup.get(objectClass);
160     }
161 
162     // If not in cache, build it
163     if (objectList == null) {
164       objectList = addContributorsFor(objectClass);
165       if (objectList.size() == 0)
166         objectList = EMPTY_LIST;
167 
168       // Store the contribution list into the cache.
169       cacheObjectLookup(objectClass, objectList);
170     }
171 
172     return objectList;
173   }
174 
175   /**
176    * Return the list of contributors for the supplied class.
177    */
178   protected List addContributorsFor(Class objectClass) {
179 
180     List classList = computeClassOrder(objectClass);
181     List result = new ArrayList();
182     addContributorsFor(classList, result);
183     classList = computeInterfaceOrder(classList); // interfaces
184     addContributorsFor(classList, result);
185     return result;
186   }
187 
188   /**
189    * Get the contributors for object including those it adapts
190    * to.
191    * 
192    * @return The list of contributors, empty if none.
193    */
194   protected List getContributors(Object object) {
195 
196     Class objectClass = object.getClass();
197     Object adapted = getAdaptedResource(object);
198 
199     if (adapted == null)
200       return getContributors(objectClass);
201     else
202       return getContributors(objectClass, adapted.getClass());
203   }
204 
205   /**
206    * Returns true if contributors exist in the manager for
207    * this object.
208    */
209   public boolean hasContributorsFor(Object object) {
210 
211     List contributors = getContributors(object);
212     return contributors.size() > 0;
213   }
214   /**
215    * Add interface Class objects to the result list based
216    * on the class hierarchy. Interfaces will be searched
217    * based on their position in the result list.
218    */
219   private void internalComputeInterfaceOrder(Class[] interfaces, List result, Map seen) {
220     List newInterfaces = new ArrayList(seen.size());
221     for (int i = 0; i < interfaces.length; i++) {
222       Class interfac = interfaces[i];
223       if (seen.get(interfac) == null) {
224         result.add(interfac);
225         seen.put(interfac, interfac);
226         newInterfaces.add(interfac);
227       }
228     }
229     for (Iterator newList = newInterfaces.iterator(); newList.hasNext();)
230       internalComputeInterfaceOrder(((Class) newList.next()).getInterfaces(), result, seen);
231   }
232   /**
233    *
234    */
235   public boolean isApplicableTo(IStructuredSelection selection, IObjectContributor contributor) {
236     Iterator elements = selection.iterator();
237     while (elements.hasNext()) {
238       if (contributor.isApplicableTo(elements.next()) == false)
239         return false;
240     }
241     return true;
242   }
243   /**
244    *
245    */
246   public boolean isApplicableTo(List list, IObjectContributor contributor) {
247     Iterator elements = list.iterator();
248     while (elements.hasNext()) {
249       if (contributor.isApplicableTo(elements.next()) == false)
250         return false;
251     }
252     return true;
253   }
254   /**
255    * @see IContributorManager#registerContributor
256    */
257   public void registerContributor(IObjectContributor contributor, String targetType) {
258     Vector contributorList = (Vector) contributors.get(targetType);
259     if (contributorList == null) {
260       contributorList = new Vector(5);
261       contributors.put(targetType, contributorList);
262     }
263     contributorList.addElement(contributor);
264     flushLookup();
265   }
266   /**
267    * @see IContributorManager#unregisterAllContributors
268    */
269   public void unregisterAllContributors() {
270     contributors = new Hashtable(5);
271     flushLookup();
272   }
273   /**
274    * @see IContributorManager#unregisterContributor
275    */
276   public void unregisterContributor(IObjectContributor contributor, String targetType) {
277     Vector contributorList = (Vector) contributors.get(targetType);
278     if (contributorList == null)
279       return;
280     contributorList.removeElement(contributor);
281     flushLookup();
282   }
283   /**
284    * @see IContributorManager#unregisterContributors
285    */
286   public void unregisterContributors(String targetType) {
287     contributors.remove(targetType);
288     flushLookup();
289   }
290 
291   /**
292    * Returns all the contributors registered against
293    * the given object class and the resource class that
294    * it has an Adaptable for.
295    */
296   protected List getContributors(Class objectClass, Class resourceClass) {
297 
298     List objectList = null;
299     List resourceList = null;
300 
301     // Lookup the results in the cache first
302     if (objectLookup != null) {
303       objectList = (List) objectLookup.get(objectClass);
304     }
305     if (adapterLookup != null) {
306       resourceList = (List) adapterLookup.get(resourceClass);
307     }
308 
309     if (objectList == null) {
310       objectList = addContributorsFor(objectClass);
311       if (objectList.size() == 0)
312         objectList = EMPTY_LIST;
313       cacheObjectLookup(objectClass, objectList);
314     }
315     if (resourceList == null) {
316       List contributors = addContributorsFor(resourceClass);
317       resourceList = new ArrayList(contributors.size());
318       Iterator enum = contributors.iterator();
319       while (enum.hasNext()) {
320         IObjectContributor contributor = (IObjectContributor) enum.next();
321         if (contributor.canAdapt())
322           resourceList.add(contributor);
323       }
324       if (resourceList.size() == 0)
325         resourceList = EMPTY_LIST;
326       cacheAdapterLookup(resourceClass, resourceList);
327     }
328 
329     // Collect the contribution lists into one result
330     ArrayList results = new ArrayList(objectList.size() + resourceList.size());
331     results.addAll(objectList);
332     results.addAll(resourceList);
333     return results;
334   }
335 
336   /**
337    * Get the adapted resource for the supplied object. If the
338    * object is an instance of IResource or is not an instance
339    * of IAdaptable return null. Otherwise see if it adapts
340    * to IResource via IContributorResourceAdapter.
341    * 
342    * @param object Object 
343    * @return an <code>IResource</code> or null
344    */
345   protected Object getAdaptedResource(Object object) {
346     Class resourceClass = LegacyResourceSupport.getResourceClass();
347     if (resourceClass == null) {
348       return null;
349     }
350     if (resourceClass.isInstance(object)) {
351       return null;
352     }
353 
354     if (object instanceof IAdaptable) {
355       IAdaptable adaptable = (IAdaptable) object;
356 
357       Class contributorResourceAdapterClass = LegacyResourceSupport.getIContributorResourceAdapterClass();
358       if (contributorResourceAdapterClass == null) {
359         return null;
360       }
361       Object resourceAdapter = adaptable.getAdapter(contributorResourceAdapterClass);
362       if (resourceAdapter == null) {
363         // reflective equivalent of
364         //    resourceAdapter = DefaultContributorResourceAdapter.getDefault();
365         try {
366           Class c = LegacyResourceSupport.getDefaultContributorResourceAdapterClass();
367           Method m = c.getDeclaredMethod("getDefault", new Class[0]); //$NON-NLS-1$
368           resourceAdapter = m.invoke(null, new Object[0]);
369         } catch (Exception e) {
370           // shouldn't happen - but play it safe
371           return null;
372         }
373       }
374 
375       Object result;
376       // reflective equivalent of
377       //    result = ((IContributorResourceAdapter) resourceAdapter).getAdaptedResource(adaptable);
378       try {
379         Method m = contributorResourceAdapterClass.getDeclaredMethod("getAdaptedResource", new Class[] {IAdaptable.class});  //$NON-NLS-1$
380         result = m.invoke(resourceAdapter, new Object[] {adaptable});
381       } catch (Exception e) {
382         // shouldn't happen - but play it safe
383         return null;
384       }
385       return result;
386     }
387     
388     return null;
389   }    
390 }