1 package org.cateproject.view.tiles;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.io.IOException;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Method;
22 import java.net.URL;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29 import javax.servlet.ServletContext;
30 import javax.servlet.jsp.JspFactory;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.tiles.TilesApplicationContext;
35 import org.apache.tiles.TilesContainer;
36 import org.apache.tiles.TilesException;
37 import org.apache.tiles.context.AbstractTilesApplicationContextFactory;
38 import org.apache.tiles.context.ChainedTilesRequestContextFactory;
39 import org.apache.tiles.context.TilesRequestContextFactory;
40 import org.apache.tiles.definition.DefinitionsFactory;
41 import org.apache.tiles.definition.DefinitionsFactoryException;
42 import org.apache.tiles.definition.DefinitionsReader;
43 import org.apache.tiles.definition.digester.DigesterDefinitionsReader;
44 import org.apache.tiles.evaluator.AttributeEvaluator;
45 import org.apache.tiles.evaluator.AttributeEvaluatorFactory;
46 import org.apache.tiles.evaluator.el.ELAttributeEvaluator;
47 import org.apache.tiles.evaluator.impl.DirectAttributeEvaluator;
48 import org.apache.tiles.factory.AbstractTilesContainerFactory;
49 import org.apache.tiles.factory.BasicTilesContainerFactory;
50 import org.apache.tiles.factory.TilesContainerFactory;
51 import org.apache.tiles.impl.BasicTilesContainer;
52 import org.apache.tiles.impl.mgmt.CachingTilesContainer;
53 import org.apache.tiles.jsp.context.JspTilesRequestContextFactory;
54 import org.apache.tiles.locale.LocaleResolver;
55 import org.apache.tiles.preparer.BasicPreparerFactory;
56 import org.apache.tiles.preparer.PreparerFactory;
57 import org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer;
58 import org.apache.tiles.renderer.impl.BasicRendererFactory;
59 import org.apache.tiles.servlet.context.ServletTilesRequestContextFactory;
60 import org.apache.tiles.servlet.context.ServletUtil;
61 import org.apache.tiles.startup.BasicTilesInitializer;
62 import org.apache.tiles.startup.TilesInitializer;
63 import org.apache.tiles.velocity.context.VelocityTilesRequestContextFactory;
64
65 import org.springframework.beans.BeanUtils;
66 import org.springframework.beans.factory.DisposableBean;
67 import org.springframework.beans.factory.InitializingBean;
68 import org.springframework.util.ClassUtils;
69 import org.springframework.util.CollectionUtils;
70 import org.springframework.util.ReflectionUtils;
71 import org.springframework.util.StringUtils;
72 import org.springframework.web.context.ServletContextAware;
73 import org.springframework.web.servlet.view.tiles2.SpringLocaleResolver;
74 import org.springframework.web.servlet.view.tiles2.SpringTilesApplicationContextFactory;
75 import org.springframework.web.servlet.view.tiles2.TilesConfigurer;
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public class CateTilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean {
118
119 private static final boolean tilesElPresent =
120 ClassUtils.isPresent(
121 "javax.servlet.jsp.JspApplicationContext", TilesConfigurer.class.getClassLoader()) &&
122 ClassUtils.isPresent(
123 "org.apache.tiles.evaluator.el.ELAttributeEvaluator", TilesConfigurer.class.getClassLoader());
124
125 private static final boolean tiles22Present = ClassUtils.isPresent(
126 "org.apache.tiles.evaluator.AttributeEvaluatorFactory", TilesConfigurer.class.getClassLoader());
127
128
129 protected final Log logger = LogFactory.getLog(getClass());
130
131 private Map<String,AbstractBaseAttributeRenderer> attributeRenderers = new HashMap<String,AbstractBaseAttributeRenderer>();
132
133 public void setAttributeRenderers(Map<String,AbstractBaseAttributeRenderer> attributeRenderers) {
134 this.attributeRenderers = attributeRenderers;
135 }
136
137 private TilesInitializer tilesInitializer;
138
139 private boolean overrideLocaleResolver = false;
140
141 private String[] definitions;
142
143 private boolean validateDefinitions = true;
144
145 private Class<? extends DefinitionsFactory> definitionsFactoryClass;
146
147 private Class<? extends PreparerFactory> preparerFactoryClass;
148
149 private boolean useMutableTilesContainer = false;
150
151 private final Map<String, String> tilesPropertyMap = new HashMap<String, String>();
152
153 private ServletContext servletContext;
154
155
156 public CateTilesConfigurer() {
157
158 StringBuilder sb = new StringBuilder("org.apache.tiles.servlet.context.ServletTilesRequestContextFactory");
159 addClassNameIfPresent(sb, "org.apache.tiles.portlet.context.PortletTilesRequestContextFactory");
160 addClassNameIfPresent(sb, "org.apache.tiles.jsp.context.JspTilesRequestContextFactory");
161 this.tilesPropertyMap.put(ChainedTilesRequestContextFactory.FACTORY_CLASS_NAMES, sb.toString());
162
163
164 this.tilesPropertyMap.put(AbstractTilesApplicationContextFactory.APPLICATION_CONTEXT_FACTORY_INIT_PARAM,
165 SpringTilesApplicationContextFactory.class.getName());
166 this.tilesPropertyMap.put(DefinitionsFactory.LOCALE_RESOLVER_IMPL_PROPERTY,
167 SpringLocaleResolver.class.getName());
168 this.tilesPropertyMap.put(TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM,
169 BasicPreparerFactory.class.getName());
170 this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM,
171 Boolean.toString(false));
172 }
173
174 private static void addClassNameIfPresent(StringBuilder sb, String className) {
175 if (ClassUtils.isPresent(className, TilesConfigurer.class.getClassLoader())) {
176 sb.append(',').append(className);
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189 public void setTilesInitializer(TilesInitializer tilesInitializer) {
190 this.tilesInitializer = tilesInitializer;
191 }
192
193
194
195
196
197
198
199
200
201
202
203 public void setCompleteAutoload(boolean completeAutoload) {
204 if (completeAutoload) {
205 try {
206 Class clazz = getClass().getClassLoader().loadClass(
207 "org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer");
208 this.tilesInitializer = (TilesInitializer) clazz.newInstance();
209 }
210 catch (Exception ex) {
211 throw new IllegalStateException("Tiles-Extras 2.2 not available", ex);
212 }
213 }
214 else {
215 this.tilesInitializer = null;
216 }
217 this.overrideLocaleResolver = completeAutoload;
218 }
219
220
221
222
223
224 public void setDefinitions(String[] definitions) {
225 this.definitions = definitions;
226 if (definitions != null) {
227 String defs = StringUtils.arrayToCommaDelimitedString(definitions);
228 if (logger.isInfoEnabled()) {
229 logger.info("TilesConfigurer: adding definitions [" + defs + "]");
230 }
231 this.tilesPropertyMap.put(DefinitionsFactory.DEFINITIONS_CONFIG, defs);
232 }
233 else {
234 this.tilesPropertyMap.remove(DefinitionsFactory.DEFINITIONS_CONFIG);
235 }
236 }
237
238
239
240
241 public void setValidateDefinitions(boolean validateDefinitions) {
242 this.validateDefinitions = validateDefinitions;
243 this.tilesPropertyMap.put(DigesterDefinitionsReader.PARSER_VALIDATE_PARAMETER_NAME,
244 Boolean.toString(validateDefinitions));
245 }
246
247
248
249
250
251
252
253
254
255
256 public void setDefinitionsFactoryClass(Class<? extends DefinitionsFactory> definitionsFactoryClass) {
257 this.definitionsFactoryClass = definitionsFactoryClass;
258 this.tilesPropertyMap.put(TilesContainerFactory.DEFINITIONS_FACTORY_INIT_PARAM,
259 definitionsFactoryClass.getName());
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281 public void setPreparerFactoryClass(Class<? extends PreparerFactory> preparerFactoryClass) {
282 this.preparerFactoryClass = preparerFactoryClass;
283 this.tilesPropertyMap.put(TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM,
284 preparerFactoryClass.getName());
285 }
286
287
288
289
290
291
292
293 public void setUseMutableTilesContainer(boolean useMutableTilesContainer) {
294 this.useMutableTilesContainer = useMutableTilesContainer;
295 this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM,
296 Boolean.toString(useMutableTilesContainer));
297 }
298
299
300
301
302
303
304
305 public void setTilesProperties(Properties tilesProperties) {
306 CollectionUtils.mergePropertiesIntoMap(tilesProperties, this.tilesPropertyMap);
307 }
308
309 public void setServletContext(ServletContext servletContext) {
310 this.servletContext = servletContext;
311 }
312
313
314
315
316
317
318
319
320 public void afterPropertiesSet() throws TilesException {
321 boolean activateEl = false;
322 if (tilesElPresent) {
323 activateEl = new JspExpressionChecker().isExpressionFactoryAvailable();
324 if (!this.tilesPropertyMap.containsKey(TilesContainerFactory.ATTRIBUTE_EVALUATOR_INIT_PARAM)) {
325 this.tilesPropertyMap.put(TilesContainerFactory.ATTRIBUTE_EVALUATOR_INIT_PARAM, activateEl ?
326 "org.apache.tiles.evaluator.el.ELAttributeEvaluator" : DirectAttributeEvaluator.class.getName());
327 }
328 }
329
330 SpringTilesApplicationContextFactory factory = new SpringTilesApplicationContextFactory();
331 factory.init(this.tilesPropertyMap);
332 TilesApplicationContext preliminaryContext = factory.createApplicationContext(this.servletContext);
333 if (this.tilesInitializer == null) {
334 this.tilesInitializer = createTilesInitializer();
335 }
336 this.tilesInitializer.initialize(preliminaryContext);
337
338 if (this.overrideLocaleResolver) {
339
340
341
342 logger.debug("Registering Tiles 2.2 LocaleResolver for complete-autoload setup");
343 try {
344 BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(this.servletContext);
345 DefinitionsFactory definitionsFactory = container.getDefinitionsFactory();
346 Method setter = definitionsFactory.getClass().getMethod("setLocaleResolver", LocaleResolver.class);
347 setter.invoke(definitionsFactory, new SpringLocaleResolver());
348 }
349 catch (Exception ex) {
350 throw new IllegalStateException("Cannot override LocaleResolver with SpringLocaleResolver", ex);
351 }
352 }
353
354 if (activateEl && this.tilesInitializer instanceof SpringTilesInitializer) {
355
356
357
358 BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(this.servletContext);
359 new TilesElActivator().registerEvaluator(container);
360 }
361 }
362
363
364
365
366
367
368 protected TilesInitializer createTilesInitializer() {
369 return (tiles22Present ? new SpringTilesInitializer() : new BasicTilesInitializer());
370 }
371
372
373
374
375
376 public void destroy() throws TilesException {
377 try {
378
379 ReflectionUtils.invokeMethod(TilesInitializer.class.getMethod("destroy"), this.tilesInitializer);
380 }
381 catch (NoSuchMethodException ex) {
382
383 ServletUtil.setContainer(this.servletContext, null);
384 }
385 }
386
387
388 private class SpringTilesInitializer extends BasicTilesInitializer {
389
390 @Override
391 protected AbstractTilesContainerFactory createContainerFactory(TilesApplicationContext context) {
392 return new SpringTilesContainerFactory();
393 }
394 }
395
396
397 private class SpringTilesContainerFactory extends BasicTilesContainerFactory {
398
399 @Override
400 protected BasicTilesContainer instantiateContainer(TilesApplicationContext context) {
401 return (useMutableTilesContainer ? new CachingTilesContainer() : new BasicTilesContainer());
402 }
403
404 @Override
405 protected void registerRequestContextFactory(String className,
406 List<TilesRequestContextFactory> factories, TilesRequestContextFactory parent) {
407
408 if (ClassUtils.isPresent(className, TilesConfigurer.class.getClassLoader())) {
409 super.registerRequestContextFactory(className, factories, parent);
410 }
411 }
412
413 @Override
414 protected List<URL> getSourceURLs(TilesApplicationContext applicationContext,
415 TilesRequestContextFactory contextFactory) {
416 if (definitions != null) {
417 try {
418 List<URL> result = new LinkedList<URL>();
419 for (String definition : definitions) {
420 result.addAll(applicationContext.getResources(definition));
421 }
422 return result;
423 }
424 catch (IOException ex) {
425 throw new DefinitionsFactoryException("Cannot load definition URLs", ex);
426 }
427 }
428 else {
429 return super.getSourceURLs(applicationContext, contextFactory);
430 }
431 }
432
433 @Override
434 protected DefinitionsReader createDefinitionsReader(TilesApplicationContext applicationContext,
435 TilesRequestContextFactory contextFactory) {
436 DigesterDefinitionsReader reader = new DigesterDefinitionsReader();
437 if (!validateDefinitions){
438 Map<String,String> map = new HashMap<String,String>();
439 map.put(DigesterDefinitionsReader.PARSER_VALIDATE_PARAMETER_NAME, Boolean.FALSE.toString());
440 reader.init(map);
441 }
442 return reader;
443 }
444
445 @Override
446 protected LocaleResolver createLocaleResolver(TilesApplicationContext applicationContext,
447 TilesRequestContextFactory contextFactory) {
448 return new SpringLocaleResolver();
449 }
450
451 @Override
452 protected DefinitionsFactory createDefinitionsFactory(TilesApplicationContext applicationContext,
453 TilesRequestContextFactory contextFactory, LocaleResolver resolver) {
454 if (definitionsFactoryClass != null) {
455 return BeanUtils.instantiate(definitionsFactoryClass);
456 }
457 else {
458 return super.createDefinitionsFactory(applicationContext, contextFactory, resolver);
459 }
460 }
461
462 @Override
463 protected PreparerFactory createPreparerFactory(TilesApplicationContext applicationContext,
464 TilesRequestContextFactory contextFactory) {
465 if (preparerFactoryClass != null) {
466 return BeanUtils.instantiate(preparerFactoryClass);
467 }
468 else {
469 return super.createPreparerFactory(applicationContext, contextFactory);
470 }
471 }
472
473 @Override
474 protected void registerAttributeRenderers(BasicRendererFactory rendererFactory, TilesApplicationContext applicationContext, TilesRequestContextFactory contextFactory, TilesContainer container, AttributeEvaluatorFactory attributeEvaluatorFactory) {
475 super.registerAttributeRenderers(rendererFactory, applicationContext, contextFactory, container, attributeEvaluatorFactory);
476
477 for(String key : attributeRenderers.keySet()) {
478 AbstractBaseAttributeRenderer attributeRenderer = attributeRenderers.get(key);
479 attributeRenderer.setApplicationContext(applicationContext);
480 attributeRenderer.setAttributeEvaluatorFactory(attributeEvaluatorFactory);
481 attributeRenderer.setRequestContextFactory(contextFactory);
482 rendererFactory.registerRenderer(key, attributeRenderer);
483 }
484 }
485
486 @Override
487 protected void registerChainedRequestContextFactories(ChainedTilesRequestContextFactory contextFactory) {
488 List<TilesRequestContextFactory> factories = new ArrayList<TilesRequestContextFactory>(3);
489 registerRequestContextFactory(ServletTilesRequestContextFactory.class.getName(),factories, contextFactory);
490 registerRequestContextFactory(JspTilesRequestContextFactory.class.getName(),factories, contextFactory);
491 registerRequestContextFactory(VelocityTilesRequestContextFactory.class.getName(), factories, contextFactory);
492
493 contextFactory.setFactories(factories);
494 }
495 }
496
497
498 private class JspExpressionChecker {
499
500 public boolean isExpressionFactoryAvailable() {
501 try {
502 JspFactory factory = JspFactory.getDefaultFactory();
503 if (factory != null &&
504 factory.getJspApplicationContext(servletContext).getExpressionFactory() != null) {
505 logger.info("Found JSP 2.1 ExpressionFactory");
506 return true;
507 }
508 }
509 catch (Throwable ex) {
510 logger.warn("Could not obtain JSP 2.1 ExpressionFactory", ex);
511 }
512 return false;
513 }
514 }
515
516
517 private class TilesElActivator {
518
519 public void registerEvaluator(BasicTilesContainer container) {
520 logger.debug("Registering Tiles 2.2 AttributeEvaluatorFactory for JSP 2.1");
521 try {
522 ClassLoader cl = TilesElActivator.class.getClassLoader();
523 Class aef = cl.loadClass("org.apache.tiles.evaluator.AttributeEvaluatorFactory");
524 Class baef = cl.loadClass("org.apache.tiles.evaluator.BasicAttributeEvaluatorFactory");
525 Constructor baefCtor = baef.getConstructor(AttributeEvaluator.class);
526 ELAttributeEvaluator evaluator = new ELAttributeEvaluator();
527 evaluator.setApplicationContext(container.getApplicationContext());
528 evaluator.init(new HashMap<String, String>());
529 Object baefValue = baefCtor.newInstance(evaluator);
530 Method setter = container.getClass().getMethod("setAttributeEvaluatorFactory", aef);
531 setter.invoke(container, baefValue);
532 }
533 catch (Exception ex) {
534 throw new IllegalStateException("Cannot activate ELAttributeEvaluator", ex);
535 }
536 }
537 }
538
539 }
540