1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package javax.faces;
20
21
22 import javax.faces.application.ApplicationFactory;
23 import javax.faces.context.FacesContextFactory;
24 import javax.faces.lifecycle.LifecycleFactory;
25 import javax.faces.render.RenderKitFactory;
26 import java.lang.reflect.Constructor;
27 import java.lang.reflect.InvocationTargetException;
28 import java.util.*;
29
30
31
32
33
34
35
36 public final class FactoryFinder
37 {
38 public static final String APPLICATION_FACTORY = "javax.faces.application.ApplicationFactory";
39 public static final String FACES_CONTEXT_FACTORY = "javax.faces.context.FacesContextFactory";
40 public static final String LIFECYCLE_FACTORY = "javax.faces.lifecycle.LifecycleFactory";
41 public static final String RENDER_KIT_FACTORY = "javax.faces.render.RenderKitFactory";
42
43
44
45
46
47 private static Map<ClassLoader, Map> _registeredFactoryNames = new HashMap<ClassLoader, Map>();
48
49
50
51
52
53
54
55
56 private static Map<ClassLoader, Map> _factories = new HashMap<ClassLoader, Map>();
57
58 private static final Set<String> VALID_FACTORY_NAMES = new HashSet<String>();
59 private static final Map<String, Class> ABSTRACT_FACTORY_CLASSES = new HashMap<String, Class>();
60 static {
61 VALID_FACTORY_NAMES.add(APPLICATION_FACTORY);
62 VALID_FACTORY_NAMES.add(FACES_CONTEXT_FACTORY);
63 VALID_FACTORY_NAMES.add(LIFECYCLE_FACTORY);
64 VALID_FACTORY_NAMES.add(RENDER_KIT_FACTORY);
65
66 ABSTRACT_FACTORY_CLASSES.put(APPLICATION_FACTORY, ApplicationFactory.class);
67 ABSTRACT_FACTORY_CLASSES.put(FACES_CONTEXT_FACTORY, FacesContextFactory.class);
68 ABSTRACT_FACTORY_CLASSES.put(LIFECYCLE_FACTORY, LifecycleFactory.class);
69 ABSTRACT_FACTORY_CLASSES.put(RENDER_KIT_FACTORY, RenderKitFactory.class);
70 }
71
72
73
74 FactoryFinder() {
75 }
76
77 public static Object getFactory(String factoryName)
78 throws FacesException
79 {
80 if(factoryName == null)
81 throw new NullPointerException("factoryName may not be null");
82
83 ClassLoader classLoader = getClassLoader();
84
85
86
87
88 Map factoryClassNames = null;
89 Map<String, Object> factoryMap = null;
90
91 synchronized(_registeredFactoryNames)
92 {
93 factoryClassNames = _registeredFactoryNames.get(classLoader);
94
95 if (factoryClassNames == null)
96 {
97 String message = "No Factories configured for this Application. This happens if the faces-initialization "+
98 "does not work at all - make sure that you properly include all configuration settings necessary for a basic faces application " +
99 "and that all the necessary libs are included. Also check the logging output of your web application and your container for any exceptions!" +
100 "\nIf you did that and find nothing, the mistake might be due to the fact that you use some special web-containers which "+
101 "do not support registering context-listeners via TLD files and " +
102 "a context listener is not setup in your web.xml.\n" +
103 "A typical config looks like this;\n<listener>\n" +
104 " <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>\n" +
105 "</listener>\n";
106 throw new IllegalStateException(message);
107 }
108
109 if (! factoryClassNames.containsKey(factoryName))
110 {
111 throw new IllegalArgumentException("no factory " + factoryName + " configured for this application.");
112 }
113
114 factoryMap = _factories.get(classLoader);
115
116 if (factoryMap == null)
117 {
118 factoryMap = new HashMap<String, Object>();
119 _factories.put(classLoader, factoryMap);
120 }
121 }
122
123 List classNames = null;
124 Object factory = null;
125 synchronized (factoryClassNames)
126 {
127 factory = factoryMap.get(factoryName);
128 if (factory != null)
129 {
130 return factory;
131 }
132 classNames = (List) factoryClassNames.get(factoryName);
133 }
134
135
136 factory = newFactoryInstance(ABSTRACT_FACTORY_CLASSES.get(factoryName), classNames.iterator(), classLoader);
137
138 synchronized (factoryClassNames)
139 {
140
141 if (factoryMap.get(factoryName) == null)
142 {
143 factoryMap.put(factoryName, factory);
144 }
145 }
146 return factory;
147 }
148
149
150 private static Object newFactoryInstance(Class interfaceClass, Iterator classNamesIterator, ClassLoader classLoader)
151 {
152 try
153 {
154 Object current = null;
155
156 while (classNamesIterator.hasNext())
157 {
158 String implClassName = (String) classNamesIterator.next();
159 Class implClass = classLoader.loadClass(implClassName);
160
161
162 if (!interfaceClass.isAssignableFrom(implClass))
163 {
164 throw new IllegalArgumentException("Class " + implClassName + " is no " + interfaceClass.getName());
165 }
166
167 if (current == null)
168 {
169
170 current = implClass.newInstance();
171 } else
172 {
173
174 try
175 {
176 Constructor delegationConstructor = implClass.getConstructor(new Class[]{interfaceClass});
177
178 try
179 {
180
181 current = delegationConstructor.newInstance(new Object[]{current});
182 } catch (InstantiationException e)
183 {
184 throw new FacesException(e);
185 } catch (IllegalAccessException e)
186 {
187 throw new FacesException(e);
188 } catch (InvocationTargetException e)
189 {
190 throw new FacesException(e);
191 }
192 } catch (NoSuchMethodException e)
193 {
194
195 current = implClass.newInstance();
196 }
197 }
198 }
199
200 return current;
201 } catch (ClassNotFoundException e)
202 {
203 throw new FacesException(e);
204 } catch (InstantiationException e)
205 {
206 throw new FacesException(e);
207 } catch (IllegalAccessException e)
208 {
209 throw new FacesException(e);
210 }
211 }
212
213
214 public static void setFactory(String factoryName,
215 String implName)
216 {
217 checkFactoryName(factoryName);
218
219 ClassLoader classLoader = getClassLoader();
220 Map<String, List> factoryClassNames = null;
221 synchronized(_registeredFactoryNames)
222 {
223 Map factories = _factories.get(classLoader);
224
225 if (factories != null && factories.containsKey(factoryName)) {
226
227
228 return;
229 }
230
231 factoryClassNames = _registeredFactoryNames.get(classLoader);
232
233 if (factoryClassNames == null)
234 {
235 factoryClassNames = new HashMap<String, List>();
236 _registeredFactoryNames.put(classLoader, factoryClassNames);
237 }
238 }
239 synchronized (factoryClassNames)
240 {
241 List<String> classNameList = factoryClassNames.get(factoryName);
242
243 if (classNameList == null)
244 {
245 classNameList = new ArrayList<String>();
246 factoryClassNames.put(factoryName, classNameList);
247 }
248 classNameList.add(implName);
249 }
250 }
251
252
253 public static void releaseFactories()
254 throws FacesException
255 {
256 ClassLoader classLoader = getClassLoader();
257
258
259 synchronized(_registeredFactoryNames)
260 {
261 _factories.remove(classLoader);
262
263
264
265 Map factoryClassNames = (Map) _registeredFactoryNames.get(classLoader);
266 if (factoryClassNames != null) factoryClassNames.clear();
267 _registeredFactoryNames.remove(classLoader);
268 }
269 }
270
271 private static void checkFactoryName(String factoryName)
272 {
273 if (! VALID_FACTORY_NAMES.contains(factoryName))
274 {
275 throw new IllegalArgumentException("factoryName '" + factoryName + "'");
276 }
277 }
278
279
280 private static ClassLoader getClassLoader()
281 {
282 try
283 {
284 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
285 if (classLoader == null)
286 {
287 throw new FacesException("web application class loader cannot be identified", null);
288 }
289 return classLoader;
290 }
291 catch (Exception e)
292 {
293 throw new FacesException("web application class loader cannot be identified", e);
294 }
295 }
296 }