1 16 package org.apache.cocoon.components.treeprocessor; 17 18 import org.apache.avalon.excalibur.component.DefaultRoleManager; 19 import org.apache.avalon.excalibur.component.ExcaliburComponentSelector; 20 import org.apache.avalon.excalibur.component.RoleManageable; 21 import org.apache.avalon.excalibur.component.RoleManager; 22 import org.apache.avalon.excalibur.pool.Recyclable; 23 import org.apache.avalon.framework.activity.Disposable; 24 import org.apache.avalon.framework.activity.Initializable; 25 import org.apache.avalon.framework.component.ComponentException; 26 import org.apache.avalon.framework.component.ComponentManager; 27 import org.apache.avalon.framework.component.ComponentSelector; 28 import org.apache.avalon.framework.component.Recomposable; 29 import org.apache.avalon.framework.configuration.AbstractConfiguration; 30 import org.apache.avalon.framework.configuration.Configurable; 31 import org.apache.avalon.framework.configuration.Configuration; 32 import org.apache.avalon.framework.configuration.ConfigurationException; 33 import org.apache.avalon.framework.configuration.NamespacedSAXConfigurationHandler; 34 import org.apache.avalon.framework.context.Context; 35 import org.apache.avalon.framework.context.ContextException; 36 import org.apache.avalon.framework.context.Contextualizable; 37 import org.apache.avalon.framework.logger.AbstractLogEnabled; 38 import org.apache.cocoon.ProcessingException; 39 import org.apache.cocoon.components.ExtendedComponentSelector; 40 import org.apache.cocoon.components.LifecycleHelper; 41 import org.apache.cocoon.components.source.SourceUtil; 42 import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory; 43 import org.apache.cocoon.sitemap.PatternException; 44 import org.apache.cocoon.sitemap.SitemapParameters; 45 import org.apache.cocoon.util.location.Location; 46 import org.apache.cocoon.util.location.LocationImpl; 47 import org.apache.cocoon.util.location.LocationUtils; 48 import org.apache.excalibur.source.Source; 49 50 import java.util.ArrayList ; 51 import java.util.HashMap ; 52 import java.util.Iterator ; 53 import java.util.List ; 54 import java.util.Map ; 55 56 61 62 public class DefaultTreeBuilder extends AbstractLogEnabled implements TreeBuilder, 63 Recomposable, Configurable, Contextualizable, RoleManageable, Recyclable, Disposable { 64 65 protected Map attributes = new HashMap (); 66 67 70 protected ConcreteTreeProcessor processor; 71 72 protected Context context; 74 75 79 protected ComponentManager parentManager; 80 81 85 protected RoleManager parentRoleManager; 86 87 protected Configuration configuration; 88 90 93 protected ComponentManager manager; 94 95 98 protected RoleManager roleManager; 99 100 101 protected ComponentSelector builderSelector; 102 103 protected LifecycleHelper lifecycle; 104 105 protected String namespace; 106 107 protected String parameterElement; 108 109 protected String languageName; 110 111 protected String fileName; 112 113 114 private List initializableNodes = new ArrayList (); 115 116 117 private List disposableNodes = new ArrayList (); 118 119 120 private List linkedBuilders = new ArrayList (); 121 122 123 private boolean canGetNode = false; 124 125 126 private Map registeredNodes = new HashMap (); 127 128 129 public void contextualize(Context context) throws ContextException { 130 this.context = context; 131 } 132 133 public void compose(ComponentManager manager) throws ComponentException { 134 this.parentManager = manager; 135 } 136 137 public void recompose(ComponentManager manager) throws ComponentException { 138 this.parentManager = manager; 139 } 140 141 public void setRoleManager(RoleManager rm) { 142 this.parentRoleManager = rm; 143 } 144 145 148 public void configure(Configuration config) throws ConfigurationException { 149 this.configuration = config; 150 151 this.languageName = config.getAttribute("name"); 152 if (this.getLogger().isDebugEnabled()) { 153 getLogger().debug("Configuring Builder for language : " + this.languageName); 154 } 155 156 this.fileName = config.getChild("file").getAttribute("name"); 157 158 this.namespace = config.getChild("namespace").getAttribute("uri", ""); 159 160 this.parameterElement = config.getChild("parameter").getAttribute("element", "parameter"); 161 } 162 163 public void setAttribute(String name, Object value) { 164 this.attributes.put(name, value); 165 } 166 167 public Object getAttribute(String name) { 168 return this.attributes.get(name); 169 } 170 171 181 protected RoleManager createRoleManager() throws Exception 182 { 183 RoleManager roles = new DefaultRoleManager(this.parentRoleManager); 184 185 LifecycleHelper.setupComponent(roles, 186 getLogger(), 187 this.context, 188 this.manager, 189 this.parentRoleManager, 190 this.configuration.getChild("roles") 191 ); 192 193 return roles; 194 } 195 196 208 protected ComponentManager createComponentManager(Configuration tree) throws Exception 209 { 210 return this.parentManager; 211 } 212 213 219 protected ComponentSelector createBuilderSelector() throws Exception { 220 221 ExcaliburComponentSelector selector = new ExtendedComponentSelector() { 223 protected String getComponentInstanceName() { 224 return "node"; 225 } 226 227 protected String getClassAttributeName() { 228 return "builder"; 229 } 230 }; 231 232 LifecycleHelper.setupComponent(selector, 234 getLogger(), 235 this.context, 236 this.manager, 237 this.roleManager, 238 this.configuration.getChild("nodes") 239 ); 240 241 return selector; 242 } 243 244 public void setProcessor(ConcreteTreeProcessor processor) { 245 this.processor = processor; 246 } 247 248 public ConcreteTreeProcessor getProcessor() { 249 return this.processor; 250 } 251 252 255 public String getLanguage() { 256 return this.languageName; 257 } 258 259 262 public String getParameterName() { 263 return this.parameterElement; 264 } 265 266 269 public boolean registerNode(String name, ProcessingNode node) { 270 if ( this.registeredNodes.containsKey(name) ) { 271 return false; 272 } 273 this.registeredNodes.put(name, node); 274 return true; 275 } 276 277 public ProcessingNode getRegisteredNode(String name) { 278 if (this.canGetNode) { 279 return (ProcessingNode)this.registeredNodes.get(name); 280 } else { 281 throw new IllegalArgumentException ("Categories are only available during buildNode()"); 282 } 283 } 284 285 public ProcessingNodeBuilder createNodeBuilder(Configuration config) throws Exception { 286 String nodeName = config.getName(); 288 289 if (this.getLogger().isDebugEnabled()) { 290 getLogger().debug("Creating node builder for " + nodeName); 291 } 292 293 ProcessingNodeBuilder builder; 294 try { 295 builder = (ProcessingNodeBuilder)this.builderSelector.select(nodeName); 296 297 } catch(ComponentException ce) { 298 if (this.builderSelector.hasComponent(nodeName)) { 300 throw ce; 302 } else { 303 String msg = "Unknown element '" + nodeName + "' at " + config.getLocation(); 305 throw new ConfigurationException(msg); 306 } 307 } 308 309 if (builder instanceof Recomposable) { 310 ((Recomposable)builder).recompose(this.manager); 311 } 312 313 builder.setBuilder(this); 314 315 if (builder instanceof LinkedProcessingNodeBuilder) { 316 this.linkedBuilders.add(builder); 317 } 318 319 return builder; 320 } 321 322 326 protected ProcessingNode createTree(Configuration tree) throws Exception { 327 ProcessingNodeBuilder rootBuilder = createNodeBuilder(tree); 329 330 return rootBuilder.buildNode(tree); 332 } 333 334 339 protected void linkNodes() throws Exception { 340 Iterator iter = this.linkedBuilders.iterator(); 342 while(iter.hasNext()) { 343 ((LinkedProcessingNodeBuilder)iter.next()).linkNode(); 344 } 345 } 346 347 350 public String getNamespace() { 351 return this.namespace; 352 } 353 354 public ProcessingNode build(Source source) 355 throws Exception { 356 357 try { 358 NamespacedSAXConfigurationHandler handler = new NamespacedSAXConfigurationHandler(); 360 AnnotationsFilter annotationsFilter = new AnnotationsFilter(handler); 361 SourceUtil.toSAX( source, annotationsFilter ); 362 Configuration treeConfig = handler.getConfiguration(); 363 364 return build(treeConfig); 365 } catch (ProcessingException e) { 366 throw e; 367 } catch(Exception e) { 368 throw new ProcessingException("Failed to load " + this.languageName + " from " + 369 source.getURI(), e); 370 } 371 } 372 373 public String getFileName() { 374 return this.fileName; 375 } 376 377 380 public ProcessingNode build(Configuration tree) throws Exception { 381 382 this.roleManager = createRoleManager(); 383 384 this.manager = createComponentManager(tree); 385 386 this.lifecycle = new LifecycleHelper(getLogger(), 388 this.context, 389 this.manager, 390 this.roleManager, 391 null ); 393 394 this.builderSelector = createBuilderSelector(); 395 396 this.canGetNode = false; 398 399 VariableResolverFactory.setDisposableCollector(this.disposableNodes); 401 402 ProcessingNode result = createTree(tree); 403 404 this.canGetNode = true; 406 407 linkNodes(); 408 409 Iterator iter = this.initializableNodes.iterator(); 411 while(iter.hasNext()) { 412 ((Initializable)iter.next()).initialize(); 413 } 414 415 return result; 417 } 418 419 424 public List getDisposableNodes() { 425 return this.disposableNodes; 426 } 427 428 431 public ComponentManager getSitemapComponentManager() { 432 return this.manager; 433 } 434 435 443 public ProcessingNode setupNode(ProcessingNode node, Configuration config) 444 throws Exception { 445 Location location = getLocation(config); 446 if (node instanceof AbstractProcessingNode) { 447 ((AbstractProcessingNode)node).setLocation(location); 448 } 449 450 this.lifecycle.setupComponent(node, false); 451 452 if (node instanceof ParameterizableProcessingNode) { 453 Map params = getParameters(config, location); 454 ((ParameterizableProcessingNode)node).setParameters(params); 455 } 456 457 if (node instanceof Initializable) { 458 this.initializableNodes.add(node); 459 } 460 461 if (node instanceof Disposable) { 462 this.disposableNodes.add(node); 463 } 464 465 return node; 466 } 467 468 protected LocationImpl getLocation(Configuration config) { 469 String prefix = ""; 470 471 if (config instanceof AbstractConfiguration) { 472 String namespace = null; 475 try { 476 namespace = ((AbstractConfiguration)config).getNamespace(); 477 } catch (ConfigurationException e) { 478 } 480 if ("http://apache.org/cocoon/sitemap/1.0".equals(namespace)) { 481 prefix="map"; 482 } 483 } 484 485 StringBuffer desc = new StringBuffer ().append('<'); 486 if (prefix.length() > 0) { 487 desc.append(prefix).append(':').append(config.getName()); 488 } else { 489 desc.append(config.getName()); 490 } 491 String type = config.getAttribute("type", null); 492 if (type != null) { 493 desc.append(" type=\"").append(type).append('"'); 494 } 495 desc.append('>'); 496 497 Location rawLoc = LocationUtils.getLocation(config, null); 498 return new LocationImpl(desc.toString(), rawLoc.getURI(), rawLoc.getLineNumber(), rawLoc.getColumnNumber()); 499 } 500 501 507 protected Map getParameters(Configuration config, Location location) throws ConfigurationException { 508 509 Configuration[] children = config.getChildren(this.parameterElement); 510 511 if (children.length == 0) { 512 return new SitemapParameters.LocatedHashMap(location, 0); 515 } 516 517 Map params = new SitemapParameters.LocatedHashMap(location, children.length+1); 518 for (int i = 0; i < children.length; i++) { 519 Configuration child = children[i]; 520 if (true) { String name = child.getAttribute("name"); 522 String value = child.getAttribute("value"); 523 try { 524 params.put( 525 VariableResolverFactory.getResolver(name, this.manager), 526 VariableResolverFactory.getResolver(value, this.manager)); 527 } catch(PatternException pe) { 528 String msg = "Invalid pattern '" + value + "' at " + child.getLocation(); 529 throw new ConfigurationException(msg, pe); 530 } 531 } 532 } 533 534 return params; 535 } 536 537 544 public String getTypeForStatement(Configuration statement, String role) throws ConfigurationException { 545 546 String type = statement.getAttribute("type", null); 547 548 ComponentSelector selector = null; 549 550 try { 551 try { 552 selector = (ComponentSelector)this.manager.lookup(role); 553 } catch(ComponentException ce) { 554 String msg = "Cannot get component selector for '" + statement.getName() + "' at " + 555 statement.getLocation(); 556 throw new ConfigurationException(msg, ce); 557 } 558 559 if (type == null && selector instanceof ExtendedComponentSelector) { 560 type = ((ExtendedComponentSelector)selector).getDefaultHint(); 561 } 562 563 if (type == null) { 564 String msg = "No default type exists for '" + statement.getName() + "' at " + 565 statement.getLocation(); 566 throw new ConfigurationException(msg); 567 } 568 569 if (!selector.hasComponent(type)) { 570 String msg = "Type '" + type + "' is not defined for '" + statement.getName() + "' at " + 571 statement.getLocation(); 572 throw new ConfigurationException(msg); 573 } 574 } finally { 575 this.manager.release(selector); 576 } 577 return type; 578 } 579 580 public void recycle() { 581 this.lifecycle = null; this.initializableNodes.clear(); 583 this.linkedBuilders.clear(); 584 this.canGetNode = false; 585 this.registeredNodes.clear(); 586 587 this.disposableNodes = new ArrayList (); 589 VariableResolverFactory.setDisposableCollector(null); 590 591 this.processor = null; 592 this.manager = null; 593 this.roleManager = null; 594 } 595 596 public void dispose() { 597 LifecycleHelper.dispose(this.builderSelector); 598 599 } 602 } 603 | Popular Tags |