1 15 package org.apache.tapestry.services.impl; 16 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.Map ; 20 import java.util.Set ; 21 22 import org.apache.commons.logging.Log; 23 import org.apache.hivemind.ApplicationRuntimeException; 24 import org.apache.hivemind.Location; 25 import org.apache.tapestry.BaseComponent; 26 import org.apache.tapestry.IBinding; 27 import org.apache.tapestry.IComponent; 28 import org.apache.tapestry.IRender; 29 import org.apache.tapestry.IRequestCycle; 30 import org.apache.tapestry.ITemplateComponent; 31 import org.apache.tapestry.Tapestry; 32 import org.apache.tapestry.binding.BindingConstants; 33 import org.apache.tapestry.binding.BindingSource; 34 import org.apache.tapestry.binding.BindingUtils; 35 import org.apache.tapestry.binding.LiteralBinding; 36 import org.apache.tapestry.engine.IPageLoader; 37 import org.apache.tapestry.parse.CloseToken; 38 import org.apache.tapestry.parse.ComponentTemplate; 39 import org.apache.tapestry.parse.LocalizationToken; 40 import org.apache.tapestry.parse.OpenToken; 41 import org.apache.tapestry.parse.TemplateToken; 42 import org.apache.tapestry.parse.TextToken; 43 import org.apache.tapestry.parse.TokenType; 44 import org.apache.tapestry.services.TemplateSource; 45 import org.apache.tapestry.spec.IComponentSpecification; 46 import org.apache.tapestry.spec.IContainedComponent; 47 import org.apache.tapestry.spec.IParameterSpecification; 48 49 57 public class ComponentTemplateLoaderLogic 58 { 59 private Log _log; 60 61 private IPageLoader _pageLoader; 62 63 private IRequestCycle _requestCycle; 64 65 private ITemplateComponent _loadComponent; 66 67 private BindingSource _bindingSource; 68 69 private IComponent[] _stack; 70 71 private int _stackx; 72 73 private IComponent _activeComponent = null; 74 75 private Set _seenIds = new HashSet (); 76 77 public ComponentTemplateLoaderLogic(Log log, IPageLoader pageLoader, BindingSource bindingSource) 78 { 79 _log = log; 80 _pageLoader = pageLoader; 81 _bindingSource = bindingSource; 82 } 83 84 public void loadTemplate(IRequestCycle requestCycle, ITemplateComponent loadComponent, 85 ComponentTemplate template) 86 { 87 _requestCycle = requestCycle; 88 _loadComponent = loadComponent; 89 90 process(template); 91 } 92 93 private void process(ComponentTemplate template) 94 { 95 int count = template.getTokenCount(); 96 97 _stack = new IComponent[count]; 98 99 for (int i = 0; i < count; i++) 100 { 101 TemplateToken token = template.getToken(i); 102 103 TokenType type = token.getType(); 104 105 if (type == TokenType.TEXT) 106 { 107 process((TextToken) token); 108 continue; 109 } 110 111 if (type == TokenType.OPEN) 112 { 113 process((OpenToken) token); 114 continue; 115 } 116 117 if (type == TokenType.CLOSE) 118 { 119 process((CloseToken) token); 120 continue; 121 } 122 123 if (type == TokenType.LOCALIZATION) 124 { 125 process((LocalizationToken) token); 126 continue; 127 } 128 } 129 130 133 if (_stackx != 0) 134 throw new ApplicationRuntimeException(Tapestry 135 .getMessage("BaseComponent.unbalance-open-tags"), _loadComponent, null, null); 136 137 checkAllComponentsReferenced(); 138 } 139 140 147 148 private void process(TextToken token) 149 { 150 if (_activeComponent == null) 151 { 152 _loadComponent.addOuter(token); 153 return; 154 } 155 156 if (!_activeComponent.getSpecification().getAllowBody()) 157 throw createBodylessComponentException(_activeComponent); 158 159 _activeComponent.addBody(token); 160 } 161 162 private void process(OpenToken token) 163 { 164 String id = token.getId(); 165 IComponent component = null; 166 String componentType = token.getComponentType(); 167 168 if (componentType == null) 169 component = getEmbeddedComponent(id); 170 else 171 { 172 checkForDuplicateId(id, token.getLocation()); 173 174 component = createImplicitComponent(id, componentType, token.getLocation()); 175 } 176 177 179 if (_seenIds.contains(id)) 180 throw new ApplicationRuntimeException(ImplMessages.multipleComponentReferences( 181 _loadComponent, 182 id), _loadComponent, token.getLocation(), null); 183 184 _seenIds.add(id); 185 186 if (_activeComponent == null) 187 _loadComponent.addOuter(component); 188 else 189 { 190 193 if (!_activeComponent.getSpecification().getAllowBody()) 194 throw createBodylessComponentException(_activeComponent); 195 196 _activeComponent.addBody(component); 197 } 198 199 addTemplateBindings(component, token); 200 201 _stack[_stackx++] = _activeComponent; 202 203 _activeComponent = component; 204 } 205 206 private void checkForDuplicateId(String id, Location location) 207 { 208 if (id == null) 209 return; 210 211 IContainedComponent cc = _loadComponent.getSpecification().getComponent(id); 212 213 if (cc != null) 214 throw new ApplicationRuntimeException(ImplMessages.dupeComponentId(id, cc), 215 _loadComponent, location, null); 216 } 217 218 private IComponent createImplicitComponent(String id, String componentType, Location location) 219 { 220 IComponent result = _pageLoader.createImplicitComponent( 221 _requestCycle, 222 _loadComponent, 223 id, 224 componentType, 225 location); 226 227 return result; 228 } 229 230 private IComponent getEmbeddedComponent(String id) 231 { 232 return _loadComponent.getComponent(id); 233 } 234 235 private void process(CloseToken token) 236 { 237 240 if (_stackx <= 0) 241 throw new ApplicationRuntimeException(ImplMessages.unbalancedCloseTags(), 242 _loadComponent, token.getLocation(), null); 243 244 246 _stack[_stackx--] = null; 247 248 _activeComponent = _stack[_stackx]; 249 } 250 251 private void process(LocalizationToken token) 252 { 253 IRender render = new LocalizedStringRender(_loadComponent, token); 254 255 if (_activeComponent == null) 256 _loadComponent.addOuter(render); 257 else 258 _activeComponent.addBody(render); 259 } 260 261 264 265 void addTemplateBindings(IComponent component, OpenToken token) 266 { 267 IComponentSpecification spec = component.getSpecification(); 268 269 Map attributes = token.getAttributesMap(); 270 271 if (attributes != null) 272 { 273 Iterator i = attributes.entrySet().iterator(); 274 275 while (i.hasNext()) 276 { 277 Map.Entry entry = (Map.Entry ) i.next(); 278 279 String attributeName = (String ) entry.getKey(); 280 String value = (String ) entry.getValue(); 281 282 IParameterSpecification pspec = spec.getParameter(attributeName); 283 String parameterName = pspec == null ? attributeName : pspec.getParameterName(); 284 285 if (!attributeName.equals(parameterName)) 286 _log.error(ImplMessages.usedTemplateParameterAlias( 287 token, 288 attributeName, 289 parameterName)); 290 291 String description = ImplMessages.templateParameterName(parameterName); 292 293 297 String defaultBindingType = BindingUtils.getDefaultBindingType( 298 spec, 299 parameterName, 300 BindingConstants.LITERAL_PREFIX); 301 302 IBinding binding = _bindingSource.createBinding( 303 _loadComponent, 304 description, 305 value, 306 defaultBindingType, 307 token.getLocation()); 308 309 addBinding(component, spec, parameterName, binding); 310 } 311 } 312 313 317 if (spec.getParameter(TemplateSource.TEMPLATE_TAG_PARAMETER_NAME) != null 318 && component.getBinding(TemplateSource.TEMPLATE_TAG_PARAMETER_NAME) == null) 319 { 320 IBinding binding = _bindingSource.createBinding( 321 component, 322 TemplateSource.TEMPLATE_TAG_PARAMETER_NAME, 323 token.getTag(), 324 BindingConstants.LITERAL_PREFIX, 325 token.getLocation()); 326 327 addBinding(component, spec, TemplateSource.TEMPLATE_TAG_PARAMETER_NAME, binding); 328 } 329 } 330 331 336 337 private void addBinding(IComponent component, IComponentSpecification spec, String name, 338 IBinding binding) 339 { 340 341 344 boolean valid = validate(component, spec, name, binding); 345 346 if (valid) 347 component.setBinding(name, binding); 348 } 349 350 private boolean validate(IComponent component, IComponentSpecification spec, String name, 351 IBinding binding) 352 { 353 356 boolean literal = binding instanceof LiteralBinding; 357 358 boolean isFormal = (spec.getParameter(name) != null); 359 360 if (isFormal) 361 { 362 if (component.getBinding(name) != null) 363 { 364 367 if (literal) 368 return false; 369 370 throw new ApplicationRuntimeException(ImplMessages.dupeTemplateBinding( 371 name, 372 component, 373 _loadComponent), component, binding.getLocation(), null); 374 } 375 376 return true; 377 } 378 379 if (!spec.getAllowInformalParameters()) 380 { 381 384 if (literal) 385 return false; 386 387 throw new ApplicationRuntimeException(ImplMessages.templateBindingForInformalParameter( 388 _loadComponent, 389 name, 390 component), component, binding.getLocation(), null); 391 } 392 393 396 if (spec.isReservedParameterName(name)) 397 { 398 401 if (literal) 402 return false; 403 404 throw new ApplicationRuntimeException(ImplMessages.templateBindingForReservedParameter( 405 _loadComponent, 406 name, 407 component), component, binding.getLocation(), null); 408 } 409 410 return true; 411 } 412 413 private void checkAllComponentsReferenced() 414 { 415 418 Map components = _loadComponent.getComponents(); 419 420 Set ids = components.keySet(); 421 422 425 if (_seenIds.containsAll(ids)) 426 return; 427 428 431 ids = new HashSet (ids); 432 ids.removeAll(_seenIds); 433 434 _log.error(ImplMessages.missingComponentSpec(_loadComponent, ids)); 435 436 } 437 438 private ApplicationRuntimeException createBodylessComponentException(IComponent component) 439 { 440 return new ApplicationRuntimeException(ImplMessages.bodylessComponent(), component, null, 441 null); 442 } 443 } | Popular Tags |