ClassTransformerFactory.java

biz/hammurapi/util/ClassTransformerFactory.java

Violations

Inspector Message Severity Location
Java Inspector 006 Missing default case for switch statement 1 304:73
Java Inspector 048 Copyrights information should be present in each file. 1
Java Inspector 086 Use equals() instead of == or != to compare objects. 1 287:67
Java Inspector 015 Do not change parameter value. For comprehensibility, formal parameters should be final 2 260:33
Java Inspector 035 Code length is more than 200 2 198:9
Java Inspector 045 Too many exceptions (more than 3) listed in throws clause 2 198:9
Java Inspector 049 Use a Collection instead of arrays Object[] 2 214:17
Java Inspector 049 Use a Collection instead of arrays Object[] 2 282:41
Java Inspector 049 Use a Collection instead of arrays Object[] 2 283:41
Java Inspector 089 Undocumented method 2 72:17
Java Inspector 089 Undocumented method 2 87:17
Java Inspector 089 Constructor is not properly documented 2 96:17
Java Inspector 089 Parameter className is not documented 2 96:17
Java Inspector 089 Parameter profile is not documented 2 96:17
Java Inspector 089 Parameter locale is not documented 2 96:17
Java Inspector 089 Undocumented method 2 159:73
Java Inspector 089 Parameter object is not documented 2 198:9
Java Inspector 089 Undocumented parameter rootName 2 198:9
Java Inspector 089 Parameter profile is not documented 2 198:9
Java Inspector 089 Parameter locale is not documented 2 198:9
Java Inspector 089 Undocumented parameter expandContext 2 198:9
Java Inspector 089 Parameter parameters is not documented 2 198:9
Java Inspector 089 Parameter out is not documented 2 198:9
Java Inspector 089 Undocumented method 2 225:33
Java Inspector 089 Undocumented method 2 229:33
Java Inspector 089 Undocumented method 2 233:49
Java Inspector 089 Undocumented method 2 237:49
Java Inspector 089 Undocumented method 2 241:49
Java Inspector 089 Undocumented method 2 279:25
Java Inspector 089 Undocumented method 2 286:49
Java Inspector 089 Undocumented method 2 346:81
Java Inspector 089 Undocumented method 2 371:81
Java Inspector 089 Undocumented constructor 2 404:9
Java Inspector 024 Avoid hardwired character literals 3 299:120
Java Inspector 024 Avoid hardwired character literals 3 299:124
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 298:81
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 314:86
Java Inspector 025 Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] 3 317:86
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 143:96
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 174:96
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 216:65
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 260:41
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 281:66
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 309:98
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 311:106
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 315:98
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 321:82
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 337:80
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 362:116
Java Inspector 026 Avoid hardwired string literals. Allowed literals: [] 3 364:88
Java Inspector 051 It is good practice to call in any case super() in a constructor. 3 404:9

Source code

1/*
2 * hgcommons 9
3 * Hammurapi Group Common Library
4 * Copyright (C) 2003 Hammurapi Group
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
21 * e-Mail: support@hammurapi.biz
22 */
23package biz.hammurapi.util;
24
25import java.io.IOException;
26import java.io.InputStream;
27import java.io.InputStreamReader;
28import java.util.AbstractCollection;
29import java.util.Collection;
30import java.util.HashMap;
31import java.util.Iterator;
32import java.util.Locale;
33import java.util.Map;
34import java.util.Properties;
35
36import javax.xml.parsers.DocumentBuilderFactory;
37import javax.xml.parsers.FactoryConfigurationError;
38import javax.xml.parsers.ParserConfigurationException;
39import javax.xml.transform.Result;
40import javax.xml.transform.Source;
41import javax.xml.transform.Templates;
42import javax.xml.transform.Transformer;
43import javax.xml.transform.TransformerConfigurationException;
44import javax.xml.transform.TransformerException;
45import javax.xml.transform.TransformerFactory;
46import javax.xml.transform.TransformerFactoryConfigurationError;
47import javax.xml.transform.URIResolver;
48import javax.xml.transform.dom.DOMSource;
49import javax.xml.transform.stream.StreamSource;
50
51import org.w3c.dom.Document;
52import org.w3c.dom.Element;
53
54import biz.hammurapi.config.Context;
55import biz.hammurapi.convert.ConvertingService;
56import biz.hammurapi.eval.ExpandingFilterWriter;
57import biz.hammurapi.xml.dom.DomSerializable;
58
59
60/**
61 * Finds class stylesheet and transforms given
62 * object using the stylesheet.
63 * @author Pavel Vlasov
64 * @revision $Revision$
65 */
66public class ClassTransformerFactory {
67 private static class Key {
68 String className;
69 String profile;
70 Locale locale;
71
72 public boolean equals(Object otherTemplateKey) {
73 if (this==otherTemplateKey) {
74 return true;
75 }
76
77 if (otherTemplateKey instanceof Key) {
78 Key otk=(Key) otherTemplateKey;
79 return className.equals(otk.className)
80 && (profile==null ? otk.profile==null : profile.equals(otk.profile))
81 && (locale==null ? otk.locale==null : locale.equals(otk.locale));
82 }
83
84 return false;
85 }
86
87 public int hashCode() {
88 return className.hashCode() ^ (profile==null ? 0 : profile.hashCode()) ^ (locale==null ? 0 : locale.hashCode());
89 }
90
91 /**
92 * @param className
93 * @param profile
94 * @param locale
95 */
96 public Key(String className, String profile, Locale locale) {
97 super();
98 this.className = className;
99 this.profile = profile;
100 this.locale = locale;
101 }
102 }
103
104 private Map templates=new HashMap();
105 private Map contexts=new HashMap();
106 private TransformerFactory factory = TransformerFactory.newInstance();
107
108 private boolean cacheExpandedTemplates;
109 private ClassTemplateResolver templateResolver;
110
111 private Templates findTemplate(Class clazz, String profile, Locale locale, Context context) throws TransformerFactoryConfigurationError, TransformerConfigurationException, IOException {
112 if (context==null || cacheExpandedTemplates) {
113 synchronized (templates) {
114 Key key=new Key(clazz.getName(), profile, locale);
115 Templates ret=(Templates) templates.get(key);
116 if (ret==null && !templates.containsKey(key)) {
117 ret = loadTemplate(clazz, profile, locale, context);
118 templates.put(key, ret);
119 }
120
121 return ret;
122 }
123 }
124 return loadTemplate(clazz, profile, locale, context);
125 }
126
127 /**
128 * @param clazz
129 * @param profile
130 * @param locale
131 * @param context
132 * @return
133 * @throws TransformerConfigurationException
134 * @throws IOException
135 */
136 private Templates loadTemplate(Class clazz, String profile, Locale locale, final Context context) throws TransformerConfigurationException, IOException {
137 InputStream is=null;
138 if (templateResolver!=null) {
139 is=templateResolver.resolve(clazz, profile, locale);
140 }
141
142 if (is==null) {
143 is=new ClassResourceLoader(clazz).getResourceAsStream(profile, locale, "xsl");
144 }
145
146 if (is==null) {
147 return null;
148 }
149 final Context classContext=findContext(clazz, profile, locale);
150 if (classContext==null && context==null) {
151 return factory.newTemplates(new StreamSource(is));
152 }
153 return factory.newTemplates(
154 new StreamSource(
155 ExpandingFilterWriter.expand(
156 new InputStreamReader(is),
157 new Context() {
158
159 public Object get(String name) {
160 Object ret = context==null ? null : context.get(name);
161 if (ret==null && classContext!=null) {
162 ret=classContext.get(name);
163 }
164 return ret;
165 }
166 })));
167 }
168
169 private Context findContext(Class clazz, String profile, Locale locale) {
170 synchronized (contexts) {
171 Key key=new Key(clazz.getName(), profile, locale);
172 Context ret=(Context) contexts.get(key);
173 if (ret==null && !contexts.containsKey(key)) {
174 ret=new ClassResourceLoader(clazz).getContext(profile, locale, "ctx");
175 contexts.put(key, ret);
176 }
177
178 return ret;
179 }
180 }
181
182 /**
183 * Transforms object using object's class stylesheet. Collections are treated differently - for them
184 * a stylesheet of the first element with profile 'list' is used if profile is null. If there are no
185 * elements in the collection or if a stylesheet is not found then ClassTransformerFactory!list stylesheet is used.
186 * @param object
187 * @param profile
188 * @param locale
189 * @param parameters
190 * @param out
191 * @throws TransformerException
192 * @throws FactoryConfigurationError
193 * @throws ParserConfigurationException
194 * @throws TransformerFactoryConfigurationError
195 * @throws IOException
196 * @throws TransformerConfigurationException
197 */
198 public void transform(
199 final Object object,
200 String rootName,
201 String profile,
202 Locale locale,
203 final Context expandContext,
204 Properties parameters,
205 Result out)
206 throws
207 TransformerException,
208 ParserConfigurationException,
209 FactoryConfigurationError,
210 TransformerConfigurationException,
211 TransformerFactoryConfigurationError,
212 IOException {
213
214 final Class[] clazz={null};
215 Document doc=DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
216 Element root=doc.createElement(rootName==null ? "root" : rootName);
217 doc.appendChild(root);
218
219 final Locale actualLocale = locale==null ? Locale.getDefault() : locale;
220
221 if (object instanceof Collection) {
222
223 AbstractCollection src = new AbstractCollection() {
224
225 public int size() {
226 return ((Collection) object).size();
227 }
228
229 public Iterator iterator() {
230 return new Iterator() {
231 Iterator master=((Collection) object).iterator();
232
233 public void remove() {
234 master.remove();
235 }
236
237 public boolean hasNext() {
238 return master.hasNext();
239 }
240
241 public Object next() {
242 Object ret=master.next();
243 if (clazz[0]==null && ret!=null) {
244 clazz[0]=ret.getClass();
245 }
246 return ret;
247 }
248 };
249 }
250
251 };
252 DomSerializable ds = (DomSerializable) ConvertingService.convert(src, DomSerializable.class);
253 ds.toDom(root);
254
255 if (clazz[0]==null) {
256 clazz[0]=ClassTransformerFactory.class;
257 }
258
259 if (profile==null) {
260 profile="list";
261 }
262 } else {
263 clazz[0]=object.getClass();
264 DomSerializable ds = (DomSerializable) ConvertingService.convert(object, DomSerializable.class);
265 ds.toDom(root);
266 }
267
268 Templates template=findTemplate(clazz[0], profile, actualLocale, expandContext);
269 if (template==null && object instanceof Collection) {
270 template=findTemplate(ClassTransformerFactory.class, profile, actualLocale, expandContext);
271 }
272
273 Transformer transformer = template==null ? factory.newTransformer() : template.newTransformer();
274
275 final URIResolver originalUriResolver = factory.getURIResolver();
276 final String finalProfile=profile;
277 transformer.setURIResolver(new URIResolver() {
278
279 public Source resolve(String uri, String base) throws TransformerException {
280 String resourceUriPrefix = biz.hammurapi.config.DomConfigFactory.RESOURCE_PREFIX;
281 if (uri.equals(resourceUriPrefix+"super")) {
282 final InputStream[] superResource={null};
283 final Class[] superClass={null};
284 new ClassHierarchyVisitable(clazz[0]).accept(new Visitor() {
285
286 public boolean visit(Object target) {
287 if (target!=clazz[0]) {
288 superClass[0]=(Class) target;
289
290 if (templateResolver!=null) {
291 superResource[0]=templateResolver.resolve(superClass[0], finalProfile, actualLocale);
292 }
293
294 if (superResource!=null) {
295 return false;
296 }
297
298 for (int i=0; i<4; i++) {
299 String variant=superClass[0].getName().replace('.','/');
300 if (finalProfile!=null) {
301 variant+=finalProfile;
302 }
303
304 switch (i) {
305 case 0:
306 variant+=actualLocale;
307 break;
308 case 1:
309 variant+="_"+actualLocale.getLanguage();
310 if (actualLocale.getCountry().length()!=0) {
311 variant+="_"+actualLocale.getCountry();
312 }
313 break;
314 case 2:
315 variant+="_"+actualLocale.getLanguage();
316 break;
317 case 3:
318 break;
319 }
320
321 variant+=".xsl";
322
323
324 superResource[0]=clazz[0].getClassLoader().getResourceAsStream(variant);
325 if (superResource[0]!=null) {
326 return false;
327 }
328 }
329 }
330
331 return true;
332 }
333
334 });
335
336 if (superResource[0]==null) {
337 throw new TransformerException("Cannot resolve: "+uri);
338 }
339
340 try {
341 return new StreamSource(
342 ExpandingFilterWriter.expand(
343 new InputStreamReader(superResource[0]),
344 new Context() {
345
346 public Object get(String name) {
347 Object ret = expandContext==null ? null : expandContext.get(name);
348 final Context classContext=findContext(superClass[0], finalProfile, actualLocale);
349 if (ret==null && classContext!=null) {
350 ret=classContext.get(name);
351 }
352 return ret;
353 }
354 }));
355 } catch (IOException e) {
356 throw new TransformerException(e);
357 }
358 } else if (uri.startsWith(resourceUriPrefix)) {
359 try {
360 final Class resourceClass = clazz[0].getClassLoader().loadClass(uri.substring(resourceUriPrefix.length()));
361 ClassResourceLoader crl=new ClassResourceLoader(resourceClass);
362 InputStream is=crl.getResourceAsStream(finalProfile, actualLocale, "xsl");
363 if (is==null) {
364 throw new TransformerException("Cannot resolve: "+uri);
365 }
366 return new StreamSource(
367 ExpandingFilterWriter.expand(
368 new InputStreamReader(is),
369 new Context() {
370
371 public Object get(String name) {
372 Object ret = expandContext==null ? null : expandContext.get(name);
373 final Context classContext=findContext(resourceClass, finalProfile, actualLocale);
374 if (ret==null && classContext!=null) {
375 ret=classContext.get(name);
376 }
377 return ret;
378 }
379 }));
380
381 } catch (ClassNotFoundException e) {
382 throw new TransformerException(e);
383 } catch (IOException e) {
384 throw new TransformerException(e);
385 }
386 }
387
388 return originalUriResolver.resolve(uri, base);
389 }
390
391 });
392
393 if (parameters!=null) {
394 Iterator it=parameters.entrySet().iterator();
395 while (it.hasNext()) {
396 Map.Entry entry=(Map.Entry) it.next();
397 transformer.setParameter((String) entry.getKey(), entry.getValue());
398 }
399 }
400
401 transformer.transform(new DOMSource(doc), out);
402 }
403
404 public ClassTransformerFactory(ClassTemplateResolver templateResolver, boolean cacheExpandedTemplates) {
405 this.templateResolver=templateResolver;
406 this.cacheExpandedTemplates=cacheExpandedTemplates;
407 }
408}
409