1 16 package org.apache.cocoon.transformation; 17 18 import org.apache.avalon.framework.activity.Disposable; 19 import org.apache.avalon.framework.parameters.Parameters; 20 import org.apache.avalon.framework.service.ServiceException; 21 import org.apache.avalon.framework.service.ServiceManager; 22 23 import org.apache.cocoon.ProcessingException; 24 import org.apache.cocoon.caching.CacheableProcessingComponent; 25 import org.apache.cocoon.components.sax.XMLDeserializer; 26 import org.apache.cocoon.components.sax.XMLSerializer; 27 import org.apache.cocoon.components.source.SourceUtil; 28 import org.apache.cocoon.environment.SourceResolver; 29 import org.apache.cocoon.transformation.helpers.IncludeCacheManager; 30 import org.apache.cocoon.transformation.helpers.IncludeCacheManagerSession; 31 import org.apache.cocoon.xml.IncludeXMLConsumer; 32 import org.apache.cocoon.xml.XMLConsumer; 33 import org.apache.cocoon.xml.XMLUtils; 34 35 import org.apache.commons.lang.BooleanUtils; 36 import org.apache.commons.lang.StringUtils; 37 import org.apache.excalibur.source.Source; 38 import org.apache.excalibur.source.SourceException; 39 import org.apache.excalibur.source.SourceParameters; 40 import org.apache.excalibur.source.SourceValidity; 41 import org.apache.excalibur.xml.dom.DOMParser; 42 import org.apache.excalibur.xml.xpath.XPathProcessor; 43 import org.w3c.dom.Document ; 44 import org.w3c.dom.NodeList ; 45 import org.xml.sax.Attributes ; 46 import org.xml.sax.InputSource ; 47 import org.xml.sax.SAXException ; 48 import org.xml.sax.helpers.AttributesImpl ; 49 50 import java.io.IOException ; 51 import java.io.Serializable ; 52 import java.util.Map ; 53 54 128 public class CIncludeTransformer extends AbstractSAXTransformer 129 implements Disposable, CacheableProcessingComponent { 130 131 public static final String CINCLUDE_NAMESPACE_URI = "http://apache.org/cocoon/include/1.0"; 132 public static final String CINCLUDE_INCLUDE_ELEMENT = "include"; 133 public static final String CINCLUDE_INCLUDE_ELEMENT_SRC_ATTRIBUTE = "src"; 134 public static final String CINCLUDE_INCLUDE_ELEMENT_ELEMENT_ATTRIBUTE = "element"; 135 public static final String CINCLUDE_INCLUDE_ELEMENT_SELECT_ATTRIBUTE = "select"; 136 public static final String CINCLUDE_INCLUDE_ELEMENT_NS_ATTRIBUTE = "ns"; 137 public static final String CINCLUDE_INCLUDE_ELEMENT_PREFIX_ATTRIBUTE = "prefix"; 138 public static final String CINCLUDE_INCLUDE_ELEMENT_STRIP_ROOT_ATTRIBUTE = "strip-root"; 139 140 public static final String CINCLUDE_INCLUDEXML_ELEMENT = "includexml"; 141 public static final String CINCLUDE_INCLUDEXML_ELEMENT_IGNORE_ERRORS_ATTRIBUTE = "ignoreErrors"; 142 public static final String CINCLUDE_SRC_ELEMENT = "src"; 143 public static final String CINCLUDE_CONFIGURATION_ELEMENT = "configuration"; 144 public static final String CINCLUDE_PARAMETERS_ELEMENT = "parameters"; 145 public static final String CINCLUDE_PARAMETER_ELEMENT = "parameter"; 146 public static final String CINCLUDE_NAME_ELEMENT = "name"; 147 public static final String CINCLUDE_VALUE_ELEMENT = "value"; 148 149 public static final String CINCLUDE_CACHED_INCLUDE_ELEMENT = "cached-include"; 150 protected static final String CINCLUDE_CACHED_INCLUDE_PLACEHOLDER_ELEMENT = "cached-includep"; 151 152 private static final int STATE_OUTSIDE = 0; 153 private static final int STATE_INCLUDE = 1; 154 155 156 protected Parameters configurationParameters; 157 158 159 protected SourceParameters resourceParameters; 160 161 162 protected int state; 163 164 protected IncludeCacheManager cacheManager; 165 166 protected IncludeCacheManagerSession cachingSession; 167 168 protected boolean compiling; 169 170 protected IncludeXMLConsumer filter; 171 172 protected XMLSerializer recorder; 173 174 protected AttributesImpl srcAttributes = new AttributesImpl (); 175 176 protected boolean supportCaching; 177 178 179 protected long startTime; 180 181 185 public CIncludeTransformer() { 186 this.defaultNamespaceURI = CINCLUDE_NAMESPACE_URI; 187 } 188 189 192 public void setup(SourceResolver resolver, Map objectModel, 193 String source, Parameters parameters) 194 throws ProcessingException, SAXException , IOException { 195 super.setup(resolver, objectModel, source, parameters); 196 this.state = STATE_OUTSIDE; 197 if ( null != this.cacheManager ) { 198 this.cachingSession = this.cacheManager.getSession( this.parameters ); 199 } 200 this.compiling = false; 201 this.supportCaching = parameters.getParameterAsBoolean("support-caching", false); 202 if (getLogger().isDebugEnabled()) { 203 getLogger().debug("Starting, session " + this.cachingSession); 204 this.startTime = System.currentTimeMillis(); 205 } 206 } 207 208 211 public void service(ServiceManager manager) throws ServiceException { 212 super.service(manager); 213 if (this.manager.hasService(IncludeCacheManager.ROLE)) { 214 this.cacheManager = (IncludeCacheManager) this.manager.lookup(IncludeCacheManager.ROLE); 215 } else { 216 getLogger().warn("The cinclude transformer cannot find the IncludeCacheManager. " + 217 "Therefore caching is turned off for the include transformer."); 218 } 219 } 220 221 224 public void dispose() { 225 if (null != this.manager) { 226 this.manager.release(this.cacheManager); 227 this.manager = null; 228 } 229 super.dispose(); 230 } 231 232 235 public void recycle() { 236 if ( null != this.cachingSession ) { 237 this.cacheManager.terminateSession( this.cachingSession ); 238 } 239 this.cachingSession = null; 240 if ( null != this.recorder) { 241 this.manager.release( this.recorder ); 242 this.recorder = null; 243 } 244 245 this.configurationParameters = null; 246 this.resourceParameters = null; 247 if (getLogger().isDebugEnabled()) { 248 getLogger().debug("Finishing, time: " + 249 (System.currentTimeMillis() - this.startTime)); 250 this.startTime = 0; 251 } 252 this.filter = null; 253 254 super.recycle(); 255 } 256 257 public void startTransformingElement(String uri, String name, String raw, Attributes attr) 258 throws ProcessingException ,IOException , SAXException { 259 if (name.equals(CINCLUDE_INCLUDE_ELEMENT)) { 261 String stripRootValue = attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_STRIP_ROOT_ATTRIBUTE); 262 boolean stripRoot = StringUtils.equals(stripRootValue, "true"); 263 264 processCIncludeElement(attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_SRC_ATTRIBUTE), 265 attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_ELEMENT_ATTRIBUTE), 266 attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_SELECT_ATTRIBUTE), 267 attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_NS_ATTRIBUTE), 268 attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_PREFIX_ATTRIBUTE), 269 stripRoot, 270 false); 271 272 } else if (name.equals(CINCLUDE_INCLUDEXML_ELEMENT) 274 && this.state == STATE_OUTSIDE) { 275 this.state = STATE_INCLUDE; 276 String ignoreErrors = attr.getValue("", CINCLUDE_INCLUDEXML_ELEMENT_IGNORE_ERRORS_ATTRIBUTE); 277 if (ignoreErrors == null || ignoreErrors.length() == 0) { 278 ignoreErrors = "false"; 279 } 280 this.stack.push(BooleanUtils.toBooleanObject(this.ignoreEmptyCharacters)); 281 this.stack.push(BooleanUtils.toBooleanObject(this.ignoreWhitespaces)); 282 this.stack.push(ignoreErrors); 283 284 this.ignoreEmptyCharacters = false; 285 this.ignoreWhitespaces = true; 286 287 } else if (name.equals(CINCLUDE_SRC_ELEMENT) 289 && this.state == STATE_INCLUDE) { 290 this.startTextRecording(); 291 292 } else if (name.equals(CINCLUDE_CONFIGURATION_ELEMENT) 294 && this.state == STATE_INCLUDE) { 295 stack.push("end"); 296 297 } else if (name.equals(CINCLUDE_PARAMETERS_ELEMENT) 299 && this.state == STATE_INCLUDE) { 300 stack.push("end"); 301 302 } else if (name.equals(CINCLUDE_PARAMETER_ELEMENT) 304 && this.state == STATE_INCLUDE) { 305 306 } else if (name.equals(CINCLUDE_NAME_ELEMENT) 308 && this.state == STATE_INCLUDE) { 309 this.startTextRecording(); 310 311 } else if (name.equals(CINCLUDE_VALUE_ELEMENT) 313 && this.state == STATE_INCLUDE) { 314 this.startSerializedXMLRecording(XMLUtils.createPropertiesForXML(true)); 315 316 } else if (name.equals(CINCLUDE_CACHED_INCLUDE_ELEMENT)) { 317 318 String src = processCIncludeElement(attr.getValue("", CINCLUDE_INCLUDE_ELEMENT_SRC_ATTRIBUTE), 319 null, 320 null, 321 null, 322 null, 323 false, 324 this.cacheManager != null); 325 if (this.compiling) { 326 this.srcAttributes.addAttribute("", CINCLUDE_INCLUDE_ELEMENT_SRC_ATTRIBUTE, CINCLUDE_SRC_ELEMENT, "CDATA", src); 327 super.startTransformingElement(uri, 328 CINCLUDE_CACHED_INCLUDE_PLACEHOLDER_ELEMENT, 329 raw + "p", 330 this.srcAttributes); 331 this.srcAttributes.clear(); 332 } 333 } else { 334 super.startTransformingElement(uri, name, raw, attr); 335 } 336 } 337 338 public void endTransformingElement(String uri, String name, String raw) 339 throws ProcessingException, IOException , SAXException { 340 if (name.equals(CINCLUDE_INCLUDE_ELEMENT)) { 341 return; 343 344 } else if (name.equals(CINCLUDE_INCLUDEXML_ELEMENT) 345 && this.state == STATE_INCLUDE) { 346 348 this.state = STATE_OUTSIDE; 349 350 final String resource = (String )stack.pop(); 351 352 final boolean ignoreErrors = stack.pop().equals("true"); 353 354 if (getLogger().isDebugEnabled()) { 355 getLogger().debug("Processing includexml element: SRC=" + resource 356 + ", ignoreErrors=" + ignoreErrors 357 + ", configuration=" + this.configurationParameters 358 + ", parameters=" + this.resourceParameters); 359 } 360 Source source = null; 361 362 try { 363 source = SourceUtil.getSource(resource, 364 this.configurationParameters, 365 this.resourceParameters, 366 this.resolver); 367 368 XMLSerializer serializer = null; 369 XMLDeserializer deserializer = null; 370 try { 371 if ( ignoreErrors ) { 372 serializer = (XMLSerializer) this.manager.lookup(XMLSerializer.ROLE); 373 deserializer = (XMLDeserializer)this.manager.lookup(XMLDeserializer.ROLE); 374 SourceUtil.toSAX(source, serializer, this.configurationParameters, true); 375 deserializer.setConsumer( this.xmlConsumer ); 376 deserializer.deserialize( serializer.getSAXFragment() ); 377 } else { 378 SourceUtil.toSAX(source, this.xmlConsumer, this.configurationParameters, true); 379 } 380 } catch (ProcessingException pe) { 381 if (!ignoreErrors) throw pe; 382 } catch (ServiceException ignore) { 383 } finally { 384 this.manager.release( serializer ); 385 this.manager.release( deserializer ); 386 } 387 } catch (SourceException se) { 388 if (!ignoreErrors) throw SourceUtil.handle(se); 389 } catch (SAXException se) { 390 if (!ignoreErrors) throw se; 391 } catch (IOException ioe) { 392 if (!ignoreErrors) throw ioe; 393 } finally { 394 this.resolver.release(source); 395 } 396 397 this.ignoreWhitespaces = ((Boolean )stack.pop()).booleanValue(); 399 this.ignoreEmptyCharacters = ((Boolean )stack.pop()).booleanValue(); 400 401 } else if (name.equals(CINCLUDE_SRC_ELEMENT) 403 && this.state == STATE_INCLUDE) { 404 405 this.stack.push(this.endTextRecording()); 406 407 } else if (name.equals(CINCLUDE_PARAMETERS_ELEMENT) 408 && this.state == STATE_INCLUDE) { 409 this.resourceParameters = new SourceParameters(); 410 String label = (String )stack.pop(); 412 String key = null; 413 String value = null; 414 while (!label.equals("end")) { 415 if (label.equals("name")) key = (String )stack.pop(); 416 if (label.equals("value")) value = (String )stack.pop(); 417 if (key != null && value != null) { 418 this.resourceParameters.setParameter(key, value); 419 key = null; 420 value = null; 421 } 422 label = (String )stack.pop(); 423 } 424 425 } else if (name.equals(CINCLUDE_CONFIGURATION_ELEMENT) == true 426 && this.state == STATE_INCLUDE) { 427 this.configurationParameters = new Parameters(); 428 String label = (String )stack.pop(); 430 String key = null; 431 String value = null; 432 while (!label.equals("end")) { 433 if (label.equals("name")) key = (String )stack.pop(); 434 if (label.equals("value")) value = (String )stack.pop(); 435 if (key != null && value != null) { 436 this.configurationParameters.setParameter(key, value); 437 key = null; 438 value = null; 439 } 440 label = (String )stack.pop(); 441 } 442 443 } else if (name.equals(CINCLUDE_PARAMETER_ELEMENT) == true 444 && this.state == STATE_INCLUDE) { 445 446 } else if (name.equals(CINCLUDE_NAME_ELEMENT) == true 447 && this.state == STATE_INCLUDE) { 448 stack.push(this.endTextRecording()); 449 stack.push("name"); 450 451 } else if (name.equals(CINCLUDE_VALUE_ELEMENT) == true 453 && this.state == STATE_INCLUDE) { 454 stack.push(this.endSerializedXMLRecording()); 455 stack.push("value"); 456 457 } else if (name.equals(CINCLUDE_CACHED_INCLUDE_ELEMENT)) { 458 if (this.compiling) { 459 super.endTransformingElement(uri, 460 CINCLUDE_CACHED_INCLUDE_PLACEHOLDER_ELEMENT, 461 raw + "p"); 462 } 463 } else { 465 super.endTransformingElement(uri, name, raw); 466 } 467 } 468 469 protected String processCIncludeElement(String src, String element, 470 String select, String ns, String prefix, 471 boolean stripRoot, 472 boolean cache) 473 throws SAXException , IOException { 474 475 if (src == null) { 476 throw new SAXException ("Missing 'src' attribute on cinclude:include element"); 477 } 478 479 if (element == null) element=""; 480 if (select == null) select=""; 481 if (ns == null) ns=""; 482 if (prefix == null) prefix=""; 483 484 if (getLogger().isDebugEnabled()) { 485 getLogger().debug("Processing include element: SRC=" + src 486 + ", element=" + element 487 + ", select=" + select 488 + ", ns=" + ns 489 + ", prefix=" + prefix 490 + ", stripRoot=" + stripRoot 491 + ", caching=" + cache); 492 } 493 494 if (cache) { 495 src = this.cacheManager.load(src, this.cachingSession); 496 497 if (this.cachingSession.isParallel() && !this.cachingSession.isPreemptive()) { 498 if (!this.compiling) { 499 this.compiling = true; 500 this.startCompiledXMLRecording(); 501 } 502 } else { 503 this.cacheManager.stream(src, this.cachingSession, this.filter); 504 } 505 506 return src; 507 } 508 509 if (!"".equals(element)) { 511 if (!ns.equals("")) { 512 super.startPrefixMapping(prefix, ns); 513 } 514 super.startElement(ns, 515 element, 516 (!ns.equals("") && !prefix.equals("") ? prefix+":"+element : element), 517 XMLUtils.EMPTY_ATTRIBUTES); 518 } 519 520 Source source = null; 521 try { 522 source = this.resolver.resolveURI(src); 523 524 if (!"".equals(select)) { 525 526 527 DOMParser parser = null; 528 XPathProcessor processor = null; 529 530 try { 531 parser = (DOMParser)this.manager.lookup(DOMParser.ROLE); 532 processor = (XPathProcessor)this.manager.lookup(XPathProcessor.ROLE); 533 534 InputSource input = SourceUtil.getInputSource(source); 535 536 Document document = parser.parseDocument(input); 537 NodeList list = processor.selectNodeList(document, select); 538 int length = list.getLength(); 539 for (int i=0; i<length; i++) { 540 IncludeXMLConsumer.includeNode(list.item(i), 541 this.filter, 542 this.filter); 543 } 544 } finally { 545 this.manager.release(parser); 546 this.manager.release(processor); 547 } 548 } else { 549 String mimeType = null; 550 if (null != this.configurationParameters) { 551 mimeType = this.configurationParameters.getParameter("mime-type", mimeType); 552 } 553 if (this.compiling) { 554 SourceUtil.toSAX(source, mimeType, new IncludeXMLConsumer(this.contentHandler, this.lexicalHandler)); 555 } else { 556 this.filter.setIgnoreRootElement(stripRoot); 557 SourceUtil.toSAX(source, mimeType, this.filter); 558 } 559 } 560 561 } catch (SourceException se) { 562 throw new SAXException ("Exception in CIncludeTransformer",se); 563 } catch (IOException e) { 564 throw new SAXException ("CIncludeTransformer could not read resource", e); 565 } catch (ProcessingException e){ 566 throw new SAXException ("Exception in CIncludeTransformer",e); 567 } catch(ServiceException e) { 568 throw new SAXException (e); 569 } finally { 570 this.resolver.release(source); 571 } 572 573 if (!"".equals(element)) { 574 super.endElement(ns, element, (!ns.equals("") && !prefix.equals("") ? prefix+":"+element : element)); 575 if (!ns.equals("")) { 576 super.endPrefixMapping(prefix); 577 } 578 } 579 return src; 580 } 581 582 588 protected void startCompiledXMLRecording() 589 throws SAXException { 590 if (this.getLogger().isDebugEnabled()) { 591 this.getLogger().debug("BEGIN startCompiledXMLRecording"); 592 } 593 594 try { 595 this.recorder = (XMLSerializer)this.manager.lookup(XMLSerializer.ROLE); 596 597 this.addRecorder(recorder); 598 599 } catch (ServiceException ce) { 600 throw new SAXException ("Unable to lookup xml serializer for compiling xml.", ce); 601 } 602 if (this.getLogger().isDebugEnabled()) { 603 this.getLogger().debug("END startCompiledXMLRecording"); 604 } 605 } 606 607 611 protected Object endCompiledXMLRecording() 612 throws SAXException { 613 if (this.getLogger().isDebugEnabled()) { 614 this.getLogger().debug("BEGIN endCompiledXMLRecording"); 615 } 616 617 XMLSerializer recorder = (XMLSerializer)this.removeRecorder(); 618 Object text = recorder.getSAXFragment(); 619 620 if (this.getLogger().isDebugEnabled()) { 621 this.getLogger().debug("END endCompiledXMLRecording text="+text); 622 } 623 return text; 624 } 625 626 629 public void startDocument() throws SAXException { 630 this.filter = new MyFilter(this.xmlConsumer, 631 this); 632 super.startDocument(); 633 } 634 635 638 public void endDocument() throws SAXException { 639 if ( this.compiling ) { 640 Object compiledXML = this.endCompiledXMLRecording(); 641 XMLDeserializer deserializer = null; 642 try { 643 deserializer = (XMLDeserializer)this.manager.lookup(XMLDeserializer.ROLE); 644 deserializer.setConsumer(this.filter); 645 deserializer.deserialize(compiledXML); 646 } catch (ServiceException ce) { 647 throw new SAXException ("Unable to lookup xml deserializer.", ce); 648 } finally { 649 this.manager.release( deserializer ); 650 } 651 } 652 super.endDocument(); 653 } 654 655 658 public Serializable getKey() { 659 if (this.supportCaching 660 && null != this.cacheManager 661 && this.cachingSession.getExpires() > 0) { 662 return "1"; 663 } 664 return null; 665 } 666 667 670 public SourceValidity getValidity() { 671 if (this.supportCaching 672 && null != this.cacheManager 673 && this.cachingSession.getExpires() > 0 674 && !this.cachingSession.isPurging()) { 675 return this.cachingSession.getExpiresValidity(); 676 } 677 return null; 678 } 679 680 } 681 682 final class MyFilter extends IncludeXMLConsumer { 683 684 private final CIncludeTransformer transformer; 685 686 690 public MyFilter(XMLConsumer consumer, 691 CIncludeTransformer transformer) { 692 super(consumer); 693 this.transformer = transformer; 694 } 695 696 699 public void endElement(String uri, String local, String qName) 700 throws SAXException { 701 if (uri != null 702 && uri.equals(CIncludeTransformer.CINCLUDE_NAMESPACE_URI) 703 && local.equals(CIncludeTransformer.CINCLUDE_CACHED_INCLUDE_PLACEHOLDER_ELEMENT)) { 704 } else { 706 super.endElement(uri, local, qName); 707 } 708 } 709 710 713 public void startElement(String uri, 714 String local, 715 String qName, 716 Attributes attr) 717 throws SAXException { 718 if (uri != null 719 && uri.equals(CIncludeTransformer.CINCLUDE_NAMESPACE_URI) 720 && local.equals(CIncludeTransformer.CINCLUDE_CACHED_INCLUDE_PLACEHOLDER_ELEMENT)) { 721 try { 723 final String src = attr.getValue("",CIncludeTransformer.CINCLUDE_INCLUDE_ELEMENT_SRC_ATTRIBUTE); 724 this.transformer.cacheManager.stream(src, this.transformer.cachingSession, this); 725 } catch (IOException ioe) { 726 throw new SAXException ("IOException", ioe); 727 } 728 } else { 729 super.startElement(uri, local, qName, attr); 730 } 731 } 732 733 } 734 | Popular Tags |