KickJava   Java API By Example, From Geeks To Geeks.

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


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.Collections JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.LinkedList JavaDoc;
18
19 import org.eclipse.osgi.util.NLS;
20 import org.eclipse.ui.internal.WorkbenchPlugin;
21 import org.eclipse.ui.internal.components.Assert;
22 import org.eclipse.ui.internal.components.ComponentMessages;
23
24 /**
25  * A dependency injection container for one or more components. Containers are an implementation of
26  * <code>IServiceProvider</code> which first look for an existing instance of a service before attempting
27  * to create one using a service factory.
28  *
29  * The owner of a container must dispose it when it is no longer needed.
30  *
31  * <p>
32  * Example usage:
33  * </p>
34  * <code>
35  * class Cat {
36  * String catName;
37  *
38  * Cat(String name) {
39  * catName = name;
40  * };
41  * }
42  *
43  * class Dog {
44  * Cat theCat;
45  *
46  * Dog(Cat toChase) {
47  * theCat = toChase;
48  * }
49  *
50  * public chaseCat() {
51  * System.out.println("Chasing " + theCat.getName());
52  * }
53  * }
54  *
55  * ...
56  *
57  * public static void main(String[] args) {
58  * // Create a context that knows how to create Dogs. Any time it needs a Cat,
59  * // it will refer to poor Fluffy.
60  * FactoryMap context = new FactoryMap()
61  * .add(Dog.class, new ReflectionFactory(Dog.class))
62  * .addInstance(Cat.class, new Cat("Fluffy"));
63  *
64  * // Create a container for a particular Dog
65  * Container container = new Container(context);
66  *
67  * try {
68  * // Create a Dog
69  * Dog myDog = (Dog)container.getService(Dog.class);
70  *
71  * // Chase Fluffy around
72  * myDog.chaseCat();
73  *
74  * } catch (ComponentException e) {
75  * // We weren't able to create the Dog
76  * System.out.println(e.toString());
77  * } finally {
78  * // Clean up the container when no longer needed
79  * container.dispose();
80  * }
81  * }
82  * </code>
83  *
84  * <p>
85  * Not intended to be subclassed by clients.
86  * </p>
87  *
88  * <p>EXPERIMENTAL: The components framework is currently under active development. All
89  * aspects of this class including its existence, name, and public interface are likely
90  * to change during the development of Eclipse 3.1</p>
91  *
92  * @since 3.1
93  */

94 public final class Container implements IDisposable, IServiceProvider {
95     
96     
97     private static class SingleFactoryContext extends ServiceFactory {
98         private ComponentFactory factory;
99         
100         public SingleFactoryContext(ComponentFactory factory) {
101             this.factory = factory;
102         }
103         
104         public ComponentHandle createHandle(Object JavaDoc componentKey, IServiceProvider container) throws ComponentException {
105             return factory.createHandle(container);
106         }
107         
108         public Collection JavaDoc getMissingDependencies() {
109             return Collections.EMPTY_SET;
110         }
111         
112         public boolean hasService(Object JavaDoc componentKey) {
113             return true;
114         }
115         
116     }
117     
118     private static final class ComponentInfo {
119         IDisposable disposable;
120         Object JavaDoc component;
121         Object JavaDoc key;
122         
123         /**
124          * Creates a ComponentInfo given an interface type and an optional existing instance and factory.
125          *
126          * @param key existing component instance. May be null if no instance is available. Must be
127          * assignable to interfaceType unless null.
128          * @param component factory for the given type. May be null if no factory is available. Must create
129          * instances that are assignable to interfaceType unless null.
130          * @param disposable component type
131          */

132         public ComponentInfo(Object JavaDoc key, Object JavaDoc component, IDisposable disposable) {
133             this.key = key;
134             this.component = component;
135             this.disposable = disposable;
136         }
137         
138         public Object JavaDoc getKey() {
139             return key;
140         }
141         
142         public Object JavaDoc getInstance() {
143             return component;
144         }
145         
146         public void dispose() {
147             if (disposable != null) {
148                 disposable.dispose();
149             }
150         }
151         
152     }
153     
154     // Array of ComponentInfo
155
private ArrayList JavaDoc services = new ArrayList JavaDoc();
156     private LinkedList JavaDoc inProgress = null;
157     
158     private ServiceFactory defaultContext;
159     
160     /**
161      * Set this flag once we've verified that our context isn't missing any
162      * dependencies.
163      */

164     private boolean verified = false;
165         
166     /**
167      * Creates a new Container that will create services using the given factory.
168      *
169      * @param context factory that will supply the instances to this container
170      */

171     public Container(ServiceFactory context) {
172         Assert.isNotNull(context);
173         Collection JavaDoc deps = context.getMissingDependencies();
174         if (deps.size() != 0) {
175             Assert.isTrue(false, ComponentMessages.Container_missing_dependency + deps.toArray()[0].toString());
176         }
177         
178         this.defaultContext = context;
179     }
180     
181     /* (non-Javadoc)
182      * @see org.eclipse.ui.component.IComponent#dispose()
183      */

184     public void dispose() {
185         if (isDisposed()) {
186             return;
187         }
188         deallocateComponents(0);
189                 
190         services = null;
191     }
192
193     /**
194      * Deallocates all components beyond the given index
195      *
196      * @since 3.1
197      *
198      * @param index
199      */

200     private void deallocateComponents(int index) {
201         ComponentInfo[] servicesArray = (ComponentInfo[]) services.toArray(new ComponentInfo[services.size()]);
202         for (int i = servicesArray.length - 1; i >= index; i--) {
203             ComponentInfo info = servicesArray[i];
204             
205             try {
206                 info.dispose();
207             } catch (Exception JavaDoc e) {
208                 WorkbenchPlugin.log(e);
209             }
210         }
211         
212         services = new ArrayList JavaDoc();
213         for (int i = 0; i < index; i++) {
214             ComponentInfo info = servicesArray[i];
215             
216             services.add(info);
217         }
218     }
219     
220     private final Object JavaDoc getComponent(Object JavaDoc key, ServiceFactory context, IServiceProvider dependencies) throws ComponentException {
221         
222         Object JavaDoc existingInstance = getExistingComponent(key, context);
223         
224         if (existingInstance != null) {
225             return existingInstance;
226         }
227         
228         // See if our context knows about this type
229

230         // If we're in the process of creating another component in this container,
231
// check for cycles
232
if (inProgress != null) {
233             for (Iterator JavaDoc iter = inProgress.iterator(); iter.hasNext();) {
234                 //ComponentKey next = (ComponentKey) iter.next();
235
Object JavaDoc next = iter.next();
236                 
237                 if (next.equals(key)) {
238                     throw new ComponentException(key, NLS.bind(
239                             ComponentMessages.Container_cycle_detected,
240                           key.toString()), null);
241                 }
242             }
243         } else {
244             inProgress = new LinkedList JavaDoc();
245         }
246         
247         inProgress.add(key);
248         
249         int start = services.size();
250         
251         boolean success = false;
252         
253         try {
254             ComponentHandle handle = context.createHandle(key, dependencies);
255             if (handle != null) {
256                 if (handle.requiresDisposal()) {
257                     services.add(new ComponentInfo(key, handle.getInstance(), handle.getDisposable()));
258                 }
259                 Object JavaDoc result = handle.getInstance();
260                 success = true;
261                 return result;
262             }
263         } finally {
264             if (!success) {
265                 // If something went wrong, deallocate everything that was allocated for
266
// the faulty component.
267
deallocateComponents(start);
268             }
269             inProgress.removeLast();
270             if (inProgress.isEmpty()) {
271                 inProgress = null;
272             }
273         }
274         
275         return null;
276     }
277         
278     private final Object JavaDoc getExistingComponent(Object JavaDoc key, ServiceFactory context) {
279         // Look for an existing component of this type
280
for (Iterator JavaDoc iter = services.iterator(); iter.hasNext();) {
281             ComponentInfo info = (ComponentInfo) iter.next();
282                             
283             if (info.getKey().equals(key)) {
284                 return info.getInstance();
285             }
286         }
287         
288         return null;
289     }
290     
291     /**
292      * Returns true iff this container has been disposed.
293      *
294      * @return true iff this container has been disposed.
295      */

296     public boolean isDisposed() {
297         return services == null;
298     }
299
300     /* (non-Javadoc)
301      * @see org.eclipse.core.components.IServiceProvider#getService(java.lang.Object)
302      */

303     public Object JavaDoc getService(Object JavaDoc key) throws ComponentException {
304         try {
305             return getComponent(key, defaultContext, this);
306         } catch (ComponentException e) {
307             throw new ComponentException(key, e);
308         }
309     }
310
311     private Object JavaDoc getComponentFromFactory(ComponentFactory factory) throws ComponentException {
312         return getComponent(factory, new SingleFactoryContext(factory), this);
313     }
314     
315     /* (non-Javadoc)
316      * @see org.eclipse.core.components.IServiceProvider#hasKey(java.lang.Object)
317      */

318     public boolean hasService(Object JavaDoc key) {
319         return defaultContext.hasService(key);
320     }
321     
322 }
323
Popular Tags