1 16 package org.apache.cocoon.transformation; 17 18 import org.apache.avalon.excalibur.pool.Recyclable; 19 import org.apache.avalon.framework.activity.Disposable; 20 import org.apache.avalon.framework.component.ComponentSelector; 21 import org.apache.avalon.framework.configuration.Configurable; 22 import org.apache.avalon.framework.configuration.Configuration; 23 import org.apache.avalon.framework.configuration.ConfigurationException; 24 import org.apache.avalon.framework.parameters.Parameters; 25 import org.apache.avalon.framework.service.ServiceException; 26 import org.apache.avalon.framework.service.ServiceManager; 27 import org.apache.avalon.framework.service.ServiceSelector; 28 import org.apache.avalon.framework.service.Serviceable; 29 30 import org.apache.cocoon.components.sax.XMLDeserializer; 31 import org.apache.cocoon.components.sax.XMLSerializer; 32 import org.apache.cocoon.environment.SourceResolver; 33 import org.apache.cocoon.taglib.IterationTag; 34 import org.apache.cocoon.taglib.Tag; 35 import org.apache.cocoon.taglib.BodyTag; 36 import org.apache.cocoon.taglib.BodyContent; 37 import org.apache.cocoon.xml.AbstractXMLProducer; 38 import org.apache.cocoon.xml.XMLConsumer; 39 import org.apache.cocoon.xml.XMLProducer; 40 import org.apache.cocoon.xml.SaxBuffer; 41 42 import org.apache.commons.collections.ArrayStack; 43 import org.apache.commons.collections.map.StaticBucketMap; 44 import org.xml.sax.Attributes ; 45 import org.xml.sax.SAXException ; 46 47 import java.beans.BeanInfo ; 48 import java.beans.IntrospectionException ; 49 import java.beans.Introspector ; 50 import java.beans.PropertyDescriptor ; 51 import java.io.IOException ; 52 import java.lang.reflect.Method ; 53 import java.util.HashMap ; 54 import java.util.Map ; 55 56 65 public class TagTransformer 66 extends AbstractXMLProducer 67 implements Transformer, Serviceable, Configurable, Disposable, Recyclable { 68 69 private int recordingLevel; 70 private int skipLevel; 71 72 private String transformerHint; 73 private ServiceSelector transformerSelector; 74 75 private final ArrayStack tagStack = new ArrayStack(); 76 private final ArrayStack tagSelectorStack = new ArrayStack(); 77 private final ArrayStack tagTransformerStack = new ArrayStack(); 78 79 private ServiceSelector tagNamespaceSelector; 80 private Tag currentTag; 81 82 83 private XMLConsumer currentConsumer; 84 85 86 private XMLConsumer currentConsumerBackup; 87 88 private XMLSerializer xmlSerializer; 89 90 91 private SourceResolver resolver; 92 93 94 private Map objectModel; 95 96 97 private Parameters parameters; 98 99 100 private ServiceManager manager; 101 102 103 104 private final String [] paramArray = new String [1]; 105 106 107 private static Map TAG_PROPERTIES_MAP = new StaticBucketMap(); 108 109 113 117 public void service(ServiceManager manager) throws ServiceException { 118 this.manager = manager; 119 this.tagNamespaceSelector = (ServiceSelector) manager.lookup(Tag.ROLE + "Selector"); 120 } 121 122 125 public void configure(Configuration conf) throws ConfigurationException { 126 this.transformerHint = conf.getChild("transformer-hint").getValue(null); 127 if (this.transformerHint != null) { 128 try { 129 this.transformerSelector = (ServiceSelector) manager.lookup(Transformer.ROLE + "Selector"); 130 } catch (ServiceException e) { 131 String message = "Can't lookup transformer selector"; 132 if (getLogger().isDebugEnabled()) { 133 getLogger().debug(message, e); 134 } 135 throw new ConfigurationException(message, e); 136 } 137 } 138 } 139 140 144 public void setup(SourceResolver resolver, Map objectModel, String source, Parameters parameters) 145 throws IOException , SAXException { 146 this.resolver = resolver; 147 this.objectModel = objectModel; 148 this.parameters = parameters; 149 } 150 151 154 public void recycle() { 155 this.recordingLevel = 0; 156 this.skipLevel = 0; 157 this.resolver = null; 158 this.objectModel = null; 159 this.parameters = null; 160 this.currentTag = null; 161 this.currentConsumer = null; 162 this.currentConsumerBackup = null; 163 164 if (xmlSerializer != null) { 166 manager.release(xmlSerializer); 167 xmlSerializer = null; 168 } 169 170 while (!tagStack.isEmpty()) { 171 Tag tag = (Tag) tagStack.pop(); 172 if (tag == null) 173 continue; 174 ComponentSelector tagSelector = (ComponentSelector)tagSelectorStack.pop(); 175 tagSelector.release(tag); 176 177 tagNamespaceSelector.release(tagSelector); 178 } 179 180 while (!tagTransformerStack.isEmpty()) { 181 Transformer transformer = (Transformer) tagTransformerStack.pop(); 182 transformerSelector.release(transformer); 183 } 184 185 if (!tagSelectorStack.isEmpty()) { 186 getLogger().fatalError("recycle: internal Error, tagSelectorStack not empty"); 187 tagSelectorStack.clear(); 188 } 189 190 super.recycle(); 191 } 192 193 196 public void dispose() { 197 this.manager.release(tagNamespaceSelector); 198 tagNamespaceSelector = null; 199 if (transformerSelector != null) { 200 this.manager.release(transformerSelector); 201 transformerSelector = null; 202 } 203 } 204 205 208 public void setConsumer(XMLConsumer consumer) { 209 this.currentConsumer = consumer; 210 super.setConsumer(consumer); 211 } 212 213 214 218 public void setDocumentLocator(org.xml.sax.Locator locator) { 219 if (this.skipLevel > 0) { 221 return; 222 } 223 224 this.currentConsumer.setDocumentLocator(locator); 225 } 226 227 public void startDocument() throws SAXException { 228 this.currentConsumer.startDocument(); 229 } 230 231 public void endDocument() throws SAXException { 232 this.currentConsumer.endDocument(); 233 } 234 235 public void processingInstruction(String target, String data) throws SAXException { 236 if (this.skipLevel > 0) { 238 return; 239 } 240 241 this.currentConsumer.processingInstruction(target, data); 242 } 243 244 public void startDTD(String name, String publicId, String systemId) throws SAXException { 245 if (this.skipLevel > 0) { 247 return; 248 } 249 250 this.currentConsumer.startDTD(name, publicId, systemId); 251 } 252 253 public void endDTD() throws SAXException { 254 if (this.skipLevel > 0) { 256 return; 257 } 258 259 this.currentConsumer.endDTD(); 260 } 261 262 public void startPrefixMapping(String prefix, String uri) throws SAXException { 263 if (this.skipLevel > 0) { 265 return; 266 } 267 268 this.currentConsumer.startPrefixMapping(prefix, uri); 269 } 270 271 public void endPrefixMapping(String prefix) throws SAXException { 272 if (this.skipLevel > 0) { 274 return; 275 } 276 277 this.currentConsumer.endPrefixMapping(prefix); 278 } 279 280 public void startCDATA() throws SAXException { 281 if (this.skipLevel > 0) { 283 return; 284 } 285 286 this.currentConsumer.startCDATA(); 287 } 288 289 public void endCDATA() throws SAXException { 290 if (this.skipLevel > 0) { 292 return; 293 } 294 295 this.currentConsumer.endCDATA(); 296 } 297 298 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) 299 throws SAXException { 300 if (this.recordingLevel > 0) { 302 this.recordingLevel ++; 303 this.currentConsumer.startElement(namespaceURI, localName, qName, atts); 304 return; 305 } 306 307 if (this.skipLevel > 0) { 309 this.skipLevel ++; 311 return; 313 } 314 315 Tag tag = null; 316 if (namespaceURI != null && namespaceURI.length() > 0) { 317 ComponentSelector tagSelector = null; 319 try { 320 tagSelector = (ComponentSelector) tagNamespaceSelector.select(namespaceURI); 321 tagSelectorStack.push(tagSelector); 322 323 tag = (Tag) tagSelector.select(localName); 325 if (getLogger().isDebugEnabled()) { 326 getLogger().debug("startElement: Got tag " + qName); 327 } 328 329 setupTag(tag, qName, atts); 330 } catch (SAXException e) { 331 throw e; 332 } catch (Exception ignore) { 333 } 335 } 336 337 tagStack.push(tag); 338 if (tag == null) { 339 currentConsumer.startElement(namespaceURI, localName, qName, atts); 340 return; 341 } 342 343 int eval = tag.doStartTag(namespaceURI, localName, qName, atts); 345 switch (eval) { 346 case Tag.EVAL_BODY : 347 skipLevel = 0; 348 if (tag instanceof IterationTag) { 349 startRecording(); 351 } 352 break; 353 354 case Tag.SKIP_BODY : 355 skipLevel = 1; 356 break; 357 358 default : 359 String tagName = tag.getClass().getName(); 360 getLogger().warn("Bad return value from doStartTag(" + tagName + "): " + eval); 361 break; 362 } 363 } 364 365 public void endElement(String namespaceURI, String localName, String qName) throws SAXException { 366 Object saxFragment = null; 367 368 if (recordingLevel > 0) { 370 if (--recordingLevel > 0) { 371 currentConsumer.endElement(namespaceURI, localName, qName); 372 return; 373 } 374 saxFragment = endRecording(); 376 } 377 378 if (skipLevel > 0) { 379 if (--skipLevel > 0) { 380 return; 381 } 382 } 383 384 Tag tag = (Tag) tagStack.pop(); 385 if (tag != null) { 386 ComponentSelector tagSelector = (ComponentSelector)tagSelectorStack.pop(); 387 try { 388 if (saxFragment != null) { 389 IterationTag iterTag = (IterationTag) tag; 391 XMLDeserializer xmlDeserializer = null; 392 try { 393 xmlDeserializer = (XMLDeserializer) manager.lookup(XMLDeserializer.ROLE); 394 xmlDeserializer.setConsumer(this); 395 396 XMLConsumer backup = this.currentConsumer; 398 if (tag instanceof BodyTag) { 399 SaxBuffer content = new SaxBuffer(); 400 this.currentConsumer = content; 401 ((BodyTag)tag).setBodyContent(new BodyContent(content, backup)); 402 ((BodyTag)tag).doInitBody(); 403 } 404 405 do { 406 xmlDeserializer.deserialize(saxFragment); 407 } while (iterTag.doAfterBody() != Tag.SKIP_BODY); 408 409 if (tag instanceof BodyTag) { 411 this.currentConsumer = backup; 412 } 413 414 } catch (ServiceException e) { 415 throw new SAXException ("Can't obtain XMLDeserializer", e); 416 } finally { 417 if (xmlDeserializer != null) { 418 manager.release(xmlDeserializer); 419 } 420 } 421 } 422 tag.doEndTag(namespaceURI, localName, qName); 423 currentTag = tag.getParent(); 424 425 if (tag == this.currentConsumer) { 426 popConsumer(); 427 } 428 } finally { 429 if (getLogger().isDebugEnabled()) { 430 getLogger().debug("endElement: Release tag " + qName); 431 } 432 433 tagSelector.release(tag); 434 tagNamespaceSelector.release(tagSelector); 435 436 if (transformerSelector != null && tag instanceof XMLProducer) { 437 getLogger().debug("endElement: Release transformer"); 438 Transformer transformer = (Transformer) tagTransformerStack.pop(); 439 transformerSelector.release(transformer); 440 } 441 } 442 } else { 443 this.currentConsumer.endElement(namespaceURI, localName, qName); 444 } 445 } 446 447 public void startEntity(String name) throws SAXException { 448 if (this.skipLevel > 0) { 450 return; 451 } 452 453 this.currentConsumer.startEntity(name); 454 } 455 456 public void endEntity(String name) throws SAXException { 457 if (this.skipLevel > 0) { 459 return; 460 } 461 462 this.currentConsumer.endEntity(name); 463 } 464 465 public void skippedEntity(String name) throws SAXException { 466 if (this.skipLevel > 0) { 468 return; 469 } 470 471 this.currentConsumer.skippedEntity(name); 472 } 473 474 public void characters(char[] ch, int start, int length) throws SAXException { 475 if (this.skipLevel > 0) { 477 return; 478 } 479 480 this.currentConsumer.characters(ch, start, length); 481 } 482 483 public void comment(char[] ch, int start, int length) throws SAXException { 484 if (this.skipLevel > 0) { 486 return; 487 } 488 489 this.currentConsumer.comment(ch, start, length); 490 } 491 492 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { 493 if (this.skipLevel > 0) { 495 return; 496 } 497 498 this.currentConsumer.ignorableWhitespace(ch, start, length); 499 } 500 501 502 506 private void setupTag(Tag tag, String name, Attributes atts) throws SAXException { 507 tag.setParent(this.currentTag); 509 510 if (tag instanceof XMLProducer) { 512 XMLConsumer tagConsumer; 513 if (transformerSelector != null) { 514 Transformer tagTransformer = null; 515 try { 516 tagTransformer = (Transformer) transformerSelector.select(transformerHint); 518 tagTransformerStack.push(tagTransformer); 519 tagTransformer.setConsumer(currentConsumer); 520 tagTransformer.setup(this.resolver, this.objectModel, null, this.parameters); 521 } catch (SAXException e) { 522 throw e; 523 } catch (Exception e) { 524 throw new SAXException ("Failed to setup tag transformer " + transformerHint, e); 525 } 526 tagConsumer = tagTransformer; 527 } else { 528 tagConsumer = this.currentConsumer; 529 } 530 531 ((XMLProducer) tag).setConsumer(tagConsumer); 532 } 533 534 try { 536 tag.setup(this.resolver, this.objectModel, this.parameters); 537 } catch (IOException e) { 538 throw new SAXException ("Could not set up tag " + name, e); 539 } 540 541 if (tag instanceof XMLConsumer) { 542 this.currentConsumer = (XMLConsumer) tag; 543 } 544 this.currentTag = tag; 545 546 for (int i = 0; i < atts.getLength(); i++) { 548 String attributeName = atts.getLocalName(i); 549 String attributeValue = atts.getValue(i); 550 this.paramArray[0] = attributeValue; 551 try { 552 Method method = getWriteMethod(tag.getClass(), attributeName); 553 method.invoke(tag, this.paramArray); 554 } catch (Throwable e) { 555 if (getLogger().isInfoEnabled()) { 556 getLogger().info("Tag " + name + " attribute " + attributeName + " not set", e); 557 } 558 } 559 } 560 } 561 562 565 private void startRecording() throws SAXException { 566 try { 567 this.xmlSerializer = (XMLSerializer) manager.lookup(XMLSerializer.ROLE); 568 } catch (ServiceException e) { 569 throw new SAXException ("Can't lookup XMLSerializer", e); 570 } 571 572 this.currentConsumerBackup = this.currentConsumer; 573 this.currentConsumer = this.xmlSerializer; 574 this.recordingLevel = 1; 575 } 576 577 580 private Object endRecording() { 581 this.currentConsumer = this.currentConsumerBackup; 583 this.currentConsumerBackup = null; 584 585 Object saxFragment = this.xmlSerializer.getSAXFragment(); 587 588 this.manager.release(this.xmlSerializer); 590 this.xmlSerializer = null; 591 592 return saxFragment; 593 } 594 595 599 private void popConsumer() { 600 Tag loop = this.currentTag; 601 for (; loop != null; loop = loop.getParent()) { 602 if (loop instanceof XMLConsumer) { 603 this.currentConsumer = (XMLConsumer) loop; 604 return; 605 } 606 } 607 608 this.currentConsumer = this.xmlConsumer; 609 } 610 611 private static Method getWriteMethod(Class type, String propertyName) throws IntrospectionException { 612 Map map = getWriteMethodMap(type); 613 Method method = (Method ) map.get(propertyName); 614 if (method == null) { 615 throw new IntrospectionException ("No such property: " + propertyName); 616 } 617 return method; 618 } 619 620 private static Map getWriteMethodMap(Class beanClass) throws IntrospectionException { 621 Map map = (Map) TAG_PROPERTIES_MAP.get(beanClass); 622 if (map != null) { 623 return map; 624 } 625 626 BeanInfo info = Introspector.getBeanInfo(beanClass); 627 if (info != null) { 628 PropertyDescriptor pds[] = info.getPropertyDescriptors(); 629 map = new HashMap (pds.length * 4 / 3, 1); 630 for (int i = 0; i < pds.length; i++) { 631 PropertyDescriptor pd = pds[i]; 632 String name = pd.getName(); 633 Method method = pd.getWriteMethod(); 634 Class type = pd.getPropertyType(); 635 if (type != String .class) continue; 637 map.put(name, method); 638 } 639 } 640 TAG_PROPERTIES_MAP.put(beanClass, map); 641 return map; 642 } 643 } 644 | Popular Tags |