View Javadoc

1   package org.cateproject.view.tiles;
2   
3   /*
4    * Copyright 2002-2010 the original author or authors.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
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   * Helper class to configure Tiles 2.x for the Spring Framework. See
79   * <a href="http://tiles.apache.org">http://tiles.apache.org</a>
80   * for more information about Tiles, which basically is a templating
81   * mechanism for JSP-based web applications.
82   *
83   * <b>Note: Spring 3.0 requires Tiles 2.1.2 or above, with explicit support for Tiles 2.2.</b>
84   * Tiles 2.1's EL support will be activated by default when running on JSP 2.1 or above
85   * and when the Tiles EL module is present in the classpath.
86   *
87   * <p>The TilesConfigurer simply configures a TilesContainer using a set of files
88   * containing definitions, to be accessed by {@link TilesView} instances. This is a
89   * Spring-based alternative (for usage in Spring configuration) to the Tiles-provided
90   * {@link org.apache.tiles.web.startup.TilesListener} (for usage in <code>web.xml</code>).
91   *
92   * <p>TilesViews can be managed by any {@link org.springframework.web.servlet.ViewResolver}.
93   * For simple convention-based view resolution, consider using {@link TilesViewResolver}.
94   *
95   * <p>A typical TilesConfigurer bean definition looks as follows:
96   *
97   * <pre>
98   * &lt;bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
99   *   &lt;property name="definitions">
100  *     &lt;list>
101  *       &lt;value>/WEB-INF/defs/general.xml&lt;/value>
102  *       &lt;value>/WEB-INF/defs/widgets.xml&lt;/value>
103  *       &lt;value>/WEB-INF/defs/administrator.xml&lt;/value>
104  *       &lt;value>/WEB-INF/defs/customer.xml&lt;/value>
105  *       &lt;value>/WEB-INF/defs/templates.xml&lt;/value>
106  *     &lt;/list>
107  *   &lt;/property>
108  * &lt;/bean></pre>
109  *
110  * The values in the list are the actual Tiles XML files containing the definitions.
111  *
112  * @author Juergen Hoeller
113  * @since 2.5
114  * @see TilesView
115  * @see TilesViewResolver
116  */
117 public class CateTilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean {
118 
119 	private static final boolean tilesElPresent =  // requires JSP 2.1 as well as Tiles EL module
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 		// Avoid Tiles 2.1 warn logging when default RequestContextFactory impl class not found
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 		// Register further Spring-specific settings which differ from the Tiles defaults
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 	 * Configure Tiles using a custom TilesInitializer, typically specified as an inner bean.
183 	 * <p>Default is a variant of {@link org.apache.tiles.startup.DefaultTilesInitializer},
184 	 * respecting the "definitions", "preparerFactoryClass" etc properties on this configurer.
185 	 * <p><b>NOTE: Specifying a custom TilesInitializer effectively disables all other bean
186 	 * properties on this configurer.</b> The entire initialization procedure is then left
187 	 * to the TilesInitializer as specified.
188 	 */
189 	public void setTilesInitializer(TilesInitializer tilesInitializer) {
190 		this.tilesInitializer = tilesInitializer;
191 	}
192 
193 	/**
194 	 * Specify whether to apply Tiles 2.2's "complete-autoload" configuration.
195 	 * <p>See {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory}
196 	 * for details on the complete-autoload mode.
197 	 * <p><b>NOTE: Specifying the complete-autoload mode effectively disables all other bean
198 	 * properties on this configurer.</b> The entire initialization procedure is then left
199 	 * to {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer}.
200 	 * @see org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory
201 	 * @see org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer
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 	 * Set the Tiles definitions, i.e. the list of files containing the definitions.
222 	 * Default is "/WEB-INF/tiles.xml".
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 	 * Set whether to validate the Tiles XML definitions. Default is "true".
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 	 * Set the {@link org.apache.tiles.definition.DefinitionsFactory} implementation to use.
249 	 * Default is {@link org.apache.tiles.definition.UrlDefinitionsFactory},
250 	 * operating on definition resource URLs.
251 	 * <p>Specify a custom DefinitionsFactory, e.g. a UrlDefinitionsFactory subclass,
252 	 * to customize the creation of Tiles Definition objects. Note that such a
253 	 * DefinitionsFactory has to be able to handle {@link java.net.URL} source objects,
254 	 * unless you configure a different TilesContainerFactory.
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 	 * Set the {@link org.apache.tiles.preparer.PreparerFactory} implementation to use.
264 	 * Default is {@link org.apache.tiles.preparer.BasicPreparerFactory}, creating
265 	 * shared instances for specified preparer classes.
266 	 * <p>Specify {@link SimpleSpringPreparerFactory} to autowire
267 	 * {@link org.apache.tiles.preparer.ViewPreparer} instances based on specified
268 	 * preparer classes, applying Spring's container callbacks as well as applying
269 	 * configured Spring BeanPostProcessors. If Spring's context-wide annotation-config
270 	 * has been activated, annotations in ViewPreparer classes will be automatically
271 	 * detected and applied.
272 	 * <p>Specify {@link SpringBeanPreparerFactory} to operate on specified preparer
273 	 * <i>names</i> instead of classes, obtaining the corresponding Spring bean from
274 	 * the DispatcherServlet's application context. The full bean creation process
275 	 * will be in the control of the Spring application context in this case,
276 	 * allowing for the use of scoped beans etc. Note that you need to define one
277 	 * Spring bean definition per preparer name (as used in your Tiles definitions).
278 	 * @see SimpleSpringPreparerFactory
279 	 * @see SpringBeanPreparerFactory
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 	 * Set whether to use a MutableTilesContainer (typically the CachingTilesContainer
289 	 * implementation) for this application. Default is "false".
290 	 * @see org.apache.tiles.mgmt.MutableTilesContainer
291 	 * @see org.apache.tiles.mgmt.CachingTilesContainer
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 	 * Set Tiles properties (equivalent to the ServletContext init-params in
301 	 * the Tiles documentation), overriding the default settings.
302 	 * <p><b>NOTE: This property is only effective with Tiles 2.1.</b>
303 	 * Tiles 2.2 doesn't support property-based configuration anymore.
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 	 * Creates and exposes a TilesContainer for this web application,
316 	 * delegating to the TilesInitializer.
317 	 * @throws TilesException in case of setup failure
318 	 * @see #createTilesInitializer()
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 			// We need to do this after initialization simply because we're reusing the
340 			// original CompleteAutoloadTilesInitializer above. We cannot subclass
341 			// CompleteAutoloadTilesInitializer when compiling against Tiles 2.1...
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 			// Again, we need to do this after initialization since SpringTilesContainerFactory
356 			// cannot override template methods that refer to Tiles 2.2 classes: in this case,
357 			// AttributeEvaluatorFactory as createAttributeEvaluatorFactory return type.
358 			BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(this.servletContext);
359 			new TilesElActivator().registerEvaluator(container);
360 		}
361 	}
362 
363 	/**
364 	 * Creates a new instance of {@link org.apache.tiles.startup.BasicTilesInitializer}.
365 	 * <p>Override it to use a different initializer.
366 	 * @see org.apache.tiles.web.startup.TilesListener#createTilesInitializer()
367 	 */
368 	protected TilesInitializer createTilesInitializer() {
369 		return (tiles22Present ? new SpringTilesInitializer() : new BasicTilesInitializer());
370 	}
371 
372 	/**
373 	 * Removes the TilesContainer from this web application.
374 	 * @throws TilesException in case of cleanup failure
375 	 */
376 	public void destroy() throws TilesException {
377 		try {
378 			// Tiles 2.2?
379 			ReflectionUtils.invokeMethod(TilesInitializer.class.getMethod("destroy"), this.tilesInitializer);
380 		}
381 		catch (NoSuchMethodException ex) {
382 			// Tiles 2.1...
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 			// Avoid Tiles 2.2 warn logging when default RequestContextFactory impl class not found
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