1 15 package org.apache.tapestry.services.impl; 16 17 import java.io.BufferedInputStream ; 18 import java.io.IOException ; 19 import java.io.InputStream ; 20 import java.io.InputStreamReader ; 21 import java.net.URL ; 22 import java.util.Collections ; 23 import java.util.HashMap ; 24 import java.util.Locale ; 25 import java.util.Map ; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.hivemind.ApplicationRuntimeException; 29 import org.apache.hivemind.Resource; 30 import org.apache.tapestry.IAsset; 31 import org.apache.tapestry.IComponent; 32 import org.apache.tapestry.IPage; 33 import org.apache.tapestry.IRequestCycle; 34 import org.apache.tapestry.Tapestry; 35 import org.apache.tapestry.engine.ITemplateSourceDelegate; 36 import org.apache.tapestry.event.ResetEventListener; 37 import org.apache.tapestry.parse.ComponentTemplate; 38 import org.apache.tapestry.parse.ITemplateParser; 39 import org.apache.tapestry.parse.ITemplateParserDelegate; 40 import org.apache.tapestry.parse.TemplateParseException; 41 import org.apache.tapestry.parse.TemplateParser; 42 import org.apache.tapestry.parse.TemplateToken; 43 import org.apache.tapestry.resolver.ComponentSpecificationResolver; 44 import org.apache.tapestry.services.ComponentPropertySource; 45 import org.apache.tapestry.services.TemplateSource; 46 import org.apache.tapestry.spec.IComponentSpecification; 47 import org.apache.tapestry.util.MultiKey; 48 49 55 56 public class TemplateSourceImpl implements TemplateSource, ResetEventListener 57 { 58 private Log _log; 59 60 63 public static final String TEMPLATE_ENCODING_PROPERTY_NAME = "org.apache.tapestry.template-encoding"; 64 65 69 private Map _cache = Collections.synchronizedMap(new HashMap ()); 70 71 74 private Map _templates = Collections.synchronizedMap(new HashMap ()); 75 76 private static final int BUFFER_SIZE = 2000; 77 78 private ITemplateParser _parser; 79 80 81 82 private Resource _contextRoot; 83 84 85 86 private ITemplateSourceDelegate _delegate; 87 88 89 90 private ComponentSpecificationResolver _componentSpecificationResolver; 91 92 93 94 private ComponentPropertySource _componentPropertySource; 95 96 99 100 public void resetEventDidOccur() 101 { 102 _cache.clear(); 103 _templates.clear(); 104 } 105 106 109 110 public ComponentTemplate getTemplate(IRequestCycle cycle, IComponent component) 111 { 112 IComponentSpecification specification = component.getSpecification(); 113 Resource resource = specification.getSpecificationLocation(); 114 115 Locale locale = component.getPage().getLocale(); 116 117 Object key = new MultiKey(new Object [] 118 { resource, locale }, false); 119 120 ComponentTemplate result = searchCache(key); 121 if (result != null) 122 return result; 123 124 result = findTemplate(cycle, resource, component, locale); 125 126 if (result == null) 127 { 128 result = _delegate.findTemplate(cycle, component, locale); 129 130 if (result != null) 131 return result; 132 133 String message = component.getSpecification().isPageSpecification() ? ImplMessages 134 .noTemplateForPage(component.getExtendedId(), locale) : ImplMessages 135 .noTemplateForComponent(component.getExtendedId(), locale); 136 137 throw new ApplicationRuntimeException(message, component, component.getLocation(), null); 138 } 139 140 saveToCache(key, result); 141 142 return result; 143 } 144 145 private ComponentTemplate searchCache(Object key) 146 { 147 return (ComponentTemplate) _cache.get(key); 148 } 149 150 private void saveToCache(Object key, ComponentTemplate template) 151 { 152 _cache.put(key, template); 153 154 } 155 156 167 168 private ComponentTemplate findTemplate(IRequestCycle cycle, Resource resource, 169 IComponent component, Locale locale) 170 { 171 IAsset templateAsset = component.getAsset(TEMPLATE_ASSET_NAME); 172 173 if (templateAsset != null) 174 return readTemplateFromAsset(cycle, component, templateAsset); 175 176 String name = resource.getName(); 177 int dotx = name.lastIndexOf('.'); 178 String templateExtension = getTemplateExtension(component); 179 String templateBaseName = name.substring(0, dotx + 1) + templateExtension; 180 181 ComponentTemplate result = findStandardTemplate( 182 cycle, 183 resource, 184 component, 185 templateBaseName, 186 locale); 187 188 if (result == null && component.getSpecification().isPageSpecification() 189 && component.getNamespace().isApplicationNamespace()) 190 result = findPageTemplateInApplicationRoot( 191 cycle, 192 (IPage) component, 193 templateExtension, 194 locale); 195 196 return result; 197 } 198 199 private ComponentTemplate findPageTemplateInApplicationRoot(IRequestCycle cycle, IPage page, 200 String templateExtension, Locale locale) 201 { 202 210 String templateBaseName = page.getPageName() + "." + templateExtension; 211 212 if (_log.isDebugEnabled()) 213 _log.debug("Checking for " + templateBaseName + " in application root"); 214 215 Resource baseLocation = _contextRoot.getRelativeResource(templateBaseName); 216 Resource localizedLocation = baseLocation.getLocalization(locale); 217 218 if (localizedLocation == null) 219 return null; 220 221 return getOrParseTemplate(cycle, localizedLocation, page); 222 } 223 224 227 228 private ComponentTemplate readTemplateFromAsset(IRequestCycle cycle, IComponent component, 229 IAsset asset) 230 { 231 InputStream stream = asset.getResourceAsStream(cycle); 232 233 char[] templateData = null; 234 235 try 236 { 237 String encoding = getTemplateEncoding(component, null); 238 239 templateData = readTemplateStream(stream, encoding); 240 241 stream.close(); 242 } 243 catch (IOException ex) 244 { 245 throw new ApplicationRuntimeException(ImplMessages.unableToReadTemplate(asset), ex); 246 } 247 248 Resource resourceLocation = asset.getResourceLocation(); 249 250 return constructTemplateInstance(cycle, templateData, resourceLocation, component); 251 } 252 253 259 260 private ComponentTemplate findStandardTemplate(IRequestCycle cycle, Resource resource, 261 IComponent component, String templateBaseName, Locale locale) 262 { 263 if (_log.isDebugEnabled()) 264 _log.debug("Searching for localized version of template for " + resource 265 + " in locale " + locale.getDisplayName()); 266 267 Resource baseTemplateLocation = resource.getRelativeResource(templateBaseName); 268 269 Resource localizedTemplateLocation = baseTemplateLocation.getLocalization(locale); 270 271 if (localizedTemplateLocation == null) 272 return null; 273 274 return getOrParseTemplate(cycle, localizedTemplateLocation, component); 275 276 } 277 278 283 284 private ComponentTemplate getOrParseTemplate(IRequestCycle cycle, Resource resource, 285 IComponent component) 286 { 287 288 ComponentTemplate result = (ComponentTemplate) _templates.get(resource); 289 if (result != null) 290 return result; 291 292 294 result = parseTemplate(cycle, resource, component); 295 296 if (result != null) 297 _templates.put(resource, result); 298 299 return result; 300 } 301 302 307 308 private ComponentTemplate parseTemplate(IRequestCycle cycle, Resource resource, 309 IComponent component) 310 { 311 String encoding = getTemplateEncoding(component, resource.getLocale()); 312 313 char[] templateData = readTemplate(resource, encoding); 314 if (templateData == null) 315 return null; 316 317 return constructTemplateInstance(cycle, templateData, resource, component); 318 } 319 320 325 326 private synchronized ComponentTemplate constructTemplateInstance(IRequestCycle cycle, 327 char[] templateData, Resource resource, IComponent component) 328 { 329 String componentAttributeName = _componentPropertySource.getComponentProperty( 330 component, 331 "org.apache.tapestry.jwcid-attribute-name"); 332 333 ITemplateParserDelegate delegate = new DefaultParserDelegate(component, 334 componentAttributeName, cycle, _componentSpecificationResolver); 335 336 TemplateToken[] tokens; 337 338 try 339 { 340 tokens = _parser.parse(templateData, delegate, resource); 341 } 342 catch (TemplateParseException ex) 343 { 344 throw new ApplicationRuntimeException(ImplMessages.unableToParseTemplate(resource), ex); 345 } 346 347 if (_log.isDebugEnabled()) 348 _log.debug("Parsed " + tokens.length + " tokens from template"); 349 350 return new ComponentTemplate(templateData, tokens); 351 } 352 353 357 358 private char[] readTemplate(Resource resource, String encoding) 359 { 360 if (_log.isDebugEnabled()) 361 _log.debug("Reading template " + resource); 362 363 URL url = resource.getResourceURL(); 364 365 if (url == null) 366 { 367 if (_log.isDebugEnabled()) 368 _log.debug("Template does not exist."); 369 370 return null; 371 } 372 373 if (_log.isDebugEnabled()) 374 _log.debug("Reading template from URL " + url); 375 376 InputStream stream = null; 377 378 try 379 { 380 stream = url.openStream(); 381 382 return readTemplateStream(stream, encoding); 383 } 384 catch (IOException ex) 385 { 386 throw new ApplicationRuntimeException(ImplMessages.unableToReadTemplate(resource), ex); 387 } 388 finally 389 { 390 Tapestry.close(stream); 391 } 392 393 } 394 395 398 399 private char[] readTemplateStream(InputStream stream, String encoding) throws IOException 400 { 401 char[] charBuffer = new char[BUFFER_SIZE]; 402 StringBuffer buffer = new StringBuffer (); 403 404 InputStreamReader reader; 405 if (encoding != null) 406 reader = new InputStreamReader (new BufferedInputStream (stream), encoding); 407 else 408 reader = new InputStreamReader (new BufferedInputStream (stream)); 409 410 try 411 { 412 while (true) 413 { 414 int charsRead = reader.read(charBuffer, 0, BUFFER_SIZE); 415 416 if (charsRead <= 0) 417 break; 418 419 buffer.append(charBuffer, 0, charsRead); 420 } 421 } 422 finally 423 { 424 reader.close(); 425 } 426 427 430 int length = buffer.length(); 431 432 charBuffer = new char[length]; 433 434 437 buffer.getChars(0, length, charBuffer, 0); 438 439 return charBuffer; 440 } 441 442 447 448 private String getTemplateExtension(IComponent component) 449 { 450 return _componentPropertySource.getComponentProperty( 451 component, 452 Tapestry.TEMPLATE_EXTENSION_PROPERTY); 453 } 454 455 private String getTemplateEncoding(IComponent component, Locale locale) 456 { 457 return _componentPropertySource.getLocalizedComponentProperty( 458 component, 459 locale, 460 TEMPLATE_ENCODING_PROPERTY_NAME); 461 } 462 463 464 465 public void setParser(ITemplateParser parser) 466 { 467 _parser = parser; 468 } 469 470 471 472 public void setLog(Log log) 473 { 474 _log = log; 475 } 476 477 478 479 public void setDelegate(ITemplateSourceDelegate delegate) 480 { 481 _delegate = delegate; 482 } 483 484 485 486 public void setComponentSpecificationResolver(ComponentSpecificationResolver resolver) 487 { 488 _componentSpecificationResolver = resolver; 489 } 490 491 492 public void setContextRoot(Resource contextRoot) 493 { 494 _contextRoot = contextRoot; 495 } 496 497 498 public void setComponentPropertySource(ComponentPropertySource componentPropertySource) 499 { 500 _componentPropertySource = componentPropertySource; 501 } 502 } | Popular Tags |