1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.bean;
20
21 import java.io.InputStream;
22 import java.io.IOException;
23 import java.net.URL;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Properties;
32 import java.util.concurrent.ConcurrentHashMap;
33
34 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
35 import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
36
37
38 /**
39 * Base interface for FacesBean storage.
40 *
41 */
42 public class FacesBeanFactory
43 {
44 /**
45 * Create a FacesBean for a component class.
46 */
47
48 static public FacesBean createFacesBean(
49 Class<?> ownerClass,
50 String rendererType)
51 {
52 if (ownerClass == null)
53 return null;
54
55 String className = ownerClass.getName();
56 FacesBean bean = createFacesBean(className, rendererType);
57
58 if (bean == null && rendererType != null)
59 {
60 bean = createFacesBean(className, null);
61 _cacheFacesBeanClass(bean, className, rendererType);
62 }
63
64 if (bean == null)
65 {
66 bean = createFacesBean(ownerClass.getSuperclass(), rendererType);
67 _cacheFacesBeanClass(bean, className, rendererType);
68 }
69
70 return bean;
71 }
72
73 static public FacesBean createFacesBean(
74 String beanType,
75 String rendererType)
76 {
77 String typeKey = _buildTypeKey(beanType, rendererType);
78
79 Class<?> type = _TYPES_CLASS.get(typeKey);
80
81 if(type == null)
82 {
83 String className = (String) _TYPES_MAP.get(typeKey);
84 if (className == null)
85 return null;
86
87
88
89
90
91 try
92 {
93 type = _getClassLoader().loadClass(className);
94 _TYPES_CLASS.put(typeKey, type);
95 }
96 catch (ClassNotFoundException cnfe)
97 {
98 _LOG.severe("CANNOT_FIND_FACESBEAN", className);
99 _LOG.severe(cnfe);
100 }
101 }
102
103 try
104 {
105 return (FacesBean) type.newInstance();
106 }
107 catch (IllegalAccessException iae)
108 {
109 _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
110 _LOG.severe(iae);
111 }
112 catch (InstantiationException ie)
113 {
114 _LOG.severe("CANNOT_CREATE_FACESBEAN_INSTANCE", type.getName());
115 _LOG.severe(ie);
116 }
117
118 return null;
119 }
120
121 static private void _initializeBeanTypes()
122 {
123 _TYPES_MAP = new HashMap<Object, Object>();
124
125 List<URL> list = new ArrayList<URL>();
126 try
127 {
128 Enumeration<URL> en = _getClassLoader().getResources(
129 "META-INF/faces-bean.properties");
130 while (en.hasMoreElements())
131 {
132 list.add(en.nextElement());
133 }
134
135 Collections.reverse(list);
136 }
137 catch (IOException ioe)
138 {
139 _LOG.severe(ioe);
140 return;
141 }
142
143 if (list.isEmpty())
144 {
145 if (_LOG.isInfo())
146 _LOG.info("NO_FACES_BEAN_PROPERTIES_FILES_LOCATED");
147 }
148
149 for(URL url : list)
150 {
151 _initializeBeanTypes(url);
152 }
153 }
154
155 static private void _initializeBeanTypes(URL url)
156 {
157 try
158 {
159 Properties properties = new Properties();
160 InputStream is = url.openStream();
161 try
162 {
163 properties.load(is);
164 if (_LOG.isFine())
165 _LOG.fine("Loading bean factory info from " + url);
166
167 _TYPES_MAP.putAll(properties);
168 }
169 finally
170 {
171 is.close();
172 }
173 }
174 catch (IOException ioe)
175 {
176 _LOG.severe("CANNOT_LOAD_URL", url);
177 _LOG.severe(ioe);
178 }
179 }
180
181
182 static private ClassLoader _getClassLoader()
183 {
184 ClassLoader loader = Thread.currentThread().getContextClassLoader();
185 if (loader == null)
186 loader = FacesBeanFactory.class.getClassLoader();
187 return loader;
188 }
189
190
191
192
193 static private String _buildTypeKey(
194 String beanType,
195 String rendererType)
196 {
197 if (rendererType != null)
198 {
199 StringBuilder typeKeyBuilder = _getSharedStringBuilder();
200
201 typeKeyBuilder.append(beanType).append('|').append(rendererType);
202
203 return typeKeyBuilder.toString();
204 }
205 else
206 return beanType;
207
208 }
209
210 static private void _cacheFacesBeanClass(
211 FacesBean bean,
212 String beanType,
213 String rendererType)
214 {
215
216 if(bean != null)
217 {
218 String typeKey = _buildTypeKey(beanType, rendererType);
219 _TYPES_CLASS.put(typeKey, bean.getClass());
220 }
221 }
222
223 /**
224 * <p>
225 * This gets a single threadlocal shared stringbuilder instance, each time you call
226 * _getSharedStringBuilder it sets the length of the stringBuilder instance to 0.
227 * </p><p>
228 * This allows you to use the same StringBuilder instance over and over.
229 * You must call toString on the instance before calling _getSharedStringBuilder again.
230 * </p>
231 * Example that works
232 * <pre><code>
233 * StringBuilder sb1 = _getSharedStringBuilder();
234 * sb1.append(a).append(b);
235 * String c = sb1.toString();
236 *
237 * StringBuilder sb2 = _getSharedStringBuilder();
238 * sb2.append(b).append(a);
239 * String d = sb2.toString();
240 * </code></pre>
241 * <br><br>
242 * Example that doesn't work, you must call toString on sb1 before
243 * calling __getSharedStringBuilder again.
244 * <pre><code>
245 * StringBuilder sb1 = _getSharedStringBuilder();
246 * StringBuilder sb2 = _getSharedStringBuilder();
247 *
248 * sb1.append(a).append(b);
249 * String c = sb1.toString();
250 *
251 * sb2.append(b).append(a);
252 * String d = sb2.toString();
253 * </code></pre>
254 *
255 */
256 static private StringBuilder _getSharedStringBuilder()
257 {
258 StringBuilder sb = _STRING_BUILDER.get();
259
260 if (sb == null)
261 {
262 sb = new StringBuilder();
263 _STRING_BUILDER.set(sb);
264 }
265
266
267 sb.setLength(0);
268
269 return sb;
270 }
271
272 static private final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(FacesBeanFactory.class);
273 static private Map<Object, Object> _TYPES_MAP;
274 static private Map<String, Class<?>> _TYPES_CLASS = new ConcurrentHashMap<String, Class<?>>();
275 static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
276 ThreadLocalUtils.newRequestThreadLocal();
277
278 static
279 {
280 _initializeBeanTypes();
281 }
282 }