1 /* 2 * $Id: CompleteAutoloadTilesContainerFactory.java 821300 2009-10-03 12:16:36Z apetrelli $ 3 * 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 package org.apache.tiles.extras.complete; 23 24 import java.io.IOException; 25 import java.net.URL; 26 import java.util.List; 27 import java.util.Map; 28 import java.util.Set; 29 30 import javax.el.ArrayELResolver; 31 import javax.el.BeanELResolver; 32 import javax.el.CompositeELResolver; 33 import javax.el.ELResolver; 34 import javax.el.ListELResolver; 35 import javax.el.MapELResolver; 36 import javax.el.ResourceBundleELResolver; 37 38 import ognl.OgnlException; 39 import ognl.OgnlRuntime; 40 import ognl.PropertyAccessor; 41 42 import org.apache.tiles.TilesApplicationContext; 43 import org.apache.tiles.TilesContainer; 44 import org.apache.tiles.compat.definition.digester.CompatibilityDigesterDefinitionsReader; 45 import org.apache.tiles.context.ChainedTilesRequestContextFactory; 46 import org.apache.tiles.context.TilesRequestContext; 47 import org.apache.tiles.context.TilesRequestContextFactory; 48 import org.apache.tiles.context.TilesRequestContextHolder; 49 import org.apache.tiles.definition.DefinitionsFactoryException; 50 import org.apache.tiles.definition.DefinitionsReader; 51 import org.apache.tiles.definition.pattern.DefinitionPatternMatcherFactory; 52 import org.apache.tiles.definition.pattern.PatternDefinitionResolver; 53 import org.apache.tiles.definition.pattern.PrefixedPatternDefinitionResolver; 54 import org.apache.tiles.definition.pattern.regexp.RegexpDefinitionPatternMatcherFactory; 55 import org.apache.tiles.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory; 56 import org.apache.tiles.el.ELAttributeEvaluator; 57 import org.apache.tiles.el.JspExpressionFactoryFactory; 58 import org.apache.tiles.el.TilesContextBeanELResolver; 59 import org.apache.tiles.el.TilesContextELResolver; 60 import org.apache.tiles.evaluator.AttributeEvaluatorFactory; 61 import org.apache.tiles.evaluator.BasicAttributeEvaluatorFactory; 62 import org.apache.tiles.factory.BasicTilesContainerFactory; 63 import org.apache.tiles.factory.TilesContainerFactoryException; 64 import org.apache.tiles.freemarker.context.FreeMarkerTilesRequestContextFactory; 65 import org.apache.tiles.freemarker.renderer.FreeMarkerAttributeRenderer; 66 import org.apache.tiles.impl.BasicTilesContainer; 67 import org.apache.tiles.impl.mgmt.CachingTilesContainer; 68 import org.apache.tiles.locale.LocaleResolver; 69 import org.apache.tiles.mvel.MVELAttributeEvaluator; 70 import org.apache.tiles.mvel.TilesContextBeanVariableResolverFactory; 71 import org.apache.tiles.mvel.TilesContextVariableResolverFactory; 72 import org.apache.tiles.ognl.ApplicationScopeNestedObjectExtractor; 73 import org.apache.tiles.ognl.DelegatePropertyAccessor; 74 import org.apache.tiles.ognl.NestedObjectDelegatePropertyAccessor; 75 import org.apache.tiles.ognl.OGNLAttributeEvaluator; 76 import org.apache.tiles.ognl.PropertyAccessorDelegateFactory; 77 import org.apache.tiles.ognl.RequestScopeNestedObjectExtractor; 78 import org.apache.tiles.ognl.SessionScopeNestedObjectExtractor; 79 import org.apache.tiles.ognl.TilesApplicationContextNestedObjectExtractor; 80 import org.apache.tiles.ognl.TilesContextPropertyAccessorDelegateFactory; 81 import org.apache.tiles.renderer.AttributeRenderer; 82 import org.apache.tiles.renderer.TypeDetectingAttributeRenderer; 83 import org.apache.tiles.renderer.impl.BasicRendererFactory; 84 import org.apache.tiles.renderer.impl.ChainedDelegateAttributeRenderer; 85 import org.apache.tiles.util.URLUtil; 86 import org.apache.tiles.velocity.context.VelocityTilesRequestContextFactory; 87 import org.apache.tiles.velocity.renderer.VelocityAttributeRenderer; 88 import org.mvel2.integration.VariableResolverFactory; 89 90 /** 91 * Tiles container factory that: 92 * <ul> 93 * <li>create supporting objects for Velocity and FreeMarker;</li> 94 * <li>create renderers for Velocity and FreeMarker templates;</li> 95 * <li>allows using EL, MVEL and OGNL as attribute expressions;</li> 96 * <li>allows using Wildcards and Regular Expressions in definition names;</li> 97 * <li>loads Tiles 1.x definition files;</li> 98 * <li>loads all the definition files that have the "tiles*.xml" pattern under 99 * <code>/WEB-INF</code> directory (and subdirectories) and under 100 * <code>META-INF</code> directories (and subdirectories) in every jar.</li> 101 * </ul> 102 * 103 * @version $Rev: 821300 $ $Date: 2009-10-03 14:16:36 +0200 (sab, 03 ott 2009) $ 104 * @since 2.2.0 105 */ 106 public class CompleteAutoloadTilesContainerFactory extends BasicTilesContainerFactory { 107 108 /** 109 * The freemarker renderer name. 110 */ 111 private static final String FREEMARKER_RENDERER_NAME = "freemarker"; 112 113 /** 114 * The velocity renderer name. 115 */ 116 private static final String VELOCITY_RENDERER_NAME = "velocity"; 117 118 /** {@inheritDoc} */ 119 @Override 120 protected BasicTilesContainer instantiateContainer( 121 TilesApplicationContext applicationContext) { 122 return new CachingTilesContainer(); 123 } 124 125 /** {@inheritDoc} */ 126 @Override 127 protected List<TilesRequestContextFactory> getTilesRequestContextFactoriesToBeChained( 128 ChainedTilesRequestContextFactory parent) { 129 List<TilesRequestContextFactory> factories = super.getTilesRequestContextFactoriesToBeChained(parent); 130 registerRequestContextFactory( 131 FreeMarkerTilesRequestContextFactory.class.getName(), 132 factories, parent); 133 registerRequestContextFactory( 134 VelocityTilesRequestContextFactory.class.getName(), 135 factories, parent); 136 return factories; 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 protected void registerAttributeRenderers( 142 BasicRendererFactory rendererFactory, 143 TilesApplicationContext applicationContext, 144 TilesRequestContextFactory contextFactory, 145 TilesContainer container, 146 AttributeEvaluatorFactory attributeEvaluatorFactory) { 147 super.registerAttributeRenderers(rendererFactory, applicationContext, contextFactory, 148 container, attributeEvaluatorFactory); 149 150 FreeMarkerAttributeRenderer freemarkerRenderer = new FreeMarkerAttributeRenderer(); 151 freemarkerRenderer.setApplicationContext(applicationContext); 152 freemarkerRenderer.setAttributeEvaluatorFactory(attributeEvaluatorFactory); 153 freemarkerRenderer.setRequestContextFactory(contextFactory); 154 freemarkerRenderer.setParameter("TemplatePath", "/"); 155 freemarkerRenderer.setParameter("NoCache", "true"); 156 freemarkerRenderer.setParameter("ContentType", "text/html"); 157 freemarkerRenderer.setParameter("template_update_delay", "0"); 158 freemarkerRenderer.setParameter("default_encoding", "ISO-8859-1"); 159 freemarkerRenderer.setParameter("number_format", "0.##########"); 160 freemarkerRenderer.commit(); 161 rendererFactory.registerRenderer(FREEMARKER_RENDERER_NAME, freemarkerRenderer); 162 163 VelocityAttributeRenderer velocityRenderer = new VelocityAttributeRenderer(); 164 velocityRenderer.setApplicationContext(applicationContext); 165 velocityRenderer.setAttributeEvaluatorFactory(attributeEvaluatorFactory); 166 velocityRenderer.setRequestContextFactory(contextFactory); 167 velocityRenderer.commit(); 168 rendererFactory.registerRenderer(VELOCITY_RENDERER_NAME, velocityRenderer); 169 } 170 171 172 173 /** {@inheritDoc} */ 174 @Override 175 protected AttributeRenderer createDefaultAttributeRenderer( 176 BasicRendererFactory rendererFactory, 177 TilesApplicationContext applicationContext, 178 TilesRequestContextFactory contextFactory, 179 TilesContainer container, 180 AttributeEvaluatorFactory attributeEvaluatorFactory) { 181 ChainedDelegateAttributeRenderer retValue = new ChainedDelegateAttributeRenderer(); 182 retValue.addAttributeRenderer((TypeDetectingAttributeRenderer) rendererFactory 183 .getRenderer(DEFINITION_RENDERER_NAME)); 184 retValue.addAttributeRenderer((TypeDetectingAttributeRenderer) rendererFactory 185 .getRenderer(VELOCITY_RENDERER_NAME)); 186 retValue.addAttributeRenderer((TypeDetectingAttributeRenderer) rendererFactory 187 .getRenderer(FREEMARKER_RENDERER_NAME)); 188 retValue.addAttributeRenderer((TypeDetectingAttributeRenderer) rendererFactory 189 .getRenderer(TEMPLATE_RENDERER_NAME)); 190 retValue.addAttributeRenderer((TypeDetectingAttributeRenderer) rendererFactory 191 .getRenderer(STRING_RENDERER_NAME)); 192 retValue.setApplicationContext(applicationContext); 193 retValue.setRequestContextFactory(contextFactory); 194 retValue.setAttributeEvaluatorFactory(attributeEvaluatorFactory); 195 return retValue; 196 } 197 198 /** {@inheritDoc} */ 199 @Override 200 protected AttributeEvaluatorFactory createAttributeEvaluatorFactory( 201 TilesApplicationContext applicationContext, 202 TilesRequestContextFactory contextFactory, LocaleResolver resolver) { 203 BasicAttributeEvaluatorFactory attributeEvaluatorFactory = new BasicAttributeEvaluatorFactory( 204 createELEvaluator(applicationContext)); 205 attributeEvaluatorFactory.registerAttributeEvaluator("MVEL", 206 createMVELEvaluator()); 207 attributeEvaluatorFactory.registerAttributeEvaluator("OGNL", 208 createOGNLEvaluator()); 209 210 return attributeEvaluatorFactory; 211 } 212 213 /** {@inheritDoc} */ 214 @Override 215 protected <T> PatternDefinitionResolver<T> createPatternDefinitionResolver( 216 Class<T> customizationKeyClass) { 217 DefinitionPatternMatcherFactory wildcardFactory = new WildcardDefinitionPatternMatcherFactory(); 218 DefinitionPatternMatcherFactory regexpFactory = new RegexpDefinitionPatternMatcherFactory(); 219 PrefixedPatternDefinitionResolver<T> resolver = new PrefixedPatternDefinitionResolver<T>(); 220 resolver.registerDefinitionPatternMatcherFactory("WILDCARD", wildcardFactory); 221 resolver.registerDefinitionPatternMatcherFactory("REGEXP", regexpFactory); 222 return resolver; 223 } 224 225 /** {@inheritDoc} */ 226 @Override 227 protected List<URL> getSourceURLs(TilesApplicationContext applicationContext, 228 TilesRequestContextFactory contextFactory) { 229 try { 230 Set<URL> urlSet = applicationContext 231 .getResources("/WEB-INF/**/tiles*.xml"); 232 urlSet.addAll(applicationContext 233 .getResources("classpath*:META-INF/**/tiles*.xml")); 234 return URLUtil.getBaseTilesDefinitionURLs(urlSet); 235 } catch (IOException e) { 236 throw new DefinitionsFactoryException( 237 "Cannot load definition URLs", e); 238 } 239 } 240 241 /** {@inheritDoc} */ 242 @Override 243 protected DefinitionsReader createDefinitionsReader(TilesApplicationContext applicationContext, 244 TilesRequestContextFactory contextFactory) { 245 return new CompatibilityDigesterDefinitionsReader(); 246 } 247 248 /** 249 * Creates the EL evaluator. 250 * 251 * @param applicationContext The Tiles application context. 252 * @return The EL evaluator. 253 */ 254 private ELAttributeEvaluator createELEvaluator( 255 TilesApplicationContext applicationContext) { 256 ELAttributeEvaluator evaluator = new ELAttributeEvaluator(); 257 evaluator.setApplicationContext(applicationContext); 258 JspExpressionFactoryFactory efFactory = new JspExpressionFactoryFactory(); 259 efFactory.setApplicationContext(applicationContext); 260 evaluator.setExpressionFactory(efFactory.getExpressionFactory()); 261 ELResolver elResolver = new CompositeELResolver() { 262 { 263 add(new TilesContextELResolver()); 264 add(new TilesContextBeanELResolver()); 265 add(new ArrayELResolver(false)); 266 add(new ListELResolver(false)); 267 add(new MapELResolver(false)); 268 add(new ResourceBundleELResolver()); 269 add(new BeanELResolver(false)); 270 } 271 }; 272 evaluator.setResolver(elResolver); 273 return evaluator; 274 } 275 276 /** 277 * Creates the MVEL evaluator. 278 * 279 * @return The MVEL evaluator. 280 */ 281 private MVELAttributeEvaluator createMVELEvaluator() { 282 TilesRequestContextHolder requestHolder = new TilesRequestContextHolder(); 283 VariableResolverFactory variableResolverFactory = new TilesContextVariableResolverFactory( 284 requestHolder); 285 variableResolverFactory 286 .setNextFactory(new TilesContextBeanVariableResolverFactory( 287 requestHolder)); 288 MVELAttributeEvaluator mvelEvaluator = new MVELAttributeEvaluator(requestHolder, 289 variableResolverFactory); 290 return mvelEvaluator; 291 } 292 293 /** 294 * Creates the OGNL evaluator. 295 * 296 * @return The OGNL evaluator. 297 */ 298 private OGNLAttributeEvaluator createOGNLEvaluator() { 299 try { 300 PropertyAccessor objectPropertyAccessor = OgnlRuntime.getPropertyAccessor(Object.class); 301 PropertyAccessor mapPropertyAccessor = OgnlRuntime.getPropertyAccessor(Map.class); 302 PropertyAccessor applicationContextPropertyAccessor = 303 new NestedObjectDelegatePropertyAccessor<TilesRequestContext>( 304 new TilesApplicationContextNestedObjectExtractor(), 305 objectPropertyAccessor); 306 PropertyAccessor requestScopePropertyAccessor = 307 new NestedObjectDelegatePropertyAccessor<TilesRequestContext>( 308 new RequestScopeNestedObjectExtractor(), mapPropertyAccessor); 309 PropertyAccessor sessionScopePropertyAccessor = 310 new NestedObjectDelegatePropertyAccessor<TilesRequestContext>( 311 new SessionScopeNestedObjectExtractor(), mapPropertyAccessor); 312 PropertyAccessor applicationScopePropertyAccessor = 313 new NestedObjectDelegatePropertyAccessor<TilesRequestContext>( 314 new ApplicationScopeNestedObjectExtractor(), mapPropertyAccessor); 315 PropertyAccessorDelegateFactory<TilesRequestContext> factory = 316 new TilesContextPropertyAccessorDelegateFactory( 317 objectPropertyAccessor, applicationContextPropertyAccessor, 318 requestScopePropertyAccessor, sessionScopePropertyAccessor, 319 applicationScopePropertyAccessor); 320 PropertyAccessor tilesRequestAccessor = new DelegatePropertyAccessor<TilesRequestContext>(factory); 321 OgnlRuntime.setPropertyAccessor(TilesRequestContext.class, tilesRequestAccessor); 322 return new OGNLAttributeEvaluator(); 323 } catch (OgnlException e) { 324 throw new TilesContainerFactoryException( 325 "Cannot initialize OGNL evaluator", e); 326 } 327 } 328 }