KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > components > framework > FactoryMap


1 /*******************************************************************************
2  * Copyright (c) 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.components.framework;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collection JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20
21 import org.eclipse.ui.internal.components.Assert;
22 import org.eclipse.ui.internal.components.DependencyOnlyFactory;
23 import org.eclipse.ui.internal.components.util.InstanceToComponentFactoryAdapter;
24 import org.eclipse.ui.internal.components.util.InstanceToServiceFactoryAdapter;
25 import org.eclipse.ui.internal.components.util.ServiceProviderToServiceFactoryAdapter;
26
27 /**
28  * Default implementation of <code>ServiceFactory</code> that is useful for expressing
29  * hardcoded dependency rules. A <code>FactoryMap</code> contains a map of
30  * component factories and an ordered list of other service factories to delegate to. It
31  * resolves dependencies like this:
32  *
33  * <ol>
34  * <li>Check if the type is being explicitly excluded.</li>
35  * <li>Check if it there is a specific mapping for the dependency.</li>
36  * <li>Run through the list of other service factories to delegate to. The first factory
37  * that can handle the dependency will be used. When delegating, all possible types
38  * are delegated to the target object.</li>
39  * <li>Return null</li>
40  * </ol>
41  *
42  * <p>Note that this is only a convenience class. Any methods that take a service factory as input
43  * argument should generally take an <code>AbstractServiceFactory</code> rather than depending
44  * on this concrete class.</p>
45  *
46  * <p>Class keys must match exactly. When a service is looked up by class, the factory will
47  * <em>not</em> look for mappings to other compatible types if an exact match is not found.</p>
48  *
49  * <p>As a convenience, all of the setters on this object return <i>this</i>,
50  * allowing them to be chained Smalltalk-style. For example: </p>
51  *
52  * <code>
53  * // Chained initialization
54  * Container myContainer = new Container(new FactoryMap()
55  * .mapInstance(Dog.class, myDog)
56  * .mapInstance(Cat.class, myCat));
57  *
58  * // Equivalent non-chained initialization
59  * FactoryMap context = new FactoryMap();
60  * context.mapInstance(Dog.class, myDog);
61  * context.mapInstance(Cat.class, myCat);
62  * Container myContainer = new Container(context);
63  * </code>
64  *
65  * <p>Not intended to be subclassed by clients.</p>
66  *
67  * <p>EXPERIMENTAL: The components framework is currently under active development. All
68  * aspects of this class including its existence, name, and public interface are likely
69  * to change during the development of Eclipse 3.1</p>
70  *
71  * @since 3.1
72  */

73 public final class FactoryMap extends ServiceFactory {
74     
75     /**
76      * Mixed-type Map of Object keys onto IComponentInfo (null if empty)
77      */

78     private Map JavaDoc adapters = null;
79     
80     private List JavaDoc exclusions = null;
81     
82     /**
83      * List of IContainerContext, or null if empty.
84      */

85     private List JavaDoc parentContexts = null;
86     
87     /**
88      * List of ContainerInfo, or null if empty
89      */

90     private List JavaDoc registeredContainers = null;
91      
92     /**
93      * Create an empty ContainerContext that does not recognize any types.
94      */

95     public FactoryMap() {
96     }
97     
98     /**
99      * Blocks the given type from being returned by this context. Subsequent calls to
100      * getComponentInfo will return null when asked for this interface, even if there is
101      * an instance or parent context that can provide the component. This is not the same
102      * as unmapping the type, which simply undoes the effects of a previous mapping and
103      * may still fall through to an object registered through add*. This overrides any
104      * previous mapping for this interface, and does not affect its subtypes or supertypes.
105      *
106      * @param interface_ interface to exclude
107      * @return this
108      */

109     public FactoryMap mapExclusion(Object JavaDoc interface_) {
110         Assert.isNotNull(interface_);
111         if (exclusions == null) {
112             exclusions = new ArrayList JavaDoc();
113         }
114         exclusions.add(interface_);
115         internalAddMapping(interface_, null);
116         return this;
117     }
118     
119     /**
120      * Maps the given interface to the given factory. The factory must be able
121      * to create objects that are assignable to the interface. This will override the
122      * effects of any previous mapping for this interface, but does not affect its
123      * subtypes or supertypes.
124      *
125      * @param interface_ interface to implement
126      * @param adapter a factory that can create objects of the given type
127      * @return this
128      */

129     public FactoryMap map(Object JavaDoc interface_, ComponentFactory adapter) {
130         Assert.isNotNull(adapter);
131         Assert.isNotNull(interface_);
132         
133         internalAddMapping(interface_, adapter);
134         return this;
135     }
136     
137     /**
138      * Maps the given interface to the given context. Whenever this context is asked
139      * for a dependency of the given type, it will delegate to the given context.
140      * This will override the effects of any previous mapping for this interface,
141      * but does not affect its subtypes or supertypes.
142      *
143      * @param interfaceType interface to map
144      * @param context context to delegate to
145      * @return this
146      */

147     public FactoryMap map(Object JavaDoc interfaceType, ServiceFactory context) {
148         Assert.isNotNull(interfaceType);
149         Assert.isNotNull(context);
150         
151         internalAddMapping(interfaceType, context);
152         
153         // Inherit all of the dependencies from the given factory.
154
add(new DependencyOnlyFactory(context));
155         return this;
156     }
157         
158     /**
159      * Maps the given interface type to the given object instance. Whenever the context
160      * is asked for a dependency of the given type, it will return the given object.
161      * This will override the effects of any previous mapping for this interface
162      * but does not affect its subtypes or supertypes.
163      *
164      * @param interfaceType interface type to map
165      * @param component component instance that either implements the interface or supplies
166      * an adapter to the interface
167      * @return this
168      */

169     public FactoryMap mapInstance(Object JavaDoc interfaceType, Object JavaDoc component) {
170         Assert.isNotNull(interfaceType);
171         Assert.isNotNull(component);
172         
173         if (interfaceType instanceof Class JavaDoc) {
174             Class JavaDoc c = (Class JavaDoc)interfaceType;
175             
176             Assert.isTrue(c.isInstance(component));
177         }
178         
179         return map(interfaceType, new InstanceToComponentFactoryAdapter(component));
180     }
181     
182     public FactoryMap addInstance(Object JavaDoc instance) {
183         return add(new InstanceToServiceFactoryAdapter(instance));
184     }
185     
186     /**
187      * Causes the receiver to delegate to the given context whenever it can't find a dependency.
188      *
189      * <p>Dependencies registered through add* are processed after specific mappings registered
190      * through map*. If two add* calls can satisfy the same dependency, the one that was added
191      * first takes precidence.</p>
192      *
193      * @param context newly added context
194      * @return this
195      */

196     public FactoryMap add(ServiceFactory context) {
197         Assert.isNotNull(context);
198         internalAddInstance(context);
199         
200         return this;
201     }
202     
203     public FactoryMap add(IServiceProvider toAdd) {
204         Assert.isNotNull(toAdd);
205         internalAddInstance(new ServiceProviderToServiceFactoryAdapter(toAdd));
206         
207         return this;
208     }
209     
210     /* (non-Javadoc)
211      * @see org.eclipse.core.component.IComponentArguments#getComponentInstance(java.lang.Class)
212      */

213     ComponentHandle getInstance(Object JavaDoc type, IServiceProvider availableDependencies) throws ComponentException {
214         if (parentContexts == null) {
215             return null;
216         }
217         
218         for (Iterator JavaDoc iter = parentContexts.iterator(); iter.hasNext();) {
219             ServiceFactory context = (ServiceFactory) iter.next();
220             
221             ComponentHandle result = context.createHandle(type, availableDependencies);
222             if (result != null) {
223                 return result;
224             }
225         }
226         return null;
227     }
228
229     /* (non-Javadoc)
230      * @see org.eclipse.core.component.IComponentContext#get(java.lang.Class)
231      */

232     public ComponentHandle createHandle(Object JavaDoc key, IServiceProvider availableDependencies) throws ComponentException {
233         if (adapters != null) {
234             if (adapters.containsKey(key)) {
235                 Object JavaDoc target = adapters.get(key);
236                 if (target == null) {
237                     return null;
238                 }
239                 
240                 if (target instanceof ComponentFactory) {
241                     ComponentFactory factory = (ComponentFactory)target;
242                     return factory.createHandle(availableDependencies);
243                 } else if (target instanceof ServiceFactory) {
244                     ServiceFactory targetContext = (ServiceFactory)target;
245                     
246                     ComponentHandle handle = targetContext.createHandle(key, availableDependencies);
247                     if (handle != null) {
248                         return handle;
249                     }
250                 }
251             }
252         }
253         
254         // Look for inherited implementations
255
return getInstance(key, availableDependencies);
256     }
257
258     private void internalAddInstance(ServiceFactory component) {
259         if (parentContexts == null) {
260             parentContexts = new ArrayList JavaDoc();
261         }
262         
263         if (!parentContexts.contains(component)) {
264             parentContexts.add(component);
265         }
266     }
267     
268     private void internalRemoveInstance(ServiceFactory component) {
269         if (parentContexts == null) {
270             return;
271         }
272         
273         parentContexts.remove(component);
274         if (parentContexts.isEmpty()) {
275             parentContexts = null;
276         }
277     }
278
279     private void internalAddMapping(Object JavaDoc interface_, Object JavaDoc toMap) {
280         if (adapters == null) {
281             adapters = new HashMap JavaDoc();
282         }
283         
284         adapters.put(interface_, toMap);
285     }
286     
287     /* (non-Javadoc)
288      * @see org.eclipse.core.components.IComponentContext#hasKey(java.lang.Object)
289      */

290     private boolean hasKey(Object JavaDoc componentKey, ServiceFactory toSkip) {
291         if (adapters != null) {
292             if (adapters.containsKey(componentKey)) {
293                 return (adapters.get(componentKey) != null);
294             }
295         }
296
297         if (parentContexts != null) {
298             for (Iterator JavaDoc iter = parentContexts.iterator(); iter.hasNext();) {
299                 ServiceFactory context = (ServiceFactory) iter.next();
300                 
301                 if (context == toSkip) {
302                     continue;
303                 }
304                 
305                 if (context.hasService(componentKey)) {
306                     return true;
307                 }
308             }
309         }
310         
311         return false;
312     }
313     
314     /* (non-Javadoc)
315      * @see org.eclipse.core.components.IComponentContext#getMissingDependencies()
316      */

317     public Collection JavaDoc getMissingDependencies() {
318         
319         HashSet JavaDoc result = new HashSet JavaDoc();
320         
321         if (parentContexts != null) {
322             for (Iterator JavaDoc iter = parentContexts.iterator(); iter.hasNext();) {
323                 ServiceFactory next = (ServiceFactory) iter.next();
324                 
325                 Collection JavaDoc inheritedDeps = next.getMissingDependencies();
326                 
327                 for (Iterator JavaDoc iterator = inheritedDeps.iterator(); iterator
328                         .hasNext();) {
329                     Object JavaDoc dep = (Object JavaDoc) iterator.next();
330                     
331                     if (!hasKey(dep, next)) {
332                         result.add(dep);
333                     }
334                 }
335             }
336         }
337         
338         if (exclusions != null) {
339             result.addAll(exclusions);
340         }
341         
342         return result;
343     }
344
345     /* (non-Javadoc)
346      * @see org.eclipse.core.components.IComponentContext#hasKey(java.lang.Object)
347      */

348     public boolean hasService(Object JavaDoc componentKey) {
349         return hasKey(componentKey, null);
350     }
351 }
352
Popular Tags