KickJava   Java API By Example, From Geeks To Geeks.

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


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.lang.reflect.Constructor JavaDoc;
14 import java.lang.reflect.Modifier JavaDoc;
15 import java.util.ArrayList JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.Comparator JavaDoc;
18 import java.util.Iterator JavaDoc;
19
20 import org.eclipse.core.runtime.CoreException;
21 import org.eclipse.core.runtime.IConfigurationElement;
22 import org.eclipse.core.runtime.IExecutableExtension;
23 import org.eclipse.ui.internal.components.ComponentUtil;
24 import org.eclipse.ui.internal.components.ComponentMessages;
25
26 /**
27  * Factory that uses reflection to create instances by constructor injection. The factory
28  * attempts to create the target class by invoking the greediest satisfiable constructor. That is,
29  * the constructor with the greatest number of arguments where all the arguments can be found as
30  * services.
31  *
32  * <p>
33  * This factory should only be used in situations where a component only has one constructor,
34  * or where it is completely obvious which constructor is the greediest.
35  * If a component has many different constructors or needs to take arguments to its constructor
36  * which can't simply be located by using the argument types as service keys, clients should implement
37  * a custom factory rather than trying to reuse this class.
38  * </p>
39  *
40  * <p>
41  * This class is normally referred to in a plugin.xml file as part of some extension markup.
42  * This will work for for any extension point that looks for objects of type AbstractComponentFactory.
43  * (such as the org.eclipse.core.components.services extension point or the org.eclipse.ui.views extension
44  * point).
45  * </p>
46  *
47  * <p>
48  * For example, the following XML markup would create the org.eclipse.ui.examples.components.views.context.RedirectAllView
49  * view by passing any dependencies it needs into its constructor. Notice that ReflectionFactory needs
50  * to be given the name of the class to create by separating it with a colon.
51  * </p>
52  * <code>
53  * <view
54  * class="org.eclipse.core.components.ReflectionFactory:org.eclipse.ui.examples.components.views.context.RedirectAllView"
55  * category="org.eclipse.ui.examples.components.context"
56  * name="RedirectAllView"
57  * id="org.eclipse.ui.examples.components.views.context.RedirectAllView"/>
58  *
59  * </code>
60  *
61  * <p>
62  * This factory can also be created programmatically, in which case it needs to receive the class
63  * to create (or its name) in the factory's constructor.
64  * </p>
65  *
66  * <p>
67  * Not intended to be subclassed by clients.
68  * </p>
69  *
70  * <p>EXPERIMENTAL: The components framework is currently under active development. All
71  * aspects of this class including its existence, name, and public interface are likely
72  * to change during the development of Eclipse 3.1</p>
73  *
74  * @since 3.1
75  */

76 public class ReflectionFactory extends ComponentFactory implements IExecutableExtension {
77     
78     private ClassIdentifier classId = null;
79     private Class JavaDoc targetClass = null;
80     
81     /**
82      * Should only be called when this factory is created through an extension point.
83      * If this constructor is used, the caller MUST call setInitializationData before
84      * attempting to use the factory. Call one of the other constructors if instantiating
85      * this object programmatically.
86      */

87     public ReflectionFactory() {
88     }
89     
90     /**
91      * Creates a factory that creates instances of the given class
92      *
93      * @param toCreateByReflection class to instantiate
94      */

95     public ReflectionFactory(Class JavaDoc toCreateByReflection) {
96         targetClass = toCreateByReflection;
97     }
98    
99     /**
100      * Creates a factory that creates instances of the given class
101      *
102      * @param classId name of the class to instantiate
103      */

104     public ReflectionFactory(ClassIdentifier classId) {
105         this.classId = classId;
106     }
107     
108     /* (non-Javadoc)
109      * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
110      */

111     public void setInitializationData(IConfigurationElement config,
112             String JavaDoc propertyName, Object JavaDoc data) throws CoreException {
113
114         classId = ComponentUtil.getClassFromInitializationData(config, data);
115     }
116     
117     /* (non-Javadoc)
118      * @see org.eclipse.core.components.IComponentFactory#getHandle(org.eclipse.core.components.IComponentProvider)
119      */

120     public ComponentHandle createHandle(IServiceProvider availableServices)
121             throws ComponentException {
122         
123         Class JavaDoc targetClass = this.targetClass;
124         
125         // Find the greediest satisfiable constructor
126
if (targetClass == null) {
127             targetClass = ComponentUtil.loadClass(classId);
128         }
129         
130         Constructor JavaDoc targetConstructor = null;
131         
132         Constructor JavaDoc[] constructors = targetClass.getConstructors();
133         
134         // Optimization: if there's only one constructor, use it.
135
if (constructors.length == 1) {
136             targetConstructor = constructors[0];
137         } else {
138             ArrayList JavaDoc toSort = new ArrayList JavaDoc();
139             
140             for (int i = 0; i < constructors.length; i++) {
141                 Constructor JavaDoc constructor = constructors[i];
142                 
143                 // Filter out non-public constructors
144
if ((constructor.getModifiers() & Modifier.PUBLIC) != 0) {
145                     toSort.add(constructor);
146                 }
147             }
148             
149             // Sort the constructors by descending number of constructor arguments
150
Collections.sort(toSort, new Comparator JavaDoc() {
151                 /* (non-Javadoc)
152                  * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
153                  */

154                 public int compare(Object JavaDoc arg0, Object JavaDoc arg1) {
155                     Constructor JavaDoc c1 = (Constructor JavaDoc)arg0;
156                     Constructor JavaDoc c2 = (Constructor JavaDoc)arg1;
157                     
158                     int l1 = c1.getParameterTypes().length;
159                     int l2 = c2.getParameterTypes().length;
160                     
161                     return l1 - l2;
162                 }
163             });
164             
165             // Find the first satisfiable constructor
166
for (Iterator JavaDoc iter = toSort.iterator(); iter.hasNext() && targetConstructor == null;) {
167                 Constructor JavaDoc next = (Constructor JavaDoc) iter.next();
168                 
169                 boolean satisfiable = true;
170                 
171                 Class JavaDoc[] params = next.getParameterTypes();
172                 for (int i = 0; i < params.length && satisfiable; i++) {
173                     Class JavaDoc clazz = params[i];
174                     
175                     if (!availableServices.hasService(clazz)) {
176                         satisfiable = false;
177                     }
178                 }
179                 
180                 if (satisfiable) {
181                     targetConstructor = next;
182                 }
183             }
184         }
185         
186         if (targetConstructor == null) {
187             throw new ComponentException(targetClass, ComponentMessages.ReflectionFactory_no_constructors, null);
188         }
189
190         Class JavaDoc[] paramKeys = targetConstructor.getParameterTypes();
191
192         try {
193             Object JavaDoc[] params = Components.queryInterfaces(availableServices, paramKeys);
194             
195             return new ComponentHandle(targetConstructor.newInstance(params));
196         } catch (Exception JavaDoc e) {
197             throw new ComponentException(targetClass, e);
198         }
199     }
200
201 }
202
Popular Tags