Browse Source

Merged branch

https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ProcessingFeedback
into Trunk.

Changes on branch:
........
  r615153 | jeremias | 2008-01-25 10:07:21 +0100 (Fr, 25 Jan 2008) | 1 line
  
  Created temporary branch for processing feedback.
........
  r615155 | jeremias | 2008-01-25 10:11:59 +0100 (Fr, 25 Jan 2008) | 1 line
  
  Initial commit of what I've built already for those who prefer code to minimalistic design docs.
........
  r615278 | jeremias | 2008-01-25 18:25:00 +0100 (Fr, 25 Jan 2008) | 1 line
  
  EventProducer interfaces now operational.
........
  r615773 | jeremias | 2008-01-28 10:06:16 +0100 (Mo, 28 Jan 2008) | 1 line
  
  No casting in client code when creating EventProducer instances.
........
  r616242 | vhennebert | 2008-01-29 11:34:45 +0100 (Di, 29 Jan 2008) | 3 lines
  
  Trick to avoid hard-coding the class name of EventProducer in the source file.
  Feel free to revert if it's not ok.
........
  r616900 | jeremias | 2008-01-30 21:59:31 +0100 (Mi, 30 Jan 2008) | 1 line
  
  Generate event model XMLs in to the build directory: build/gensrc and build/test-gensrc (the latter is new and needs to be setup as source folder in your IDE!)
........
  r616907 | jeremias | 2008-01-30 22:12:59 +0100 (Mi, 30 Jan 2008) | 1 line
  
  Added an XMLResourceBundle that uses an XML file instead of a properties file to load the translations. The XML format is the same as for Cocoon's XMLResourceBundle.
........
  r617097 | vhennebert | 2008-01-31 11:53:21 +0100 (Do, 31 Jan 2008) | 2 lines
  
  Minor typo + slight improvement of Javadoc
........
  r617176 | jeremias | 2008-01-31 19:14:19 +0100 (Do, 31 Jan 2008) | 5 lines
  
  Renamed FopEvent to Event as suggested by Simon.
  EventProducerCollectorTask.java now reads the EventSeverity from a doclet tag.
  Added generation of EventProducer translations (including simple merging, no validation, yet)
  EventFormatter introduced (only basic functionality, yet).
  Added a simple EventListener implementation that uses EventFormatter to convert the events to human-readable, localized messages that are sent to the log via Commons Logging.
........
  r617362 | jeremias | 2008-02-01 08:18:07 +0100 (Fr, 01 Feb 2008) | 1 line
  
  Some remaining rename operations based on an earlier discussion.
........
  r617413 | jeremias | 2008-02-01 10:46:26 +0100 (Fr, 01 Feb 2008) | 2 lines
  
  Extracted formatting functionality into utility class AdvancedMessageFormat.java.
  AdvancedMessageFormat.java now supports conditional sub-groups (delimited by []).
........
  r618682 | jeremias | 2008-02-05 17:07:08 +0100 (Di, 05 Feb 2008) | 1 line
  
  Add support for special object formatters (where toString() isn't good enough). ATM, it's hard-coded but could later be hooked into dynamic discovery if we have multiple such formatters. The SAX Locator is the only example for now.
........
  r618686 | jeremias | 2008-02-05 17:12:56 +0100 (Di, 05 Feb 2008) | 3 lines
  
  Hooked most of FONode into the new event mechanism. The FOUserAgent provides a DefaultEventBroadcaster instance.
  If a producer method declares throwing an exception, the event is automatically marked FATAL and the dynamic proxy throws an exception right after notifying the listeners.
  The exceptions are created through the EventExceptionManager. It currently contains only one exception factory for ValidationException. If we need more such factories it's better to register them dynamically. Right now, they're hard-coded.
........
  r619313 | jeremias | 2008-02-07 10:14:15 +0100 (Do, 07 Feb 2008) | 1 line
  
  Make sure no events are now just silently swallowed because after upgrading a user doesn't know about the event system.
........
  r619314 | jeremias | 2008-02-07 10:14:46 +0100 (Do, 07 Feb 2008) | 1 line
  
  Log what translation file is being written.
........
  r619320 | jeremias | 2008-02-07 10:31:00 +0100 (Do, 07 Feb 2008) | 2 lines
  
  FObj hooked into the event system.
  Code reduction using a protected method on FONode to acquire a FOValidationEventProducer.
........
  r619359 | jeremias | 2008-02-07 11:59:19 +0100 (Do, 07 Feb 2008) | 2 lines
  
  Fop's QName now extends XGCommons' QName to initiate a transition.
  Hooked PropertyList into the event mechanism.
........
  r631252 | jeremias | 2008-02-26 16:24:33 +0100 (Di, 26 Feb 2008) | 1 line
  
  Removed superfluous warning.
........
  r631268 | jeremias | 2008-02-26 17:08:11 +0100 (Di, 26 Feb 2008) | 1 line
  
  Deprecated two methods which are a problem for localization. Also helps finding additional spots to switch over to the event mechanism.
........
  r633852 | jeremias | 2008-03-05 15:20:24 +0100 (Mi, 05 Mrz 2008) | 1 line
  
  Add severity to formatting parameters.
........
  r633855 | jeremias | 2008-03-05 15:21:57 +0100 (Mi, 05 Mrz 2008) | 4 lines
  
  Added support for additional field styles:
  {<fieldname>,if,<true-text>,<false-text>}
  {<fieldname>,equals,<test-string>,<true-text>,<false-text>}
........
  r633856 | jeremias | 2008-03-05 15:24:04 +0100 (Mi, 05 Mrz 2008) | 2 lines
  
  Javadocs and TODOs.
  EventListeners can change the event severity.
........
  r633857 | jeremias | 2008-03-05 15:27:08 +0100 (Mi, 05 Mrz 2008) | 4 lines
  
  Javadocs.
  Moved out event listener registration into a CompositeEventListener.
  Event broadcaster uses the events effective severity, not the initial value (for the case where listeners override the initial value).
  Set up a special EventBroadCaster in the FOUserAgent that filters events through a class (FOValidationEventListenerProxy) that adjusts the event severity for relaxed validation.
........
  r633858 | jeremias | 2008-03-05 15:32:07 +0100 (Mi, 05 Mrz 2008) | 2 lines
  
  Instead of always decentrally checking whether strict validation is enabled or not, this is now done in a special event listener. The event producer method caller simply indicates whether it can recover from the error condition and continue.
  Started switching to event production in table FOs.
........
  r634027 | jeremias | 2008-03-05 21:58:35 +0100 (Mi, 05 Mrz 2008) | 7 lines
  
  Moved AdvancedMessageFormat into its own package.
  AdvancedMessageFormat got the following added functionality:
  - Alternative conditional regions [ bla {field}] -> [ bla {field1}| even more bla {field2}]
  - Functions: functions get access to the parameters and they can produce an object that is then formatted ({#gatherContextInfo})
  - "if" and "equals" format moved to top-level classes and added by dynamic registration.
  EventFormatter now supports includes in the form {{includeName}} so you can include other entries from the resource bundle for better reuse.
  Some more events in table code.
........
  r634031 | jeremias | 2008-03-05 22:05:22 +0100 (Mi, 05 Mrz 2008) | 1 line
  
  SVN Props
........
  r634208 | jeremias | 2008-03-06 11:26:52 +0100 (Do, 06 Mrz 2008) | 2 lines
  
  Improved context gathering.
  Moved GatherContextInfoFunction to an inner class of FONode to reduce visibilities.
........
  r634209 | jeremias | 2008-03-06 11:28:14 +0100 (Do, 06 Mrz 2008) | 1 line
  
  Made FOPException localizable.
........
  r634280 | jeremias | 2008-03-06 15:38:30 +0100 (Do, 06 Mrz 2008) | 2 lines
  
  ExceptionFactory is now dynamically registered.
  More table warnings and errors switch to events.
........
  r634326 | jeremias | 2008-03-06 17:08:16 +0100 (Do, 06 Mrz 2008) | 1 line
  
  Remaining table FOs switched to events.
........
  r634328 | jeremias | 2008-03-06 17:09:21 +0100 (Do, 06 Mrz 2008) | 1 line
  
  Deprecated FOP's QName. Mixing with Commons' variant only produces problems.
........
  r634381 | jeremias | 2008-03-06 20:12:57 +0100 (Do, 06 Mrz 2008) | 2 lines
  
  Made the "invalidChild" event fully localizable by adding a "lookup" field for the optional rule to be displayed.
  And a few switches to the event system.
........
  r634692 | jeremias | 2008-03-07 15:31:43 +0100 (Fr, 07 Mrz 2008) | 1 line
  
  More FO tree stuff switched to events.
........
  r634712 | jeremias | 2008-03-07 16:19:21 +0100 (Fr, 07 Mrz 2008) | 1 line
  
  Avoid an NPE that says nothing (ex. could happen if the message template is wrong).
........
  r634738 | jeremias | 2008-03-07 17:38:21 +0100 (Fr, 07 Mrz 2008) | 2 lines
  
  Non-FO children were not properly run through validation by FOTreeBuilder.
  Unified the way that non-FO elements are validated. Some FOs were already fixed. I now fixed the rest, so foreign elements can occur everywhere.
........
  r637833 | jeremias | 2008-03-17 12:01:41 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Exception while cloning for RetrieveMarker to be handled by user as suggested by Andreas.
........
  r637835 | jeremias | 2008-03-17 12:03:31 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Throw a RuntimeException of no other Exception class is specified for an event as a fallback if someone just sets the event severity to FATAL.
........
  r637838 | jeremias | 2008-03-17 12:06:10 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Throw a meaningful exception when the property name is wrong. Otherwise, there will be an ArrayIndexOutOfBoundsException.
........
  r637859 | jeremias | 2008-03-17 13:35:26 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Throw a meaningful exception when the property name is wrong. Otherwise, there will be an ArrayIndexOutOfBoundsException.
........
  r637938 | jeremias | 2008-03-17 16:19:51 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Switched pagination package to events.
........
  r637947 | jeremias | 2008-03-17 16:45:16 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Removed unlocalizable validation helper methods.
........
  r637952 | jeremias | 2008-03-17 16:59:02 +0100 (Mo, 17 Mrz 2008) | 1 line
  
  Events on FOTreeBuilder.
........
  r638299 | jeremias | 2008-03-18 11:09:30 +0100 (Di, 18 Mrz 2008) | 2 lines
  
  Added support for java.util.text's ChoiceFormat to AdvancedMessageFormat.
  Reuse the regexes as constants.
........
  r638302 | jeremias | 2008-03-18 11:17:06 +0100 (Di, 18 Mrz 2008) | 1 line
  
  Events for inline-level layout managers.
........
  r638774 | jeremias | 2008-03-19 11:17:36 +0100 (Mi, 19 Mrz 2008) | 1 line
  
  Added DEBUG level.
........
  r638777 | jeremias | 2008-03-19 11:23:40 +0100 (Mi, 19 Mrz 2008) | 3 lines
  
  Generalized FOValidationEventListenerProxy into FOPEventListenerProxy, the main proxy for FOP's own event manipulation proxy. Done because of support for overflow="hidden" vs. overflow="error-if-overflow".
  Switched block-level layout managers to events.
  Some cleanup along the way.
........
  r639222 | jeremias | 2008-03-20 10:27:34 +0100 (Do, 20 Mrz 2008) | 2 lines
  
  Some initial work for event forwarding from Batik.
  Missing errors/exceptions converted to events in PageSequenceMaster.
........
  r639270 | jeremias | 2008-03-20 13:50:35 +0100 (Do, 20 Mrz 2008) | 1 line
  
  Removed DEBUG event severity again. Promoted constrained geometry adjustment event to INFO level as per discussion.
........
  r640395 | jeremias | 2008-03-24 13:39:13 +0100 (Mo, 24 Mrz 2008) | 3 lines
  
  Moved the creation of the fallback LoggingEventListener to FOUserAgent so event before the startDocument() SAX event arrive in the log.
  Dynamic discovery of event models. Renderers and extensions can register renderer-specific event models.
  Switched the most important parts of the renderers to events (maybe not everything is converted).
........
  r640397 | jeremias | 2008-03-24 13:43:04 +0100 (Mo, 24 Mrz 2008) | 1 line
  
  Remaining fixcrlfs. Xalan likes to mix CRLF and LF on Windows.
........
  r640398 | jeremias | 2008-03-24 13:43:54 +0100 (Mo, 24 Mrz 2008) | 1 line
  
  Ignore namespace declarations for property handling.
........
  r640463 | jeremias | 2008-03-24 17:59:52 +0100 (Mo, 24 Mrz 2008) | 2 lines
  
  Event in area package.
  Exposed getUserAgent() in Renderer interface (was already public in AbstractRenderer).
........
  r642972 | jeremias | 2008-03-31 14:18:39 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Code restructured a bit.
........
  r642975 | jeremias | 2008-03-31 14:24:07 +0200 (Mo, 31 Mrz 2008) | 2 lines
  
  Plugged fonts package into the event subsystem. Note: I did not follow the same pattern as for the rest as the font package is to be considered FOP-external, so I just added a manual adapter for the FontEventListener. This demonstrates how an external library can be integrated with the event system.
  Missing warning for unknown formatting objects added. Warning is not issued by the ElementMappingRegistry anymore but by FOTreeBuilder which has access to more context information.
........
  r642997 | jeremias | 2008-03-31 16:10:08 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Added an example to demonstrate how to write your own event listener and how to deal with the exceptions thrown in the process.
........
  r642998 | jeremias | 2008-03-31 16:13:40 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  Removed unused method. Event formatting should not be part of the Event class. Use EventFormatter.format(Event) instead.
........
  r643066 | jeremias | 2008-03-31 19:18:54 +0200 (Mo, 31 Mrz 2008) | 1 line
  
  First part of the event subsystem documentation (DRAFT).
........
  r643784 | jeremias | 2008-04-02 10:05:33 +0200 (Mi, 02 Apr 2008) | 1 line
  
  More documentation.
........
  r643785 | jeremias | 2008-04-02 10:06:38 +0200 (Mi, 02 Apr 2008) | 1 line
  
  Some nits.
........
  r643787 | jeremias | 2008-04-02 10:24:41 +0200 (Mi, 02 Apr 2008) | 1 line
  
  Completed javadocs
........
  r643824 | jeremias | 2008-04-02 12:00:30 +0200 (Mi, 02 Apr 2008) | 1 line
  
  Javadocs.
........
  r645847 | vhennebert | 2008-04-08 12:54:16 +0200 (Di, 08 Apr 2008) | 2 lines
  
  Minor typo fixes
........
  r645848 | vhennebert | 2008-04-08 12:58:30 +0200 (Di, 08 Apr 2008) | 2 lines
  
  Another small typo fix
........
  r647678 | jeremias | 2008-04-14 09:20:26 +0200 (Mo, 14 Apr 2008) | 1 line
  
  Renamed *EventProducer.Factory.create() to *EventProducer.Provider.get() to better reflect what the method does (instances may be cached and reused).
........


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@647742 13f79535-47bb-0310-9956-ffa450edef68
pull/37/head
Jeremias Maerki 16 years ago
parent
commit
ff38e91905
100 changed files with 5047 additions and 545 deletions
  1. 141
    27
      build.xml
  2. 227
    0
      examples/embedding/java/embedding/events/ExampleEvents.java
  3. 33
    0
      examples/embedding/java/embedding/events/missing-image.fo
  4. BIN
      lib/build/qdox-1.6.3.jar
  5. 201
    0
      lib/build/qdox.LICENSE.txt
  6. 28
    0
      src/codegen/java/org/apache/fop/tools/EventConventionException.java
  7. 183
    0
      src/codegen/java/org/apache/fop/tools/EventProducerCollector.java
  8. 200
    0
      src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java
  9. 55
    0
      src/codegen/java/org/apache/fop/tools/merge-translation.xsl
  10. 35
    0
      src/codegen/java/org/apache/fop/tools/model2translation.xsl
  11. 1
    0
      src/documentation/content/xdocs/site.xml
  12. 422
    0
      src/documentation/content/xdocs/trunk/events.xml
  13. 4
    0
      src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory
  14. 7
    0
      src/java/META-INF/services/org.apache.fop.events.model.EventModelFactory
  15. 1
    0
      src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$Function
  16. 1
    0
      src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$ObjectFormatter
  17. 6
    0
      src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$PartFactory
  18. 21
    0
      src/java/org/apache/fop/apps/FOPException.java
  19. 45
    0
      src/java/org/apache/fop/apps/FOUserAgent.java
  20. 91
    0
      src/java/org/apache/fop/area/AreaEventProducer.java
  21. 3
    2
      src/java/org/apache/fop/area/AreaTreeHandler.java
  22. 5
    5
      src/java/org/apache/fop/area/AreaTreeObject.java
  23. 1
    1
      src/java/org/apache/fop/area/AreaTreeParser.java
  24. 38
    39
      src/java/org/apache/fop/area/CachedRenderPagesModel.java
  25. 9
    7
      src/java/org/apache/fop/area/PageViewport.java
  26. 28
    17
      src/java/org/apache/fop/area/RenderPagesModel.java
  27. 69
    0
      src/java/org/apache/fop/events/CompositeEventListener.java
  28. 160
    0
      src/java/org/apache/fop/events/DefaultEventBroadcaster.java
  29. 150
    0
      src/java/org/apache/fop/events/Event.java
  30. 61
    0
      src/java/org/apache/fop/events/EventBroadcaster.java
  31. 84
    0
      src/java/org/apache/fop/events/EventExceptionManager.java
  32. 196
    0
      src/java/org/apache/fop/events/EventFormatter.java
  33. 101
    0
      src/java/org/apache/fop/events/EventFormatter.xml
  34. 23
    0
      src/java/org/apache/fop/events/EventFormatter_de.xml
  35. 37
    0
      src/java/org/apache/fop/events/EventListener.java
  36. 31
    0
      src/java/org/apache/fop/events/EventProducer.java
  37. 73
    0
      src/java/org/apache/fop/events/FOPEventListenerProxy.java
  38. 37
    0
      src/java/org/apache/fop/events/FOPEventModelFactory.java
  39. 92
    0
      src/java/org/apache/fop/events/LoggingEventListener.java
  40. 47
    0
      src/java/org/apache/fop/events/PropertyExceptionFactory.java
  41. 136
    0
      src/java/org/apache/fop/events/ResourceEventProducer.java
  42. 43
    0
      src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java
  43. 51
    0
      src/java/org/apache/fop/events/ValidationExceptionFactory.java
  44. 61
    0
      src/java/org/apache/fop/events/model/AbstractEventModelFactory.java
  45. 198
    0
      src/java/org/apache/fop/events/model/EventMethodModel.java
  46. 135
    0
      src/java/org/apache/fop/events/model/EventModel.java
  47. 33
    0
      src/java/org/apache/fop/events/model/EventModelFactory.java
  48. 140
    0
      src/java/org/apache/fop/events/model/EventModelParser.java
  49. 105
    0
      src/java/org/apache/fop/events/model/EventProducerModel.java
  50. 82
    0
      src/java/org/apache/fop/events/model/EventSeverity.java
  51. 2
    1
      src/java/org/apache/fop/fo/ElementMapping.java
  52. 1
    1
      src/java/org/apache/fop/fo/ElementMappingRegistry.java
  53. 1
    1
      src/java/org/apache/fop/fo/FOElementMapping.java
  54. 2
    0
      src/java/org/apache/fop/fo/FOEventHandler.java
  55. 126
    46
      src/java/org/apache/fop/fo/FONode.java
  56. 3
    6
      src/java/org/apache/fop/fo/FOText.java
  57. 40
    27
      src/java/org/apache/fop/fo/FOTreeBuilder.java
  58. 348
    0
      src/java/org/apache/fop/fo/FOValidationEventProducer.java
  59. 47
    30
      src/java/org/apache/fop/fo/FObj.java
  60. 30
    37
      src/java/org/apache/fop/fo/PropertyList.java
  61. 7
    1
      src/java/org/apache/fop/fo/expr/FromParentFunction.java
  62. 5
    0
      src/java/org/apache/fop/fo/expr/InheritedPropFunction.java
  63. 5
    0
      src/java/org/apache/fop/fo/expr/NearestSpecPropFunction.java
  64. 5
    4
      src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
  65. 7
    7
      src/java/org/apache/fop/fo/extensions/destination/Destination.java
  66. 11
    18
      src/java/org/apache/fop/fo/flow/AbstractListItemPart.java
  67. 3
    1
      src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java
  68. 11
    10
      src/java/org/apache/fop/fo/flow/BasicLink.java
  69. 16
    16
      src/java/org/apache/fop/fo/flow/BidiOverride.java
  70. 10
    8
      src/java/org/apache/fop/fo/flow/BlockContainer.java
  71. 5
    2
      src/java/org/apache/fop/fo/flow/Character.java
  72. 13
    5
      src/java/org/apache/fop/fo/flow/ExternalGraphic.java
  73. 5
    2
      src/java/org/apache/fop/fo/flow/Float.java
  74. 5
    3
      src/java/org/apache/fop/fo/flow/Footnote.java
  75. 3
    1
      src/java/org/apache/fop/fo/flow/FootnoteBody.java
  76. 3
    1
      src/java/org/apache/fop/fo/flow/InitialPropertySet.java
  77. 15
    18
      src/java/org/apache/fop/fo/flow/Inline.java
  78. 10
    8
      src/java/org/apache/fop/fo/flow/InlineContainer.java
  79. 20
    23
      src/java/org/apache/fop/fo/flow/InstreamForeignObject.java
  80. 10
    8
      src/java/org/apache/fop/fo/flow/ListBlock.java
  81. 17
    15
      src/java/org/apache/fop/fo/flow/ListItem.java
  82. 7
    6
      src/java/org/apache/fop/fo/flow/Marker.java
  83. 2
    1
      src/java/org/apache/fop/fo/flow/MultiCase.java
  84. 6
    3
      src/java/org/apache/fop/fo/flow/MultiProperties.java
  85. 5
    2
      src/java/org/apache/fop/fo/flow/MultiPropertySet.java
  86. 7
    4
      src/java/org/apache/fop/fo/flow/MultiSwitch.java
  87. 7
    4
      src/java/org/apache/fop/fo/flow/MultiToggle.java
  88. 3
    1
      src/java/org/apache/fop/fo/flow/PageNumber.java
  89. 14
    17
      src/java/org/apache/fop/fo/flow/RetrieveMarker.java
  90. 14
    11
      src/java/org/apache/fop/fo/flow/Wrapper.java
  91. 8
    4
      src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java
  92. 20
    19
      src/java/org/apache/fop/fo/flow/table/Table.java
  93. 25
    22
      src/java/org/apache/fop/fo/flow/table/TableAndCaption.java
  94. 11
    18
      src/java/org/apache/fop/fo/flow/table/TableBody.java
  95. 12
    9
      src/java/org/apache/fop/fo/flow/table/TableCaption.java
  96. 13
    15
      src/java/org/apache/fop/fo/flow/table/TableCell.java
  97. 3
    4
      src/java/org/apache/fop/fo/flow/table/TableCellContainer.java
  98. 14
    7
      src/java/org/apache/fop/fo/flow/table/TableColumn.java
  99. 159
    0
      src/java/org/apache/fop/fo/flow/table/TableEventProducer.java
  100. 0
    0
      src/java/org/apache/fop/fo/flow/table/TableFObj.java

+ 141
- 27
build.xml View File

@@ -118,13 +118,15 @@ list of possible build targets.
</fileset>
</path>

<path id="libs-run-classpath">
<fileset dir="${basedir}/lib">
<include name="*.jar"/>
</fileset>
<fileset dir="${optional.lib.dir}">
<path id="libs-build-tools-classpath">
<path refid="libs-build-classpath"/>
<fileset dir="${basedir}/lib/build">
<include name="*.jar"/>
</fileset>
</path>
<path id="libs-run-classpath">
<path refid="libs-build-classpath"/>
<fileset dir="${basedir}/build">
<include name="fop.jar"/>
<include name="fop-hyph.jar" />
@@ -362,7 +364,7 @@ list of possible build targets.
<!-- =================================================================== -->
<!-- Compiles the source directory -->
<!-- =================================================================== -->
<target name="compile-java" depends="init, codegen" description="Compiles the source code">
<target name="compile-java" depends="init, codegen">
<!-- create directories -->
<mkdir dir="${build.classes.dir}"/>
<javac destdir="${build.classes.dir}" fork="${javac.fork}" debug="${javac.debug}"
@@ -375,12 +377,118 @@ list of possible build targets.
<patternset refid="exclude-jai"/>
<classpath refid="libs-build-classpath"/>
</javac>

<mkdir dir="${build.sandbox-classes.dir}"/>
<javac destdir="${build.sandbox-classes.dir}" fork="${javac.fork}" debug="${javac.debug}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
source="${javac.source}" target="${javac.target}">
<src path="${src.sandbox.dir}"/>
<patternset includes="**/*.java"/>
<patternset refid="exclude-jai"/>
<classpath>
<path refid="libs-build-classpath"/>
<pathelement location="${build.classes.dir}"/>
</classpath>
</javac>
</target>

<target name="resourcegen" depends="compile-java">
<mkdir dir="${build.codegen-classes.dir}"/>
<javac destdir="${build.codegen-classes.dir}" fork="${javac.fork}" debug="${javac.debug}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
source="${javac.source}" target="${javac.target}">
<src path="${src.codegen.dir}/java"/>
<patternset includes="**/*.java"/>
<classpath>
<path refid="libs-build-tools-classpath"/>
<pathelement location="${build.classes.dir}"/>
</classpath>
</javac>
<copy todir="${build.codegen-classes.dir}">
<fileset dir="${src.codegen.dir}/java">
<include name="**/*.xsl"/>
</fileset>
</copy>
<taskdef name="eventResourceGenerator"
classname="org.apache.fop.tools.EventProducerCollectorTask">
<classpath>
<path refid="libs-build-tools-classpath"/>
<pathelement location="${build.classes.dir}"/>
<pathelement location="${build.codegen-classes.dir}"/>
</classpath>
</taskdef>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/events/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/events/EventFormatter.xml">
<fileset dir="${src.java.dir}">
<include name="**/*.java"/>
<exclude name="org/apache/fop/render/*/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/events/EventFormatter.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/afp/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/afp/AFPEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/afp/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/afp/AFPEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/bitmap/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/bitmap/BitmapRendererEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/bitmap/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/bitmap/BitmapRendererEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/pcl/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/pcl/PCLEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/pcl/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/pcl/PCLEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/pdf/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/pdf/PDFEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/pdf/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/pdf/PDFEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/ps/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/ps/PSEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/ps/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/ps/PSEventProducer.xml" tab="remove" tablength="2"/>
<eventResourceGenerator
modelfile="${build.gensrc.dir}/org/apache/fop/render/rtf/event-model.xml"
translationfile="${src.java.dir}/org/apache/fop/render/rtf/RTFEventProducer.xml">
<fileset dir="${src.java.dir}">
<include name="org/apache/fop/render/rtf/**/*.java"/>
</fileset>
</eventResourceGenerator>
<fixcrlf file="${src.java.dir}/org/apache/fop/render/rtf/RTFEventProducer.xml" tab="remove" tablength="2"/>
</target>
<target name="compile-copy-resources" depends="resourcegen">
<copy todir="${build.classes.dir}">
<fileset dir="${src.java.dir}">
<include name="META-INF/**"/>
<include name="**/*.icm"/>
<include name="**/*.xml"/>
<include name="**/*.LICENSE.txt"/>
</fileset>
<fileset dir="${build.gensrc.dir}">
<include name="**/*.xml"/>
</fileset>
</copy>
<mkdir dir="${build.viewer.resources.dir}"/>
<copy todir="${build.viewer.resources.dir}">
@@ -390,31 +498,22 @@ list of possible build targets.
<copy todir="${build.viewer.images.dir}">
<fileset dir="${src.viewer.images.dir}"/>
</copy>

<mkdir dir="${build.sandbox-classes.dir}"/>
<javac destdir="${build.sandbox-classes.dir}" fork="${javac.fork}" debug="${javac.debug}"
deprecation="${javac.deprecation}" optimize="${javac.optimize}"
source="${javac.source}" target="${javac.target}">
<src path="${src.sandbox.dir}"/>
<patternset includes="**/*.java"/>
<patternset refid="exclude-jai"/>
<classpath>
<path refid="libs-build-classpath"/>
<pathelement location="${build.classes.dir}"/>
</classpath>
</javac>
<!-- sandbox -->
<copy todir="${build.sandbox-classes.dir}">
<fileset dir="${src.sandbox.dir}">
<include name="META-INF/**"/>
</fileset>
</copy>
</target>

<target name="compile" depends="compile-java, compile-copy-resources" description="Compiles the source code"/>

<!-- =================================================================== -->
<!-- compiles hyphenation patterns -->
<!-- =================================================================== -->
<target name="compile-hyphenation" depends="compile-java">
<target name="compile-hyphenation" depends="compile">
<path id="hyph-classpath">
<path refid="libs-build-classpath"/>
<pathelement location="${build.classes.dir}"/>
@@ -452,13 +551,13 @@ list of possible build targets.
<!-- main FOP JARs -->
<!-- =================================================================== -->

<target name="uptodate-jar-main" depends="compile-java">
<target name="uptodate-jar-main" depends="compile">
<uptodate property="jar.main.uptodate" targetfile="${build.dir}/fop.jar">
<srcfiles dir= "${build.classes.dir}"/>
</uptodate>
</target>

<target name="jar-main" depends="compile-java,uptodate-jar-main" description="Generates the main jar file" unless="jar.main.uptodate">
<target name="jar-main" depends="compile,uptodate-jar-main" description="Generates the main jar file" unless="jar.main.uptodate">
<tstamp>
<format property="ts" pattern="yyyyMMdd-HHmmss-z"/>
</tstamp>
@@ -487,13 +586,13 @@ list of possible build targets.
</jar>
</target>

<target name="uptodate-jar-sandbox" depends="compile-java">
<target name="uptodate-jar-sandbox" depends="compile">
<uptodate property="jar.sandbox.uptodate" targetfile="${build.dir}/fop-sandbox.jar">
<srcfiles dir= "${build.sandbox-classes.dir}"/>
</uptodate>
</target>

<target name="jar-sandbox" depends="compile-java,uptodate-jar-sandbox" description="Generates the sandbox jar file" unless="jar.sandbox.uptodate">
<target name="jar-sandbox" depends="compile,uptodate-jar-sandbox" description="Generates the sandbox jar file" unless="jar.sandbox.uptodate">
<tstamp>
<format property="ts" pattern="yyyyMMdd-HHmmss-z"/>
</tstamp>
@@ -608,14 +707,14 @@ list of possible build targets.
<include name="xmlgraphics-commons*.jar"/>
</fileset>
<target name="uptodate-transcoder-pkg" depends="compile-java">
<target name="uptodate-transcoder-pkg" depends="compile">
<uptodate property="transcoder.pkg.uptodate" targetfile="${build.dir}/fop-transcoder.jar">
<srcfiles refid="transcoder-classes-files"/>
<srcfiles refid="transcoder-lib-files"/>
</uptodate>
</target>

<target name="transcoder-pkg" depends="uptodate-transcoder-pkg, compile-java" description="Generates the jar for the transcoder package for Batik" unless="transcoder.pkg.uptodate">
<target name="transcoder-pkg" depends="uptodate-transcoder-pkg, compile" description="Generates the jar for the transcoder package for Batik" unless="transcoder.pkg.uptodate">
<echo message="Creating the jar file ${build.dir}/fop-transcoder.jar"/>

<property name="fop-transcoder.name" value="FOP Transcoder Package"/>
@@ -693,6 +792,7 @@ list of possible build targets.
</target>
<target name="junit-compile" depends="package, transcoder-pkg, junit-with-xmlunit, junit-without-xmlunit" description="Runs FOP's JUnit tests" if="junit.present">
<mkdir dir="${build.dir}/test-classes"/>
<mkdir dir="${build.dir}/test-gensrc"/>
<mkdir dir="${junit.reports.dir}"/>
<javac destdir="${build.dir}/test-classes" fork="${javac.fork}"
debug="${javac.debug}" deprecation="${javac.deprecation}"
@@ -707,6 +807,20 @@ list of possible build targets.
</fileset>
</classpath>
</javac>
<eventResourceGenerator modelfile="${build.dir}/test-gensrc/org/apache/fop/events/test-event-model.xml">
<fileset dir="${basedir}/test/java">
<include name="**/*.java"/>
</fileset>
</eventResourceGenerator>
<copy todir="${build.dir}/test-classes">
<fileset dir="${basedir}/test/java">
<include name="META-INF/**"/>
<include name="**/*.xml"/>
</fileset>
<fileset dir="${build.dir}/test-gensrc">
<include name="**/*.xml"/>
</fileset>
</copy>
</target>

<target name="junit-transcoder" depends="junit-compile" description="Runs FOP's JUnit transcoder tests" if="junit.present">

+ 227
- 0
examples/embedding/java/embedding/events/ExampleEvents.java View File

@@ -0,0 +1,227 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */
package embedding.events;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

import org.apache.commons.io.IOUtils;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.events.Event;
import org.apache.fop.events.EventFormatter;
import org.apache.fop.events.EventListener;
import org.apache.fop.events.model.EventSeverity;

/**
* This class demonstrates how to register an event listener with FOP so you can customize
* FOP's error behaviour.
*/
public class ExampleEvents {

// configure fopFactory as desired
private FopFactory fopFactory = FopFactory.newInstance();

/**
* Converts an FO file to a PDF file using FOP
* @param fo the FO file
* @param pdf the target PDF file
* @throws IOException In case of an I/O problem
* @throws FOPException In case of a FOP problem
* @throws TransformerException In case of a problem with XSLT
*/
public void convertFO2PDF(URL fo, File pdf)
throws IOException, FOPException, TransformerException {
OutputStream out = null;
try {
//Create the user agent for this processing run
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
//Adding a simple logging listener that writes to stdout and stderr
foUserAgent.getEventBroadcaster().addEventListener(new SysOutEventListener());
// Add your own event listener
foUserAgent.getEventBroadcaster().addEventListener(new MyEventListener());
// configure foUserAgent further as desired
// Setup output stream. Note: Using BufferedOutputStream
// for performance reasons (helpful with FileOutputStreams).
out = new FileOutputStream(pdf);
out = new BufferedOutputStream(out);

// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);

// Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
// Setup input stream
Source src = new StreamSource(fo.toExternalForm());

// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);

} finally {
IOUtils.closeQuietly(out);
}
}

private static class MyEventListener implements EventListener {

public void processEvent(Event event) {
if ("org.apache.fop.events.ResourceEventProducer.imageNotFound"
.equals(event.getEventID())) {
//Get the FileNotFoundException that's part of the event's parameters
FileNotFoundException fnfe = (FileNotFoundException)event.getParam("fnfe");

System.out.println("---=== imageNotFound Event for " + event.getParam("uri")
+ "!!! ===---");
//Stop processing when an image could not be found. Otherwise, FOP would just
//continue without the image!
System.out.println("Throwing a RuntimeException...");
throw new RuntimeException(EventFormatter.format(event), fnfe);
} else {
//ignore all other events
}
}
}
/** A simple event listener that writes the events to stdout and sterr. */
private static class SysOutEventListener implements EventListener {

/** {@inheritDoc} */
public void processEvent(Event event) {
String msg = EventFormatter.format(event);
EventSeverity severity = event.getSeverity();
if (severity == EventSeverity.INFO) {
System.out.println("[INFO ] " + msg);
} else if (severity == EventSeverity.WARN) {
System.out.println("[WARN ] " + msg);
} else if (severity == EventSeverity.ERROR) {
System.err.println("[ERROR] " + msg);
} else if (severity == EventSeverity.FATAL) {
System.err.println("[FATAL] " + msg);
} else {
assert false;
}
}
}

/**
* This method extracts the original exception from some exception. The exception
* might be nested multiple levels deep.
* @param t the Throwable to inspect
* @return the original Throwable or the method parameter t if there are no nested Throwables.
*/
private static Throwable getOriginalThrowable(Throwable t) {
if (t instanceof SAXException) {
SAXException saxe = (SAXException)t;
if (saxe.getException() != null) {
return getOriginalThrowable(saxe.getException());
} else {
return saxe;
}
} else {
if (t.getCause() != null) {
return getOriginalThrowable(t.getCause());
} else {
return t;
}
}
}

/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleEvents\n");
System.out.println("Preparing...");
//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();

//Setup input and output files
URL fo = ExampleEvents.class.getResource("missing-image.fo");
File pdffile = new File(outDir, "out.pdf");

System.out.println("Input: XSL-FO (" + fo.toExternalForm() + ")");
System.out.println("Output: PDF (" + pdffile + ")");
System.out.println();
System.out.println("Transforming...");
ExampleEvents app = new ExampleEvents();
try {
app.convertFO2PDF(fo, pdffile);
} catch (TransformerException te) {
//Note: We don't get the original exception here!
//FOP needs to embed the exception in a SAXException and the TraX transformer
//again wraps the SAXException in a TransformerException. Even our own
//RuntimeException just wraps the original FileNotFoundException.
//So we need to unpack to get the original exception (about three layers deep).
Throwable originalThrowable = getOriginalThrowable(te);
originalThrowable.printStackTrace(System.err);
System.out.println("Aborted!");
System.exit(-1);
}
System.out.println("Success!");
} catch (Exception e) {
//Some other error (shouldn't happen in this example)
e.printStackTrace(System.err);
System.exit(-1);
}
}

}

+ 33
- 0
examples/embedding/java/embedding/events/missing-image.fo View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4" page-height="29.7cm" page-width="21cm" margin="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:flow flow-name="xsl-region-body">
<fo:block>
The following image is not available:
<fo:external-graphic src="my-missing-image.png"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>

BIN
lib/build/qdox-1.6.3.jar View File


+ 201
- 0
lib/build/qdox.LICENSE.txt View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

+ 28
- 0
src/codegen/java/org/apache/fop/tools/EventConventionException.java View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.tools;

public class EventConventionException extends Exception {

public EventConventionException(String message) {
super(message);
}
}

+ 183
- 0
src/codegen/java/org/apache/fop/tools/EventProducerCollector.java View File

@@ -0,0 +1,183 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.tools;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;

import org.apache.fop.events.EventProducer;
import org.apache.fop.events.model.EventMethodModel;
import org.apache.fop.events.model.EventModel;
import org.apache.fop.events.model.EventProducerModel;
import org.apache.fop.events.model.EventSeverity;

import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.DefaultDocletTagFactory;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.DocletTagFactory;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;

/**
* Finds EventProducer interfaces and builds the event model for them.
*/
public class EventProducerCollector {

private static final String CLASSNAME_EVENT_PRODUCER = EventProducer.class.getName();
private static final Map PRIMITIVE_MAP;
static {
Map m = new java.util.HashMap();
m.put("boolean", Boolean.class);
m.put("byte", Byte.class);
m.put("char", Character.class);
m.put("short", Short.class);
m.put("int", Integer.class);
m.put("long", Long.class);
m.put("float", Float.class);
m.put("double", Double.class);
PRIMITIVE_MAP = Collections.unmodifiableMap(m);
}
private DocletTagFactory tagFactory;
private EventModel model = new EventModel();

public EventProducerCollector() {
this.tagFactory = createDocletTagFactory();
}

protected DocletTagFactory createDocletTagFactory() {
return new DefaultDocletTagFactory();
}

public void scanFile(File src, String filename)
throws IOException, EventConventionException, ClassNotFoundException {
JavaDocBuilder builder = new JavaDocBuilder(this.tagFactory);
builder.addSource(src);
JavaClass[] classes = builder.getClasses();
for (int i = 0, c = classes.length; i < c; i++) {
JavaClass clazz = classes[i];
if (clazz.isInterface() && implementsInterface(clazz, CLASSNAME_EVENT_PRODUCER)) {
processEventProducerInterface(clazz, filename);
}
}
}

private boolean implementsInterface(JavaClass clazz, String intf) {
JavaClass[] classes = clazz.getImplementedInterfaces();
for (int i = 0, c = classes.length; i < c; i++) {
JavaClass cl = classes[i];
if (cl.getFullyQualifiedName().equals(intf)) {
return true;
}
}
return false;
}

/**
* Processes an EventProducer interface and creates an EventProducerModel from it.
* @param clazz the EventProducer interface
* @param javaFilename the filename of the Java source of the interface
* @throws EventConventionException if the event producer conventions are violated
* @throws ClassNotFoundException if a required class cannot be found
*/
protected void processEventProducerInterface(JavaClass clazz, String javaFilename)
throws EventConventionException, ClassNotFoundException {
EventProducerModel prodMeta = new EventProducerModel(clazz.getFullyQualifiedName());
JavaMethod[] methods = clazz.getMethods(true);
for (int i = 0, c = methods.length; i < c; i++) {
JavaMethod method = methods[i];
EventMethodModel methodMeta = createMethodModel(method);
prodMeta.addMethod(methodMeta);
}
this.model.addProducer(prodMeta);
}

private EventMethodModel createMethodModel(JavaMethod method)
throws EventConventionException, ClassNotFoundException {
JavaClass clazz = method.getParentClass();
//Check EventProducer conventions
if (!method.getReturns().isVoid()) {
throw new EventConventionException("All methods of interface "
+ clazz.getFullyQualifiedName() + " must have return type 'void'!");
}
String methodSig = clazz.getFullyQualifiedName() + "." + method.getCallSignature();
JavaParameter[] params = method.getParameters();
if (params.length < 1) {
throw new EventConventionException("The method " + methodSig
+ " must have at least one parameter: 'Object source'!");
}
Type firstType = params[0].getType();
if (firstType.isPrimitive() || !"source".equals(params[0].getName())) {
throw new EventConventionException("The first parameter of the method " + methodSig
+ " must be: 'Object source'!");
}
//build method model
DocletTag tag = method.getTagByName("event.severity");
EventSeverity severity;
if (tag != null) {
severity = EventSeverity.valueOf(tag.getValue());
} else {
severity = EventSeverity.INFO;
}
EventMethodModel methodMeta = new EventMethodModel(
method.getName(), severity);
if (params.length > 1) {
for (int j = 1, cj = params.length; j < cj; j++) {
JavaParameter p = params[j];
Class type;
JavaClass pClass = p.getType().getJavaClass();
if (p.getType().isPrimitive()) {
type = (Class)PRIMITIVE_MAP.get(pClass.getName());
if (type == null) {
throw new UnsupportedOperationException(
"Primitive datatype not supported: " + pClass.getName());
}
} else {
String className = pClass.getFullyQualifiedName();
type = Class.forName(className);
}
methodMeta.addParameter(type, p.getName());
}
}
Type[] exceptions = method.getExceptions();
if (exceptions != null && exceptions.length > 0) {
//We only use the first declared exception because that is always thrown
JavaClass cl = exceptions[0].getJavaClass();
methodMeta.setExceptionClass(cl.getFullyQualifiedName());
methodMeta.setSeverity(EventSeverity.FATAL); //In case it's not set in the comments
}
return methodMeta;
}

public EventModel getModel() {
return this.model;
}
public void saveModelToXML(File modelFile) throws IOException {
getModel().saveToXML(modelFile);
}
}

+ 200
- 0
src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java View File

@@ -0,0 +1,200 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.tools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Node;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.selectors.FilenameSelector;

public class EventProducerCollectorTask extends Task {

private List filesets = new java.util.ArrayList();
private File modelFile;
private File translationFile;
/** {@inheritDoc} */
public void execute() throws BuildException {
try {
EventProducerCollector collector = new EventProducerCollector();
processFileSets(collector);
getModelFile().getParentFile().mkdirs();
collector.saveModelToXML(getModelFile());
log("Event model written to " + getModelFile());
if (getTranslationFile() != null) {
updateTranslationFile();
}
} catch (ClassNotFoundException e) {
throw new BuildException(e);
} catch (EventConventionException ece) {
throw new BuildException(ece);
} catch (IOException ioe) {
throw new BuildException(ioe);
}
}
private static final String MODEL2TRANSLATION = "model2translation.xsl";
private static final String MERGETRANSLATION = "merge-translation.xsl";
protected void updateTranslationFile() throws IOException {
try {
boolean resultExists = getTranslationFile().exists();
SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
//Generate fresh generated translation file as template
Source src = new StreamSource(getModelFile());
StreamSource xslt1 = new StreamSource(
getClass().getResourceAsStream(MODEL2TRANSLATION));
if (xslt1.getInputStream() == null) {
throw new FileNotFoundException(MODEL2TRANSLATION + " not found");
}
DOMResult domres = new DOMResult();
Transformer transformer = tFactory.newTransformer(xslt1);
transformer.transform(src, domres);
final Node generated = domres.getNode();
Node sourceDocument;
if (resultExists) {
//Load existing translation file into memory (because we overwrite it later)
src = new StreamSource(getTranslationFile());
domres = new DOMResult();
transformer = tFactory.newTransformer();
transformer.transform(src, domres);
sourceDocument = domres.getNode();
} else {
//Simply use generated as source document
sourceDocument = generated;
}

//Generate translation file (with potentially new translations)
src = new DOMSource(sourceDocument);
Result res = new StreamResult(getTranslationFile());
StreamSource xslt2 = new StreamSource(
getClass().getResourceAsStream(MERGETRANSLATION));
if (xslt2.getInputStream() == null) {
throw new FileNotFoundException(MERGETRANSLATION + " not found");
}
transformer = tFactory.newTransformer(xslt2);
transformer.setURIResolver(new URIResolver() {
public Source resolve(String href, String base) throws TransformerException {
if ("my:dom".equals(href)) {
return new DOMSource(generated);
}
return null;
}
});
if (resultExists) {
transformer.setParameter("generated-url", "my:dom");
}
transformer.transform(src, res);
if (resultExists) {
log("Translation file updated: " + getTranslationFile());
} else {
log("Translation file generated: " + getTranslationFile());
}
} catch (TransformerException te) {
throw new IOException(te.getMessage());
}
}

protected void processFileSets(EventProducerCollector collector)
throws IOException, EventConventionException, ClassNotFoundException {
Iterator iter = filesets.iterator();
while (iter.hasNext()) {
FileSet fs = (FileSet)iter.next();
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
String[] srcFiles = ds.getIncludedFiles();
File directory = fs.getDir(getProject());
for (int i = 0, c = srcFiles.length; i < c; i++) {
String filename = srcFiles[i];
File src = new File(directory, filename);
collector.scanFile(src, filename);
}
}
}

public void addFileset(FileSet set) {
filesets.add(set);
}
public void setModelFile(File f) {
this.modelFile = f;
}
public File getModelFile() {
return this.modelFile;
}
public void setTranslationFile(File f) {
this.translationFile = f;
}
public File getTranslationFile() {
return this.translationFile;
}
public static void main(String[] args) {
try {
Project project = new Project();

EventProducerCollectorTask generator = new EventProducerCollectorTask();
generator.setProject(project);
project.setName("Test");
FileSet fileset = new FileSet();
fileset.setDir(new File("test/java"));
FilenameSelector selector = new FilenameSelector();
selector.setName("**/*.java");
fileset.add(selector);
generator.addFileset(fileset);
File targetDir = new File("build/codegen1");
targetDir.mkdirs();
generator.setModelFile(new File("D:/out.xml"));
generator.setTranslationFile(new File("D:/out1.xml"));
generator.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
}

+ 55
- 0
src/codegen/java/org/apache/fop/tools/merge-translation.xsl View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml" encoding="UTF-8"/>

<xsl:param name="generated-url" select="''"/>
<xsl:template match="catalogue">
<catalogue>
<xsl:attribute name="xml:lang"><xsl:value-of select="@xml:lang"/></xsl:attribute>
<xsl:apply-templates/>
<xsl:if test="$generated-url != ''">
<xsl:variable name="generated" select="document($generated-url)"/>
<xsl:call-template name="add-new-messages">
<xsl:with-param name="existing" select="."/>
<xsl:with-param name="new" select="$generated/catalogue"/>
</xsl:call-template>
</xsl:if>
</catalogue>
</xsl:template>
<xsl:template name="add-new-messages">
<xsl:param name="existing"/>
<xsl:param name="new"/>
<xsl:for-each select="$new/message">
<xsl:variable name="k" select="@key"/>
<xsl:if test="not(boolean($existing/message[@key = $k]))">
<xsl:apply-templates select="."></xsl:apply-templates>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>

+ 35
- 0
src/codegen/java/org/apache/fop/tools/model2translation.xsl View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes" method="xml" encoding="UTF-8"/>

<xsl:template match="event-model">
<catalogue>
<xsl:attribute name="xml:lang">en</xsl:attribute>
<xsl:apply-templates select="//method"></xsl:apply-templates>
</catalogue>
</xsl:template>
<xsl:template match="method">
<message>
<xsl:attribute name="key"><xsl:value-of select="../@name"/>.<xsl:value-of select="@name"/></xsl:attribute>
</message>
</xsl:template>
</xsl:stylesheet>

+ 1
- 0
src/documentation/content/xdocs/site.xml View File

@@ -155,6 +155,7 @@
<fonts label="Fonts" href="fonts.html"/>
<hyphenation label="Hyphenation" href="hyphenation.html"/>
<extensions label="Extensions" href="extensions.html"/>
<events label="Events" href="events.html"/>
</features>
</trunk>

+ 422
- 0
src/documentation/content/xdocs/trunk/events.xml View File

@@ -0,0 +1,422 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "http://forrest.apache.org/dtd/document-v20.dtd">
<document>
<header>
<title>Events/Processing Feedback</title>
<version>$Revision: 634267 $</version>
</header>
<body>
<section id="introduction">
<title>Introduction</title>
<p>
In versions until 0.20.5, FOP used
<a href="http://excalibur.apache.org/framework/index.html">Avalon-style Logging</a> where
it was possible to supply a logger per processing run. During the redesign
the logging infrastructure was switched over to
<a href="http://commons.apache.org/logging/">Commons Logging</a> which is (like Log4J or
java.util.logging) a "static" logging framework (the logger is accessed through static
variables). This made it very difficult in a multi-threaded system to retrieve information
for a single processing run.
</p>
<p>
With FOP's event subsystem, we'd like to close this gap again and even go further. The
first point is to realize that we have two kinds of "logging". Firstly, we have the logging
infrastructure for the (FOP) developer who needs to be able to enable finer log messages
for certain parts of FOP to track down a certain problem. Secondly, we have the user who
would like to be informed about missing images, overflowing lines or substituted fonts.
These messages (or events) are targeted at less technical people and may ideally be
localized (translated). Furthermore, tool and solution builders would like to integrate
FOP into their own solutions. For example, an FO editor should be able to point the user
to the right place where a particular problem occurred while developing a document template.
Finally, some integrators would like to abort processing if a resource (an image or a font)
has not been found, while others would simply continue. The event system allows to
react on these events.
</p>
<p>
On this page, we won't discuss logging as such. We will show how the event subsystem can
be used for various tasks. We'll first look at the event subsystem from the consumer side.
Finally, the production of events inside FOP will be discussed (this is mostly interesting
for FOP developers only).
</p>
</section>
<section id="consumer">
<title>The consumer side</title>
<p>
The event subsystem is located in the <code>org.apache.fop.events</code> package and its
base is the <code>Event</code> class. An instance is created for each event and is sent
to a set of <code>EventListener</code> instances by the <code>EventBroadcaster</code>.
An <code>Event</code> contains:
</p>
<ul>
<li>an event ID,</li>
<li>a source object (which generated the event),</li>
<li>a severity level (Info, Warning, Error and Fatal Error) and</li>
<li>a map of named parameters.</li>
</ul>
<p>
The <code>EventFormatter</code> class can be used to translate the events into
human-readable, localized messages.
</p>
<p>
A full example of what is shown here can be found in the
<code>examples/embedding/java/embedding/events</code> directory in the FOP distribution.
The example can also be accessed
<a href="http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/examples/embedding/java/embedding/events/">via the web</a>.
</p>
<section id="write-listener">
<title>Writing an EventListener</title>
<p>
The following code sample shows a very simple EventListener. It basically just sends
all events to System.out (stdout) or System.err (stderr) depending on the event severity.
</p>
<source><![CDATA[import org.apache.fop.events.Event;
import org.apache.fop.events.EventFormatter;
import org.apache.fop.events.EventListener;
import org.apache.fop.events.model.EventSeverity;

/** A simple event listener that writes the events to stdout and stderr. */
public class SysOutEventListener implements EventListener {

/** {@inheritDoc} */
public void processEvent(Event event) {
String msg = EventFormatter.format(event);
EventSeverity severity = event.getSeverity();
if (severity == EventSeverity.INFO) {
System.out.println("[INFO ] " + msg);
} else if (severity == EventSeverity.WARN) {
System.out.println("[WARN ] " + msg);
} else if (severity == EventSeverity.ERROR) {
System.err.println("[ERROR] " + msg);
} else if (severity == EventSeverity.FATAL) {
System.err.println("[FATAL] " + msg);
} else {
assert false;
}
}
}]]></source>
<p>
You can see that for every event the method <code>processEvent</code> of the
<code>EventListener</code> will be called. Inside this method you can do whatever
processing you would like including throwing a <code>RuntimeException</code>, if you want
to abort the current processing run.
</p>
<p>
The code above also shows how you can turn an event into a human-readable, localized
message that can be presented to a user. The <code>EventFormatter</code> class does
this for you. It provides additional methods if you'd like to explicitly specify
the locale.
</p>
<p>
It is possible to gather all events for a whole processing run so they can be
evaluated afterwards. However, care should be taken about memory consumption since
the events provide references to objects inside FOP which may themselves have
references to other objects. So holding on to these objects may mean that whole
object trees cannot be released!
</p>
</section>
<section id="add-listener">
<title>Adding an EventListener</title>
<p>
To register the event listener with FOP, get the <code>EventBroadcaster</code> which
is associated with the user agent (<code>FOUserAgent</code>) and add it there:
</p>
<source><![CDATA[FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
foUserAgent.getEventBroadcaster().addEventListener(new SysOutEventListener());]]></source>
<p>
Please note that this is done separately for each processing run, i.e. for each
new user agent.
</p>
</section>
<section id="listener-example1">
<title>An additional listener example</title>
<p>
Here's an additional example of an event listener:
</p>
<p>
By default, FOP continues processing even if an image wasn't found. If you have
more strict requirements and want FOP to stop if an image is not available, you can
do something like the following:
</p>
<source><![CDATA[public class MyEventListener implements EventListener {

public void processEvent(Event event) {
if ("org.apache.fop.events.ResourceEventProducer.imageNotFound"
.equals(event.getEventID())) {
//Get the FileNotFoundException that's part of the event's parameters
FileNotFoundException fnfe = (FileNotFoundException)event.getParam("fnfe");

throw new RuntimeException(EventFormatter.format(event), fnfe);
} else {
//ignore all other events (or do something of your choice)
}
}
}]]></source>
<p>
This throws a <code>RuntimeException</code> with the <code>FileNotFoundException</code>
as the cause. Further processing effectively stops in FOP. You can catch the exception
in your code and react as you see necessary.
</p>
</section>
</section>
<section id="producer">
<title>The producer side (for FOP developers)</title>
<p>
This section is primarily for FOP and FOP plug-in developers. It describes how to use
the event subsystem for producing events.
</p>
<note>
The event package has been designed in order to be theoretically useful for use cases
outside FOP. If you think this is interesting independently from FOP, please talk to
<a href="mailto:fop-dev@xmlgraphics.apache.org">us</a>.
</note>
<section id="basic-event-production">
<title>Producing and sending an event</title>
<p>
The basics are very simple. Just instantiate an <code>Event</code> object and fill
it with the necessary parameters. Then pass it to the <code>EventBroadcaster</code>
which distributes the events to the interested listeneners. Here's a code example:
</p>
<source><![CDATA[Event ev = new Event(this, "complain", EventSeverity.WARN,
Event.paramsBuilder()
.param("reason", "I'm tired")
.param("blah", new Integer(23))
.build());
EventBroadcaster broadcaster = [get it from somewhere];
broadcaster.broadcastEvent(ev);
]]></source>
<p>
The <code>Event.paramsBuilder()</code> is a
<a href="http://en.wikipedia.org/wiki/Fluent_interface">fluent interface</a>
to help with the build-up of the parameters. You could just as well instantiate a
<code>Map</code> (<code>Map&lt;String, Object&gt;</code>) and fill it with values.
</p>
</section>
<section id="event-producer">
<title>The EventProducer interface</title>
<p>
To simplify event production, the event subsystem provides the <code>EventProducer</code>
interface. You can create interfaces which extend <code>EventProducer</code>. These
interfaces will contain one method per event to be generated. By contract, each event
method must have as its first parameter a parameter named "source" (Type Object) which
indicates the object that generated the event. After that come an arbitrary number of
parameters of any type as needed by the event.
</p>
<p>
The event producer interface does not need to have any implementation. The implementation
is produced at runtime by a dynamic proxy created by <code>DefaultEventBroadcaster</code>.
The dynamic proxy creates <code>Event</code> instances for each method call against
the event producer interface. Each parameter (except "source") is added to the event's
parameter map.
</p>
<p>
To simplify the code needed to get an instance of the event producer interface it is
suggested to create a public inner provider class inside the interface.
</p>
<p>
Here's an example of such an event producer interface:
</p>
<source><![CDATA[public interface MyEventProducer extends EventProducer {

public class Provider {
public static MyEventProducer get(EventBroadcaster broadcaster) {
return (MyEventProducer)broadcaster.getEventProducerFor(MyEventProducer.class);
}
}

/**
* Complain about something.
* @param source the event source
* @param reason the reason for the complaint
* @param blah the complaint
* @event.severity WARN
*/
void complain(Object source, String reason, int blah);
}]]></source>
<p>
To produce the same event as in the first example above, you'd use the following code:
</p>
<source><![CDATA[EventBroadcaster broadcaster = [get it from somewhere];
TestEventProducer producer = TestEventProducer.Provider.get(broadcaster);
producer.complain(this, "I'm tired", 23);]]></source>
</section>
<section id="event-model">
<title>The event model</title>
<p>
Inside an invocation handler for a dynamic proxy, there's no information about
the names of each parameter. The JVM doesn't provide it. The only thing you know is
the interface and method name. In order to properly fill the <code>Event</code>'s
parameter map we need to know the parameter names. These are retrieved from an
event object model. This is found in the <code>org.apache.fop.events.model</code>
package. The data for the object model is retrieved from an XML representation of the
event model that is loaded as a resource. The XML representation is generated using an
Ant task at build time (<code>ant resourcegen</code>). The Ant task (found in
<code>src/codegen/java/org/apache/fop/tools/EventProducerCollectorTask.java</code>)
scans FOP's sources for descendants of the <code>EventProducer</code> interface and
uses <a href="http://qdox.codehaus.org/">QDox</a> to parse these interfaces.
</p>
<p>
Primarily, the QDox-based collector task records the parameters' names and types.
Furthermore, it extracts additional attributes embedded as Javadoc comments from
the methods. At the moment, the only such attribute is "@event.severity" which indicates
the default event severity (which can be changed by event listeners). The example event
producer above shows the Javadocs for an event method.
</p>
<p>
There's one more information that is extracted from the event producer information for
the event model: an optional primary exception. The first exception in the "throws"
declaration of an event method is noted. It is used to throw an exception from
the invocation handler if the event has an event severity of "FATAL" when all
listeners have been called (listeners can update the event severity). Please note
that an implementation of
<code>org.apache.fop.events.EventExceptionManager$ExceptionFactory</code> has to be
registered for the <code>EventExceptionManager</code> to be able to construct the
exception from an event.
</p>
<p>
For a given application, there can be multiple event models active at the same time.
In FOP, each renderer is considered to be a plug-in and provides its own specific
event model. The individual event models are provided through an
<code>EventModelFactory</code>. This interface is implemented for each event model
and registered through the service provider mechanism
(see the <a href="#plug-ins">plug-ins section</a> for details).
</p>
</section>
<section id="event-severity">
<title>Event severity</title>
<p>
Four different levels of severity for events has been defined:
</p>
<ol>
<li>INFO: informational only</li>
<li>WARN: a Warning</li>
<li>ERROR: an error condition from which FOP can recover. FOP will continue processing.</li>
<li>FATAL: a fatal error which causes an exception in the end and FOP will stop processing.</li>
</ol>
<p>
Event listeners can choose to ignore certain events based on their event severity.
Please note that you may recieve an event "twice" in a specific case: if there is
a fatal error an event is generated and sent to the listeners. After that an exception
is thrown with the same information and processing stops. If the fatal event is
shown to the user and the following exception is equally presented to the user it
may appear that the event is duplicated. Of course, the same information is just
published through two different channels.
</p>
</section>
<section id="plug-ins">
<title>Plug-ins to the event subsystem</title>
<p>
The event subsystem is extensible. There are a number of extension points:
</p>
<ul>
<li>
<strong><code>org.apache.fop.events.model.EventModelFactory</code>:</strong> Provides
an event model to the event subsystem.
</li>
<li>
<strong><code>org.apache.fop.events.EventExceptionManager$ExceptionFactory</code>:</strong>
Creates exceptions for events, i.e. turns an event into a specific exception.
</li>
</ul>
<p>
The names in bold above are used as filenames for the service provider files that
are placed in the <code>META-INF/services</code> directory. That way, they are
automatically detected. This is a mechanism defined by the
<a href="http://java.sun.com/j2se/1.4.2/docs/guide/jar/jar.html#Service%20Provider">JAR file specification</a>.
</p>
</section>
<section id="l10n">
<title>Localization (L10n)</title>
<p>
One goal of the event subsystem was to have localized (translated) event messages.
The <code>EventFormatter</code> class can be used to convert an event to a
human-readable message. Each <code>EventProducer</code> can provide its own XML-based
translation file. If there is none, a central translation file is used, called
"EventFormatter.xml" (found in the same directory as the <code>EventFormatter</code>
class).
</p>
<p>
The XML format used by the <code>EventFormatter</code> is the same as
<a href="ext:cocoon">Apache Cocoon's</a> catalog format. Here's an example:
</p>
<source><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<catalogue xml:lang="en">
<message key="locator">
[ (See position {loc})| (See {#gatherContextInfo})| (No context info available)]
</message>
<message key="org.apache.fop.render.rtf.RTFEventProducer.explicitTableColumnsRequired">
RTF output requires that all table-columns for a table are defined. Output will be incorrect.{{locator}}
</message>
<message key="org.apache.fop.render.rtf.RTFEventProducer.ignoredDeferredEvent">
Ignored deferred event for {node} ({start,if,start,end}).{{locator}}
</message>
</catalogue>
]]></source>
<p>
The example (extracted from the RTF handler's event producer) has message templates for
two event methods. The class used to do variable replacement in the templates is
<code>org.apache.fop.util.text.AdvancedMessageFormat</code> which is more powerful
than the <code>MessageFormat</code> classes provided by the Java class library
(<code>java.util.text</code> package).
</p>
<p>
"locator" is a template that is reused by the other message templates
by referencing it through "{{locator}}". This is some kind of include command.
</p>
<p>
Normal event parameters are accessed by name inside single curly braces, for example:
"{node}". For objects, this format just uses the <code>toString()</code> method to turn
the object into a string, unless there is an <code>ObjectFormatter</code> registered
for that type (there's an example for <code>org.xml.sax.Locator</code>).
</p>
<p>
The single curly braces pattern supports additional features. For example, it is possible
to do this: "{start,if,start,end}". "if" here is a special field modifier that evaluates
"start" as a boolean and if that is true returns the text right after the second comma
("start"). Otherwise it returns the text after the third comma ("end"). The "equals"
modifier is similar to "if" but it takes as an additional (comma-separated) parameter
right after the "equals" modifier, a string that is compared to the value of the variable.
An example: {severity,equals,EventSeverity:FATAL,,some text} (this adds "some text" if
the severity is not FATAL).
</p>
<p>
Additional such modifiers can be added by implementing the
<code>AdvancedMessageFormat$Part</code> and <code>AdvancedMessageFormat$PartFactory</code>
interfaces.
</p>
<p>
Square braces can be used to specify optional template sections. The whole section will
be omitted if any of the variables used within are unavailable. Pipe (|) characters can
be used to specify alternative sub-templates (see "locator" above for an example).
</p>
<p>
Developers can also register a function (in the above example:
<code>{#gatherContextInfo})</code>
to do more complex information rendering. These functions are implementations of the
<code>AdvancedMessageFormat$Function</code> interface. Please take care that this is
done in a locale-independent way as there is no locale information available, yet.
</p>
</section>
</section>
</body>
</document>

+ 4
- 0
src/java/META-INF/services/org.apache.fop.events.EventExceptionManager$ExceptionFactory View File

@@ -0,0 +1,4 @@
org.apache.fop.events.ValidationExceptionFactory
org.apache.fop.events.PropertyExceptionFactory
org.apache.fop.events.UnsupportedOperationExceptionFactory
org.apache.fop.layoutmgr.LayoutException$LayoutExceptionFactory

+ 7
- 0
src/java/META-INF/services/org.apache.fop.events.model.EventModelFactory View File

@@ -0,0 +1,7 @@
org.apache.fop.events.FOPEventModelFactory
org.apache.fop.render.afp.AFPEventProducer$EventModelFactory
org.apache.fop.render.bitmap.BitmapRendererEventProducer$EventModelFactory
org.apache.fop.render.pcl.PCLEventProducer$EventModelFactory
org.apache.fop.render.pdf.PDFEventProducer$EventModelFactory
org.apache.fop.render.ps.PSEventProducer$EventModelFactory
org.apache.fop.render.rtf.RTFEventProducer$EventModelFactory

+ 1
- 0
src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$Function View File

@@ -0,0 +1 @@
org.apache.fop.fo.FONode$GatherContextInfoFunction

+ 1
- 0
src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$ObjectFormatter View File

@@ -0,0 +1 @@
org.apache.fop.util.text.LocatorFormatter

+ 6
- 0
src/java/META-INF/services/org.apache.fop.util.text.AdvancedMessageFormat$PartFactory View File

@@ -0,0 +1,6 @@
org.apache.fop.util.text.IfFieldPart$Factory
org.apache.fop.util.text.EqualsFieldPart$Factory
org.apache.fop.util.text.ChoiceFieldPart$Factory
org.apache.fop.util.text.HexFieldPart$Factory
org.apache.fop.util.text.GlyphNameFieldPart$Factory
org.apache.fop.events.EventFormatter$LookupFieldPartFactory

+ 21
- 0
src/java/org/apache/fop/apps/FOPException.java View File

@@ -32,6 +32,8 @@ public class FOPException extends SAXException {
private String systemId;
private int line;
private int column;
private String localizedMessage;

/**
* Constructs a new FOP exception with the specified detail message.
@@ -210,5 +212,24 @@ public class FOPException extends SAXException {
}
}
}
/**
* Sets the localized message for this exception.
* @param msg the localized message
*/
public void setLocalizedMessage(String msg) {
this.localizedMessage = msg;
}

/** {@inheritDoc} */
public String getLocalizedMessage() {
if (this.localizedMessage != null) {
return this.localizedMessage;
} else {
return super.getLocalizedMessage();
}
}

}

+ 45
- 0
src/java/org/apache/fop/apps/FOUserAgent.java View File

@@ -36,6 +36,12 @@ import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext;

import org.apache.fop.Version;
import org.apache.fop.events.DefaultEventBroadcaster;
import org.apache.fop.events.Event;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventProducer;
import org.apache.fop.events.FOPEventListenerProxy;
import org.apache.fop.events.LoggingEventListener;
import org.apache.fop.fo.FOEventHandler;
import org.apache.fop.render.Renderer;
import org.apache.fop.render.RendererFactory;
@@ -89,6 +95,7 @@ public class FOUserAgent {
private Renderer rendererOverride = null;
private FOEventHandler foEventHandlerOverride = null;
private boolean locatorEnabled = true; // true by default (for error messages).
private EventBroadcaster eventBroadcaster = new FOPEventBroadcaster();
/** Producer: Metadata element for the system/software that produces
* the document. (Some renderers can store this in the document.)
@@ -530,5 +537,43 @@ public class FOUserAgent {
return locatorEnabled;
}

/**
* Returns the event broadcaster that control events sent inside a processing run. Clients
* can register event listeners with the event broadcaster to listen for events that occur
* while a document is being processed.
* @return the event broadcaster.
*/
public EventBroadcaster getEventBroadcaster() {
return this.eventBroadcaster;
}

private class FOPEventBroadcaster extends DefaultEventBroadcaster {

private FOPEventListenerProxy rootListener;
public FOPEventBroadcaster() {
this.rootListener = new FOPEventListenerProxy(
this.listeners, FOUserAgent.this);
}
/** {@inheritDoc} */
public void broadcastEvent(Event event) {
rootListener.processEvent(event);
}

/** {@inheritDoc} */
protected EventProducer createProxyFor(Class clazz) {
if (!this.listeners.hasEventListeners()) {
//Backwards-compatibility: Make sure at least the LoggingEventListener is plugged
//in so no events are just silently swallowed.
addEventListener(
new LoggingEventListener(LogFactory.getLog(FOUserAgent.class)));
}
return super.createProxyFor(clazz);
}
}
}


+ 91
- 0
src/java/org/apache/fop/area/AreaEventProducer.java View File

@@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.area;

import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventProducer;

/**
* Event producer interface for events related to the area tree.
*/
public interface AreaEventProducer extends EventProducer {

/**
* Provider class for the event producer.
*/
class Provider {
/**
* Returns an event producer.
* @param broadcaster the event broadcaster to use
* @return the event producer
*/
public static AreaEventProducer get(EventBroadcaster broadcaster) {
return (AreaEventProducer)broadcaster.getEventProducerFor(
AreaEventProducer.class);
}
}

/**
* An unresolved ID reference was encountered.
* @param source the event source
* @param type the type of reference
* @param id the unresolved ID
* @event.severity WARN
*/
void unresolvedIDReference(Object source, String type, String id);
/**
* An unresolved ID reference was encountered on a page.
* @param source the event source
* @param page the page the ID reference was found on
* @param id the unresolved ID
* @event.severity WARN
*/
void unresolvedIDReferenceOnPage(Object source, String page, String id);
/**
* A page could not be loaded/deserialized from a file.
* @param source the event source
* @param page the page to be loaded
* @param e the original exception
* @event.severity ERROR
*/
void pageLoadError(Object source, String page, Exception e);
/**
* A page could not be saved/serialized to a file.
* @param source the event source
* @param page the page to be serialized
* @param e the original exception
* @event.severity ERROR
*/
void pageSaveError(Object source, String page, Exception e);
/**
* A page could not be rendered.
* @param source the event source
* @param page the page to be serialized
* @param e the original exception
* @event.severity ERROR
*/
void pageRenderingError(Object source, String page, Exception e);
}

+ 3
- 2
src/java/org/apache/fop/area/AreaTreeHandler.java View File

@@ -325,8 +325,9 @@ public class AreaTreeHandler extends FOEventHandler {
if (pageVPList != null) {
res.resolveIDRef(ids[count], pageVPList);
} else {
log.warn(odi.getName() + ": Unresolved id reference \""
+ ids[count] + "\" found.");
AreaEventProducer eventProducer = AreaEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.unresolvedIDReference(this, odi.getName(), ids[count]);
idTracker.addUnresolvedIDRef(ids[count], res);
}
}

+ 5
- 5
src/java/org/apache/fop/area/AreaTreeObject.java View File

@@ -23,7 +23,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

import org.apache.fop.util.QName;
import org.apache.xmlgraphics.util.QName;

/**
* Abstract base class for all area tree objects.
@@ -53,12 +53,12 @@ public abstract class AreaTreeObject {
if (atts.size() == 0) {
return;
}
Iterator iter = atts.keySet().iterator();
Iterator iter = atts.entrySet().iterator();
while (iter.hasNext()) {
QName qName = (QName)iter.next();
String value = (String)atts.get(qName);
Map.Entry entry = (Map.Entry)iter.next();
String value = (String)entry.getValue();
//The casting is only to ensure type safety (too bad we can't use generics, yet)
setForeignAttribute(qName, value);
setForeignAttribute((QName)entry.getKey(), value);
}
}

+ 1
- 1
src/java/org/apache/fop/area/AreaTreeParser.java View File

@@ -50,6 +50,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
import org.apache.xmlgraphics.image.loader.ImageSessionContext;
import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.Trait.Background;
@@ -78,7 +79,6 @@ import org.apache.fop.util.ColorUtil;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.ContentHandlerFactoryRegistry;
import org.apache.fop.util.DefaultErrorListener;
import org.apache.fop.util.QName;

/**
* This is a parser for the area tree XML (intermediate format) which is used to reread an area

+ 38
- 39
src/java/org/apache/fop/area/CachedRenderPagesModel.java View File

@@ -19,24 +19,27 @@
package org.apache.fop.area;

import org.apache.commons.io.IOUtils;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.FontInfo;
import org.xml.sax.SAXException;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.xml.sax.SAXException;

import org.apache.commons.io.IOUtils;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.fonts.FontInfo;

/**
* A simple cached render pages model.
@@ -69,46 +72,39 @@ public class CachedRenderPagesModel extends RenderPagesModel {
*/
protected boolean checkPreparedPages(PageViewport newpage, boolean renderUnresolved) {
for (Iterator iter = prepared.iterator(); iter.hasNext();) {
PageViewport p = (PageViewport)iter.next();
if (p.isResolved() || renderUnresolved) {
if (p != newpage) {
PageViewport pageViewport = (PageViewport)iter.next();
if (pageViewport.isResolved() || renderUnresolved) {
if (pageViewport != newpage) {
try {
// load page from cache
String name = (String)pageMap.get(p);
String name = (String)pageMap.get(pageViewport);
File tempFile = new File(baseDir, name);
log.debug("Loading page from: " + tempFile);
ObjectInputStream in = new ObjectInputStream(
new BufferedInputStream(
new FileInputStream(tempFile)));
try {
p.loadPage(in);
pageViewport.loadPage(in);
} finally {
IOUtils.closeQuietly(in);
}
if (!tempFile.delete()) {
log.warn("Temporary file could not be deleted: " + tempFile);
ResourceEventProducer eventProducer
= ResourceEventProducer.Provider.get(
renderer.getUserAgent().getEventBroadcaster());
eventProducer.cannotDeleteTempFile(this, tempFile);
}
pageMap.remove(p);
pageMap.remove(pageViewport);
} catch (Exception e) {
log.error(e);
AreaEventProducer eventProducer
= AreaEventProducer.Provider.get(
renderer.getUserAgent().getEventBroadcaster());
eventProducer.pageLoadError(this, pageViewport.getPageNumberString(), e);
}
}

try {
renderer.renderPage(p);
if (!p.isResolved()) {
String[] idrefs = p.getIDRefs();
for (int count = 0; count < idrefs.length; count++) {
log.warn("Page " + p.getPageNumberString()
+ ": Unresolved id reference \"" + idrefs[count]
+ "\" found.");
}
}
} catch (Exception e) {
// use error handler to handle this FOP or IO Exception
log.error(e);
}
p.clear();
renderPage(pageViewport);
pageViewport.clear();
iter.remove();
} else {
if (!renderer.supportsOutOfOrder()) {
@@ -147,8 +143,11 @@ public class CachedRenderPagesModel extends RenderPagesModel {
if (log.isDebugEnabled()) {
log.debug("Page saved to temporary file: " + tempFile);
}
} catch (Exception e) {
log.error(e);
} catch (IOException ioe) {
AreaEventProducer eventProducer
= AreaEventProducer.Provider.get(
renderer.getUserAgent().getEventBroadcaster());
eventProducer.pageSaveError(this, page.getPageNumberString(), ioe);
}
}


+ 9
- 7
src/java/org/apache/fop/area/PageViewport.java View File

@@ -21,14 +21,15 @@ package org.apache.fop.area;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
@@ -516,9 +517,9 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl
* The map of unresolved references are set on the page so that
* the resolvers can be properly serialized and reloaded.
* @param out the object output stream to write the contents
* @throws Exception if there is a problem saving the page
* @throws IOException in case of an I/O error while serializing the page
*/
public void savePage(ObjectOutputStream out) throws Exception {
public void savePage(ObjectOutputStream out) throws IOException {
// set the unresolved references so they are serialized
page.setUnresolvedReferences(unresolvedIDRefs);
out.writeObject(page);
@@ -531,9 +532,10 @@ public class PageViewport extends AreaTreeObject implements Resolvable, Cloneabl
* if there are any unresolved references that were resolved
* while saved they will be resolved on the page contents.
* @param in the object input stream to read the page from
* @throws Exception if there is an error loading the page
* @throws ClassNotFoundException if a class was not found while loading the page
* @throws IOException if an I/O error occurred while loading the page
*/
public void loadPage(ObjectInputStream in) throws Exception {
public void loadPage(ObjectInputStream in) throws IOException, ClassNotFoundException {
page = (Page) in.readObject();
unresolvedIDRefs = page.getUnresolvedReferences();
if (unresolvedIDRefs != null && pendingResolved != null) {

+ 28
- 17
src/java/org/apache/fop/area/RenderPagesModel.java View File

@@ -156,23 +156,7 @@ public class RenderPagesModel extends AreaTreeModel {
&& pageViewport.getPageSequence().isFirstPage(pageViewport)) {
renderer.startPageSequence(getCurrentPageSequence());
}
try {
renderer.renderPage(pageViewport);
if (!pageViewport.isResolved()) {
String[] idrefs = pageViewport.getIDRefs();
for (int count = 0; count < idrefs.length; count++) {
log.warn("Page " + pageViewport.getPageNumberString()
+ ": Unresolved id reference \"" + idrefs[count]
+ "\" found.");
}
}
} catch (Exception e) {
// use error handler to handle this FOP or IO Exception
log.error("Error while rendering page " + pageViewport.getPageIndex(), e);
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
}
renderPage(pageViewport);
pageViewport.clear();
iter.remove();
} else {
@@ -185,6 +169,33 @@ public class RenderPagesModel extends AreaTreeModel {
return renderer.supportsOutOfOrder() || prepared.isEmpty();
}

/**
* Renders the given page and notified about unresolved IDs if any.
* @param pageViewport the page to be rendered.
*/
protected void renderPage(PageViewport pageViewport) {
try {
renderer.renderPage(pageViewport);
if (!pageViewport.isResolved()) {
String[] idrefs = pageViewport.getIDRefs();
for (int count = 0; count < idrefs.length; count++) {
AreaEventProducer eventProducer = AreaEventProducer.Provider.get(
renderer.getUserAgent().getEventBroadcaster());
eventProducer.unresolvedIDReferenceOnPage(this,
pageViewport.getPageNumberString(), idrefs[count]);
}
}
} catch (Exception e) {
AreaEventProducer eventProducer = AreaEventProducer.Provider.get(
renderer.getUserAgent().getEventBroadcaster());
eventProducer.pageRenderingError(this,
pageViewport.getPageNumberString(), e);
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}
}
}

/**
* Prepare a page.
* An unresolved page can be prepared if the renderer supports

+ 69
- 0
src/java/org/apache/fop/events/CompositeEventListener.java View File

@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.List;

/**
* EventListener implementation forwards events to possibly multiple other EventListeners.
*/
public class CompositeEventListener implements EventListener {

private List listeners = new java.util.ArrayList();
/**
* Adds an event listener to the broadcaster. It is appended to the list of previously
* registered listeners (the order of registration defines the calling order).
* @param listener the listener to be added
*/
public synchronized void addEventListener(EventListener listener) {
this.listeners.add(listener);
}

/**
* Removes an event listener from the broadcaster. If the event listener is not registered,
* nothing happens.
* @param listener the listener to be removed
*/
public synchronized void removeEventListener(EventListener listener) {
this.listeners.remove(listener);
}

private synchronized int getListenerCount() {
return this.listeners.size();
}
/**
* Indicates whether any listeners have been registered with the broadcaster.
* @return true if listeners are present, false otherwise
*/
public boolean hasEventListeners() {
return (getListenerCount() > 0);
}
/** {@inheritDoc} */
public synchronized void processEvent(Event event) {
for (int i = 0, c = getListenerCount(); i < c; i++) {
EventListener listener = (EventListener)this.listeners.get(i);
listener.processEvent(event);
}
}

}

+ 160
- 0
src/java/org/apache/fop/events/DefaultEventBroadcaster.java View File

@@ -0,0 +1,160 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.xmlgraphics.util.Service;

import org.apache.fop.events.model.EventMethodModel;
import org.apache.fop.events.model.EventModel;
import org.apache.fop.events.model.EventModelFactory;
import org.apache.fop.events.model.EventProducerModel;
import org.apache.fop.events.model.EventSeverity;

/**
* Default implementation of the EventBroadcaster interface. It holds a list of event listeners
* and can provide {@link EventProducer} instances for type-safe event production.
*/
public class DefaultEventBroadcaster implements EventBroadcaster {

/** Holds all registered event listeners */
protected CompositeEventListener listeners = new CompositeEventListener();
/** {@inheritDoc} */
public void addEventListener(EventListener listener) {
this.listeners.addEventListener(listener);
}

/** {@inheritDoc} */
public void removeEventListener(EventListener listener) {
this.listeners.removeEventListener(listener);
}

/** {@inheritDoc} */
public boolean hasEventListeners() {
return this.listeners.hasEventListeners();
}
/** {@inheritDoc} */
public void broadcastEvent(Event event) {
this.listeners.processEvent(event);
}

private static List/*<EventModel>*/ eventModels = new java.util.ArrayList();
private Map proxies = new java.util.HashMap();
static {
Iterator iter = Service.providers(EventModelFactory.class, true);
while (iter.hasNext()) {
EventModelFactory factory = (EventModelFactory)iter.next();
addEventModel(factory.createEventModel());
}
}

/**
* Adds a new {@link EventModel} to the list of registered event models.
* @param eventModel the event model instance
*/
public static void addEventModel(EventModel eventModel) {
eventModels.add(eventModel);
}
/** {@inheritDoc} */
public EventProducer getEventProducerFor(Class clazz) {
if (!EventProducer.class.isAssignableFrom(clazz)) {
throw new IllegalArgumentException(
"Class must be an implementation of the EventProducer interface: "
+ clazz.getName());
}
EventProducer producer;
producer = (EventProducer)this.proxies.get(clazz);
if (producer == null) {
producer = createProxyFor(clazz);
this.proxies.put(clazz, producer);
}
return producer;
}
private EventProducerModel getEventProducerModel(Class clazz) {
for (int i = 0, c = eventModels.size(); i < c; i++) {
EventModel eventModel = (EventModel)eventModels.get(i);
EventProducerModel producerModel = eventModel.getProducer(clazz);
if (producerModel != null) {
return producerModel;
}
}
return null;
}
/**
* Creates a dynamic proxy for the given EventProducer interface that will handle the
* conversion of the method call into the broadcasting of an event instance.
* @param clazz a descendant interface of EventProducer
* @return the EventProducer instance
*/
protected EventProducer createProxyFor(Class clazz) {
final EventProducerModel producerModel = getEventProducerModel(clazz);
if (producerModel == null) {
throw new IllegalStateException("Event model doesn't contain the definition for "
+ clazz.getName());
}
return (EventProducer)Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[] {clazz},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
EventMethodModel methodModel = producerModel.getMethod(methodName);
String eventID = producerModel.getInterfaceName() + "." + methodName;
if (methodModel == null) {
throw new IllegalStateException(
"Event model isn't consistent"
+ " with the EventProducer interface. Please rebuild FOP!"
+ " Affected method: "
+ eventID);
}
Map params = new java.util.HashMap();
int i = 1;
Iterator iter = methodModel.getParameters().iterator();
while (iter.hasNext()) {
EventMethodModel.Parameter param
= (EventMethodModel.Parameter)iter.next();
params.put(param.getName(), args[i]);
i++;
}
Event ev = new Event(args[0], eventID, methodModel.getSeverity(), params);
broadcastEvent(ev);
if (ev.getSeverity() == EventSeverity.FATAL) {
EventExceptionManager.throwException(ev,
methodModel.getExceptionClass());
}
return null;
}
});
}
}

+ 150
- 0
src/java/org/apache/fop/events/Event.java View File

@@ -0,0 +1,150 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Collections;
import java.util.EventObject;
import java.util.Map;

import org.apache.fop.events.model.EventSeverity;

/**
* This is the default event class used by this package. Each event has a unique event identifier
* (a String), a severity indicator and a map of name/value pairs.
*/
public class Event extends EventObject {

private static final long serialVersionUID = -1310594422868258083L;
private String eventID;
private EventSeverity severity;
private Map params;
/**
* Creates a new Event.
* @param source the object that creates the event
* @param eventID the unique identifier of the event
* @param severity the severity level
* @param params the event parameters (a map of name/value pairs)
*/
public Event(Object source, String eventID, EventSeverity severity, Map params) {
super(source);
this.eventID = eventID;
setSeverity(severity);
this.params = params;
}
/**
* Returns the event identifier.
* @return the event identifier
*/
public String getEventID() {
return this.eventID;
}
/**
* Returns the event group identifier.
* @return the event group identifier (or null if there is no group identifier)
*/
public String getEventGroupID() {
int pos = this.eventID.lastIndexOf('.');
if (pos > 0) {
return this.eventID.substring(0, pos);
} else {
return null;
}
}
/**
* Returns the severity level.
* @return the severity level
*/
public EventSeverity getSeverity() {
return this.severity;
}
/**
* Sets the event's severity level. This method can be used to increase or decrease the
* severity level in a listener.
* @param severity the new event severity
*/
public void setSeverity(EventSeverity severity) {
this.severity = severity;
}

/**
* Returns a parameter.
* @param key the key to the parameter
* @return the parameter value or null if no value with this key is found
*/
public Object getParam(String key) {
if (this.params != null) {
return this.params.get(key);
} else {
return null;
}
}
/**
* Returns an unmodifiable {@link java.util.Map} with all event parameters.
* @return the parameter map
*/
public Map getParams() {
return Collections.unmodifiableMap(this.params);
}
/**
* Creates and returns a fluent builder object for building up the parameter map.
* @return the parameter builder
*/
public static ParamsBuilder paramsBuilder() {
return new ParamsBuilder();
}
/**
* This class is a fluent builder class for building up the parameter map.
*/
public static class ParamsBuilder {
private Map params;
/**
* Adds a new parameter (a name/value pair).
* @param name the name of the parameter
* @param value the value of the parameter
* @return this instance
*/
public ParamsBuilder param(String name, Object value) {
if (this.params == null) {
this.params = new java.util.HashMap();
}
this.params.put(name, value);
return this;
}
/**
* Returns the accumulated parameter map.
* @return the accumulated parameter map
*/
public Map build() {
return this.params;
}
}
}

+ 61
- 0
src/java/org/apache/fop/events/EventBroadcaster.java View File

@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

/**
* The EventBroadcaster is the central relay point for events. It receives events from various
* parts of the application and forwards them to any registered EventListener.
*/
public interface EventBroadcaster {

/**
* Adds an event listener to the broadcaster. It is appended to the list of previously
* registered listeners (the order of registration defines the calling order).
* @param listener the listener to be added
*/
void addEventListener(EventListener listener);
/**
* Removes an event listener from the broadcaster. If the event listener is not registered,
* nothing happens.
* @param listener the listener to be removed
*/
void removeEventListener(EventListener listener);
/**
* Indicates whether any listeners have been registered with the broadcaster.
* @return true if listeners are present, false otherwise
*/
boolean hasEventListeners();
/**
* Broadcasts an event. This method is usually called from within the observed component.
* @param event the event to be broadcast
*/
void broadcastEvent(Event event);
/**
* Returns an event producer instance for the given interface class.
* @param clazz the Class object identifying an {@link EventProducer} interface
* @return the event producer instance
*/
EventProducer getEventProducerFor(Class clazz);
}

+ 84
- 0
src/java/org/apache/fop/events/EventExceptionManager.java View File

@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Iterator;
import java.util.Map;

import org.apache.xmlgraphics.util.Service;

/**
* This class is reponsible for converting events into exceptions.
*/
public class EventExceptionManager {

private static final Map EXCEPTION_FACTORIES = new java.util.HashMap();
static {
Iterator iter;
iter = Service.providers(ExceptionFactory.class, true);
while (iter.hasNext()) {
ExceptionFactory factory = (ExceptionFactory)iter.next();
EXCEPTION_FACTORIES.put(factory.getExceptionClass().getName(), factory);
}
}
/**
* Converts an event into an exception and throws that. If the exception class is null,
* a {@link RuntimeException} will be thrown.
* @param event the event to be converted
* @param exceptionClass the exception class to be thrown
* @throws Throwable this happens always
*/
public static void throwException(Event event, String exceptionClass) throws Throwable {
if (exceptionClass != null) {
ExceptionFactory factory = (ExceptionFactory)EXCEPTION_FACTORIES.get(exceptionClass);
if (factory != null) {
throw factory.createException(event);
} else {
throw new IllegalArgumentException(
"No such ExceptionFactory available: " + exceptionClass);
}
} else {
String msg = EventFormatter.format(event);
throw new RuntimeException(msg);
}
}
/**
* This interface is implementation by exception factories that can create exceptions from
* events.
*/
public interface ExceptionFactory {
/**
* Creates an exception from an event.
* @param event the event
* @return the newly created exception
*/
Throwable createException(Event event);
/**
* Returns the {@link Exception} class created by this factory.
* @return the exception class
*/
Class getExceptionClass();
}
}

+ 196
- 0
src/java/org/apache/fop/events/EventFormatter.java View File

@@ -0,0 +1,196 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.util.XMLResourceBundle;
import org.apache.fop.util.text.AdvancedMessageFormat;
import org.apache.fop.util.text.AdvancedMessageFormat.Part;
import org.apache.fop.util.text.AdvancedMessageFormat.PartFactory;

/**
* Converts events into human-readable, localized messages.
*/
public final class EventFormatter {

private static final Pattern INCLUDES_PATTERN = Pattern.compile("\\{\\{.+\\}\\}");
private static ResourceBundle defaultBundle = XMLResourceBundle.getXMLBundle(
EventFormatter.class.getName(), EventFormatter.class.getClassLoader());
private static Log log = LogFactory.getLog(EventFormatter.class);
private EventFormatter() {
//utility class
}
/**
* Formats an event using the default locale.
* @param event the event
* @return the formatted message
*/
public static String format(Event event) {
ResourceBundle bundle = null;
String groupID = event.getEventGroupID();
if (groupID != null) {
try {
bundle = XMLResourceBundle.getXMLBundle(
groupID,
EventFormatter.class.getClassLoader());
} catch (MissingResourceException mre) {
if (log.isTraceEnabled()) {
log.trace("No XMLResourceBundle for " + groupID + " available.");
}
}
}
if (bundle == null) {
bundle = defaultBundle;
}
return format(event, bundle);
}
/**
* Formats an event using a given locale.
* @param event the event
* @param locale the locale
* @return the formatted message
*/
public static String format(Event event, Locale locale) {
ResourceBundle bundle = null;
String groupID = event.getEventGroupID();
if (groupID != null) {
try {
bundle = XMLResourceBundle.getXMLBundle(
groupID, locale,
EventFormatter.class.getClassLoader());
} catch (MissingResourceException mre) {
if (log.isTraceEnabled()) {
log.trace("No XMLResourceBundle for " + groupID + " available.");
}
}
}
if (bundle == null) {
bundle = XMLResourceBundle.getXMLBundle(
EventFormatter.class.getName(),
locale,
EventFormatter.class.getClassLoader());
}
return format(event, bundle);
}

private static String format(Event event, ResourceBundle bundle) {
String template = bundle.getString(event.getEventID());
return format(event, processIncludes(template, bundle));
}

private static String processIncludes(String template, ResourceBundle bundle) {
CharSequence input = template;
int replacements;
StringBuffer sb;
do {
sb = new StringBuffer(Math.max(16, input.length()));
replacements = processIncludesInner(input, sb, bundle);
input = sb;
} while (replacements > 0);
String s = sb.toString();
return s;
}

private static int processIncludesInner(CharSequence template, StringBuffer sb,
ResourceBundle bundle) {
int replacements = 0;
Matcher m = INCLUDES_PATTERN.matcher(template);
while (m.find()) {
String include = m.group();
include = include.substring(2, include.length() - 2);
m.appendReplacement(sb, bundle.getString(include));
replacements++;
}
m.appendTail(sb);
return replacements;
}

/**
* Formats the event using a given pattern. The pattern needs to be compatible with
* {@link AdvancedMessageFormat}.
* @param event the event
* @param pattern the pattern (compatible with {@link AdvancedMessageFormat})
* @return the formatted message
*/
public static String format(Event event, String pattern) {
AdvancedMessageFormat format = new AdvancedMessageFormat(pattern);
Map params = new java.util.HashMap(event.getParams());
params.put("source", event.getSource());
params.put("severity", event.getSeverity());
return format.format(params);
}
private static class LookupFieldPart implements Part {
private String fieldName;
public LookupFieldPart(String fieldName) {
this.fieldName = fieldName;
}

public boolean isGenerated(Map params) {
return getKey(params) != null;
}

public void write(StringBuffer sb, Map params) {
sb.append(defaultBundle.getString(getKey(params)));
}

private String getKey(Map params) {
return (String)params.get(fieldName);
}
/** {@inheritDoc} */
public String toString() {
return "{" + this.fieldName + ", lookup}";
}
}
/** PartFactory for lookups. */
public static class LookupFieldPartFactory implements PartFactory {

/** {@inheritDoc} */
public Part newPart(String fieldName, String values) {
return new LookupFieldPart(fieldName);
}

/** {@inheritDoc} */
public String getFormat() {
return "lookup";
}
}

}

+ 101
- 0
src/java/org/apache/fop/events/EventFormatter.xml View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<catalogue xml:lang="en">
<message key="locator">[ (See position {loc})| (See {#gatherContextInfo})| (No context info available)]</message>
<message key="rule.markerDescendantOfFlow">An fo:marker is permitted only as the descendant of an fo:flow.</message>
<message key="rule.retrieveMarkerDescendatOfStaticContent">An fo:retrieve-marker is permitted only as the descendant of an fo:static-content.</message>
<message key="rule.bidiOverrideContent">An fo:bidi-override that is a descendant of an fo:leader or of the fo:inline child of an fo:footnote may not have block-level children, unless it has a nearer ancestor that is an fo:inline-container.</message>
<message key="rule.inlineContent">An fo:inline that is a descendant of an fo:leader or fo:footnote may not have block-level children, unless it has a nearer ancestor that is an fo:inline-container.</message>
<message key="rule.childOfSPM">The element must be a child of fo:simple-page-master.</message>
<message key="rule.childOfDeclarations">The element must be a child of fo:declarations.</message>
<message key="rule.childOfSPMorDeclarations">The element must be a child of fo:declarations or fo:simple-page-master.</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.invalidChild">"{offendingNode}" is not a valid child element of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.missingChildElement">"{elementName}" is missing child elements.[
Required content model: {contentModel}]{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,,
Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.markerNotInitialChild">fo:marker must be an initial child: {mcname}{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.markerNotUniqueForSameParent">fo:marker "marker-class-name" must be unique for same parent: {mcname}{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.invalidProperty">Invalid property encountered on "{elementName}": {attr}{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.invalidPropertyValue">Invalid property value encountered in {propName}="{propValue}"[: {e}]{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.unimplementedFeature">The following feature isn't implemented by Apache FOP, yet: {feature} (on {elementName}){{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.missingLinkDestination">Missing attribute on {elementName}: Either external-destination or internal-destination must be specified.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.markerCloningFailed">Unable to clone subtree of fo:marker (marker-class-name="{markerClassName}") for fo:retrieve-marker.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.colorProfileNameNotUnique">Duplicate color profile profile name: {name}{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.regionNameMappedToMultipleRegionClasses">Region-name ("{regionName}") is being mapped to multiple region-classes ({defaultRegionClass1} and {defaultRegionClass2}).{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.masterNameNotUnique">The page master name ("{name}") must be unique across page-masters and page-sequence-masters.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.duplicateFlowNameInPageSequence">Duplicate flow-name "{flowName}" found within {elementName}.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.flowNameNotMapped">The flow-name "{flowName}" on {elementName} could not be mapped to a region-name in the layout-master-set.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.masterNotFound">The master-reference "{masterReference}" on {elementName} matches no simple-page-master or page-sequence-master.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.illegalRegionName">The region-name "{regionName}" for {elementName} is not permitted.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.nonZeroBorderPaddingOnRegion">Border and padding for {elementName} "{regionName}" must be '0' (See 6.4.13 in XSL 1.0).{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.columnCountErrorOnRegionBodyOverflowScroll">If overflow property is set to "scroll" on {elementName}, a column-count other than "1" may not be specified.{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.invalidFORoot">First element must be the fo:root formatting object. Found {elementName} instead. Please make sure you're producing a valid XSL-FO document.</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.emptyDocument">Document is empty (something might be wrong with your XSLT stylesheet).</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.unknownFormattingObject">Unknown formatting object "{offendingNode}" encountered (a child of {elementName}}.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.nonAutoBPDOnTable">Only a value of "auto" for block-progression-dimension has a well-specified behavior on fo:table. Falling back to "auto".{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.noTablePaddingWithCollapsingBorderModel">In collapsing border model a table does not have padding (see http://www.w3.org/TR/REC-CSS2/tables.html#collapsing-borders), but a non-zero value for padding was found. The padding will be ignored.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.noMixRowsAndCells">Either fo:table-rows or fo:table-cells may be children of an {elementName} but not both.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.footerOrderCannotRecover">This table uses the collapsing border model. In order to resolve borders in an efficient way the table-footer must be known before any table-body is parsed. Either put the footer at the correct place or switch to the separate border model.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.startEndRowUnderTableRowWarning">starts-row/ends-row for fo:table-cells non-applicable for children of an fo:table-row.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.tooManyCells">The column-number or number of cells in the row overflows the number of fo:table-columns specified for the table.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.valueMustBeBiggerGtEqOne">{propName} must be 1 or bigger, but got {actualValue}{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.warnImplicitColumns">table-layout=\"fixed\" and column-width unspecified =&gt; falling back to proportional-column-width(1){{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.paddingNotApplicable">padding-* properties are not applicable to {elementName}, but a non-zero value for padding was found.{{locator}}</message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.cellOverlap">{elementName} overlaps in column {column}.<!-- no locator here, exception will be wrapped --></message>
<message key="org.apache.fop.fo.flow.table.TableEventProducer.breakIgnoredDueToRowSpanning">{breakBefore,if,break-before,break-after} ignored on {elementName} because of row spanning in progress (See XSL 1.1, {breakBefore,if,7.20.2,7.20.1}){{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.imageNotFound">Image not found.[ URI: {uri}.]{{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.imageError">Image not available.[ URI: {uri}.] Reason:[ {reason}][ {e}]{{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.imageIOError">I/O error while loading image.[ URI: {uri}.][ Reason: {ioe}]{{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.ifoNoIntrinsicSize">The intrinsic dimensions of an instream-foreign-object could not be determined.{{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.uriError">Error while handling URI: {uri}. Reason: {e}{{locator}}</message>
<message key="org.apache.fop.events.ResourceEventProducer.foreignXMLProcessingError">Some XML content will be ignored. Could not render XML in namespace "{namespaceURI}".[ Reason: {e}]</message>
<message key="org.apache.fop.events.ResourceEventProducer.foreignXMLNoHandler">Some XML content will be ignored. No handler defined for XML with namespace "{namespaceURI}".</message>
<message key="org.apache.fop.events.ResourceEventProducer.imageWritingError">Error while writing an image to the target file.[ Reason: {e}]</message>
<message key="org.apache.fop.events.ResourceEventProducer.cannotDeleteTempFile">Temporary file could not be deleted: {tempFile}</message>
<message key="org.apache.fop.layoutmgr.inline.InlineLevelEventProducer.leaderWithoutContent">fo:leader is set to "use-content" but has no content.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.inline.InlineLevelEventProducer.lineOverflows">Line {line} of a paragraph overflows the available area by {overflowLength,choice,50000#{overflowLength} millipoints|50000&lt;more than 50 points}.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.rowTooTall">The contents of table-row {row} are taller than they should be (there is a block-progression-dimension or height constraint on the indicated row). Due to its contents the row grows to {effCellBPD} millipoints, but the row shouldn't get any taller than {maxCellBPD} millipoints.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.tableFixedAutoWidthNotSupported">table-layout="fixed" and width="auto", but auto-layout not supported =&gt; assuming width="100%".{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.objectTooWide">The extent in inline-progression-direction (width) of a {elementName} is bigger than the available space ({effIPD}mpt &gt; {maxIPD}mpt).{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.overconstrainedAdjustEndIndent">Adjusting end-indent based on overconstrained geometry rules for {elementName}.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.viewportOverflow">Content overflows the viewport of an {elementName} in block-progression direction by {amount} millipoints.{clip,if, Content will be clipped.}{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.regionOverflow">Content overflows the viewport of the {elementName} on page {page} in block-progression direction by {amount} millipoints.{clip,if, Content will be clipped.}{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.flowNotMappingToRegionBody">Flow "{flowName}" does not map to the region-body in page-master "{masterName}". FOP presently does not support this.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.pageSequenceMasterExhausted">Subsequences exhausted in page-sequence-master "{pageSequenceMasterName}", {canRecover,if,using previous subsequence,cannot recover}.{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.missingSubsequencesInPageSequenceMaster">No subsequences in page-sequence-master "{pageSequenceMasterName}".{{locator}}</message>
<message key="org.apache.fop.layoutmgr.BlockLevelEventProducer.noMatchingPageMaster">No simple-page-master matching "{pageMasterName}" in page-sequence-master "{pageSequenceMasterName}".{{locator}}</message>
<message key="org.apache.fop.svg.SVGEventProducer.error">SVG error: {message}</message>
<message key="org.apache.fop.svg.SVGEventProducer.alert">SVG alert: {message}</message>
<message key="org.apache.fop.svg.SVGEventProducer.info">SVG info: {message}</message>
<message key="org.apache.fop.svg.SVGEventProducer.svgNotBuilt">SVG graphic could not be built. Reason: {e}</message>
<message key="org.apache.fop.svg.SVGEventProducer.svgRenderingError">SVG graphic could not be rendered. Reason: {e}</message>
<message key="org.apache.fop.render.RendererEventProducer.ioError">I/O error while writing to target file.[ Reason: {ioe}]</message>
<message key="org.apache.fop.area.AreaEventProducer.unresolvedIDReference">{type}: Unresolved ID reference "{id}" found.</message>
<message key="org.apache.fop.area.AreaEventProducer.unresolvedIDReferenceOnPage">Page {page}: Unresolved ID reference "{id}" found.</message>
<message key="org.apache.fop.area.AreaEventProducer.pageLoadError">Error while deserializing page {page}.[ Reason: {e}]</message>
<message key="org.apache.fop.area.AreaEventProducer.pageSaveError">Error while serializing page {page}.[ Reason: {e}]</message>
<message key="org.apache.fop.area.AreaEventProducer.pageRenderingError">Error while rendering page {page}.[ Reason: {e}]</message>
<message key="org.apache.fop.fonts.FontEventAdapter.fontSubstituted">Font "{requested}" not found. Substituting with "{effective}".</message>
<message key="org.apache.fop.fonts.FontEventAdapter.fontLoadingErrorAtAutoDetection">Unable to load font file: {fontURL}.[ Reason: {e}]</message>
<message key="org.apache.fop.fonts.FontEventAdapter.glyphNotAvailable">Glyph "{ch}" (0x{ch,hex}[, {ch,glyph-name}]) not available in font "{fontName}".</message>
</catalogue>

+ 23
- 0
src/java/org/apache/fop/events/EventFormatter_de.xml View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- $Id$ -->
<catalogue xml:lang="de">
<message key="locator">[ (Siehe Position {loc})| (Siehe {#gatherContextInfo})| (Keine Kontextinformationen verfügbar)]</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.tooManyNodes">In "{elementName}" darf nur ein einziges "{offendingNode}" vorkommen!{{locator}}</message>
<message key="org.apache.fop.fo.FOValidationEventProducer.missingProperty">Dem Element "{elementName}" fehlt ein verlangtes Property "{propertyName}"!{{locator}}</message>
</catalogue>

+ 37
- 0
src/java/org/apache/fop/events/EventListener.java View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

/**
* This interface is implemented by clients who want to listen for events.
*/
public interface EventListener extends java.util.EventListener {

/**
* This method is called for each event that is generated. With the event's ID it is possible
* to react to certain events. Events can also simply be recorded and presented to a user.
* It is possible to throw an (unchecked) exception if the processing needs to be aborted
* because some special event occured. This way the client can configure the behaviour of
* the observed application.
* @param event the event
*/
void processEvent(Event event);
}

+ 31
- 0
src/java/org/apache/fop/events/EventProducer.java View File

@@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

/**
* This is a marker interface which all event producer interfaces need to extend. These interfaces
* must agree to the following convention:
* <ul>
* <li>The first parameter of each method must be: <code>Object source</code>
* </ul>
*/
public interface EventProducer {

}

+ 73
- 0
src/java/org/apache/fop/events/FOPEventListenerProxy.java View File

@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.events.model.EventSeverity;
import org.apache.fop.fo.FOValidationEventProducer;
import org.apache.fop.layoutmgr.BlockLevelEventProducer;

/**
* EventListener proxy that inspects all events and adjusts severity levels where necessary.
* For validation events, it reacts on each event based on the strict validation setting in
* the user agent.
* For layout events, it reduces the default severity level if FOP signals that it can recover
* from the event.
*/
public class FOPEventListenerProxy implements EventListener {

private static final String FOVALIDATION_EVENT_ID_PREFIX
= FOValidationEventProducer.class.getName();
private static final String BLOCK_LEVEL_EVENT_ID_PREFIX
= BlockLevelEventProducer.class.getName();

private EventListener delegate;
private FOUserAgent userAgent;
/**
* Main constructor.
* @param delegate the event listener to delegate events to
* @param userAgent the FO user agent
*/
public FOPEventListenerProxy(EventListener delegate, FOUserAgent userAgent) {
this.delegate = delegate;
this.userAgent = userAgent;
}
/** {@inheritDoc} */
public synchronized void processEvent(Event event) {
if (event.getEventID().startsWith(FOVALIDATION_EVENT_ID_PREFIX)) {
Boolean canRecover = (Boolean)event.getParam("canRecover");
if (Boolean.TRUE.equals(canRecover) && !userAgent.validateStrictly()) {
//Reduce severity if FOP can recover
event.setSeverity(EventSeverity.WARN);
}
} else if (event.getEventID().startsWith(BLOCK_LEVEL_EVENT_ID_PREFIX)) {
Boolean canRecover = (Boolean)event.getParam("canRecover");
if (Boolean.TRUE.equals(canRecover)) {
//Reduce severity if FOP can recover
event.setSeverity(EventSeverity.WARN);
}
}
this.delegate.processEvent(event);
}

}

+ 37
- 0
src/java/org/apache/fop/events/FOPEventModelFactory.java View File

@@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import org.apache.fop.events.model.AbstractEventModelFactory;
import org.apache.fop.events.model.EventModel;

/**
* Factory for FOP's main event model.
*/
public class FOPEventModelFactory extends AbstractEventModelFactory {

private static final String EVENT_MODEL_FILENAME = "event-model.xml";

/** {@inheritDoc} */
public EventModel createEventModel() {
return loadModel(getClass(), EVENT_MODEL_FILENAME);
}

}

+ 92
- 0
src/java/org/apache/fop/events/LoggingEventListener.java View File

@@ -0,0 +1,92 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.events.model.EventSeverity;

/**
* EventListener implementation that redirects events to Commons Logging. The events are
* converted to localized messages.
*/
public class LoggingEventListener implements EventListener {

/** Default logger instance */
private static Log defaultLog = LogFactory.getLog(LoggingEventListener.class);
private Log log;
private boolean skipFatal;
/**
* Creates an instance logging to the default log category of this class.
*/
public LoggingEventListener() {
this(defaultLog);
}
/**
* Creates an instance logging to a given logger. Events with fatal severity level will be
* skipped.
* @param log the target logger
*/
public LoggingEventListener(Log log) {
this(log, true);
}
/**
* Creates an instance logging to a given logger.
* @param log the target logger
* @param skipFatal true if events with fatal severity level should be skipped (i.e. not logged)
*/
public LoggingEventListener(Log log, boolean skipFatal) {
this.log = log;
this.skipFatal = skipFatal;
}
/**
* Returns the target logger for this instance.
* @return the target logger
*/
public Log getLog() {
return this.log;
}
/** {@inheritDoc} */
public void processEvent(Event event) {
String msg = EventFormatter.format(event);
EventSeverity severity = event.getSeverity();
if (severity == EventSeverity.INFO) {
log.info(msg);
} else if (severity == EventSeverity.WARN) {
log.warn(msg);
} else if (severity == EventSeverity.ERROR) {
log.error(msg);
} else if (severity == EventSeverity.FATAL) {
if (!skipFatal) {
log.fatal(msg);
}
} else {
assert false;
}
}

}

+ 47
- 0
src/java/org/apache/fop/events/PropertyExceptionFactory.java View File

@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Locale;

import org.apache.fop.events.EventExceptionManager.ExceptionFactory;
import org.apache.fop.fo.expr.PropertyException;

/**
* Exception factory for {@link PropertyException}.
*/
public class PropertyExceptionFactory implements ExceptionFactory {

/** {@inheritDoc} */
public Throwable createException(Event event) {
String msg = EventFormatter.format(event, Locale.ENGLISH);
PropertyException ex = new PropertyException(msg);
if (!Locale.ENGLISH.equals(Locale.getDefault())) {
ex.setLocalizedMessage(EventFormatter.format(event));
}
return ex;
}
/** {@inheritDoc} */
public Class getExceptionClass() {
return PropertyException.class;
}
}

+ 136
- 0
src/java/org/apache/fop/events/ResourceEventProducer.java View File

@@ -0,0 +1,136 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.w3c.dom.Document;

import org.xml.sax.Locator;

import org.apache.xmlgraphics.image.loader.ImageException;

/**
* Event producer interface for resource events (missing images, fonts etc.).
*/
public interface ResourceEventProducer extends EventProducer {

/**
* Provider class for the event producer.
*/
class Provider {
/**
* Returns an event producer.
* @param broadcaster the event broadcaster to use
* @return the requested event producer
*/
public static ResourceEventProducer get(EventBroadcaster broadcaster) {
return (ResourceEventProducer)broadcaster.getEventProducerFor(
ResourceEventProducer.class);
}
}

/**
* Image not found.
* @param source the event source
* @param uri the original URI of the image
* @param fnfe the "file not found" exception
* @param loc the location of the error or null
* @event.severity ERROR
*/
void imageNotFound(Object source, String uri, FileNotFoundException fnfe, Locator loc);
/**
* Error while processing image.
* @param source the event source
* @param uri the original URI of the image
* @param e the image exception
* @param loc the location of the error or null
* @event.severity ERROR
*/
void imageError(Object source, String uri, ImageException e, Locator loc);
/**
* I/O error while loading an image.
* @param source the event source
* @param uri the original URI of the image
* @param ioe the I/O exception
* @param loc the location of the error or null
* @event.severity ERROR
*/
void imageIOError(Object source, String uri, IOException ioe, Locator loc);

/**
* Error while writing/serializing an image to an output format.
* @param source the event source
* @param e the original exception
* @event.severity ERROR
*/
void imageWritingError(Object source, Exception e);

/**
* Error while handling a URI.
* @param source the event source
* @param uri the original URI of the image
* @param e the original exception
* @param loc the location of the error or null
* @event.severity ERROR
*/
void uriError(Object source, String uri, Exception e, Locator loc);

/**
* Intrinsic size of fo:instream-foreign-object could not be determined.
* @param source the event source
* @param loc the location of the error or null
* @event.severity ERROR
*/
void ifoNoIntrinsicSize(Object source, Locator loc);
/**
* Error processing foreign XML content.
* @param source the event source
* @param doc the foreign XML
* @param namespaceURI the namespace URI of the foreign XML
* @param e the original exception
* @event.severity ERROR
*/
void foreignXMLProcessingError(Object source, Document doc, String namespaceURI, Exception e);

/**
* No handler for foreign XML content.
* @param source the event source
* @param doc the foreign XML
* @param namespaceURI the namespace URI of the foreign XML
* @event.severity ERROR
*/
void foreignXMLNoHandler(Object source, Document doc, String namespaceURI);
/**
* Cannot delete a temporary file.
* @param source the event source
* @param tempFile the temporary file
* @event.severity ERROR
*/
void cannotDeleteTempFile(Object source, File tempFile);
}

+ 43
- 0
src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java View File

@@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Locale;

import org.apache.fop.events.EventExceptionManager.ExceptionFactory;

/**
* Exception factory for {@link UnsupportedOperationException}.
*/
public class UnsupportedOperationExceptionFactory implements ExceptionFactory {

/** {@inheritDoc} */
public Throwable createException(Event event) {
String msg = EventFormatter.format(event, Locale.ENGLISH);
UnsupportedOperationException ex = new UnsupportedOperationException(msg);
return ex;
}
/** {@inheritDoc} */
public Class getExceptionClass() {
return UnsupportedOperationException.class;
}
}

+ 51
- 0
src/java/org/apache/fop/events/ValidationExceptionFactory.java View File

@@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events;

import java.util.Locale;

import org.xml.sax.Locator;

import org.apache.fop.events.EventExceptionManager.ExceptionFactory;
import org.apache.fop.fo.ValidationException;

/**
* Exception factory for {@link ValidationException}.
*/
public class ValidationExceptionFactory implements ExceptionFactory {

/** {@inheritDoc} */
public Throwable createException(Event event) {
Locator loc = (Locator)event.getParam("loc");
String msg = EventFormatter.format(event, Locale.ENGLISH);
ValidationException ex = new ValidationException(msg, loc);
if (!Locale.ENGLISH.equals(Locale.getDefault())) {
ex.setLocalizedMessage(EventFormatter.format(event));
}
return ex;
}
/** {@inheritDoc} */
public Class getExceptionClass() {
return ValidationException.class;
}
}

+ 61
- 0
src/java/org/apache/fop/events/model/AbstractEventModelFactory.java View File

@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.io.InputStream;
import java.util.MissingResourceException;

import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.io.IOUtils;

import org.apache.fop.events.DefaultEventBroadcaster;

/**
* This interface is used to instantiate (load, parse) event models.
*/
public abstract class AbstractEventModelFactory implements EventModelFactory {

/**
* Loads an event model and returns its instance.
* @param resourceBaseClass base class to use for loading resources
* @param resourceName the resource name pointing to the event model to be loaded
* @return the newly loaded event model.
*/
public EventModel loadModel(Class resourceBaseClass, String resourceName) {
InputStream in = resourceBaseClass.getResourceAsStream(resourceName);
if (in == null) {
throw new MissingResourceException(
"File " + resourceName + " not found",
DefaultEventBroadcaster.class.getName(), "");
}
try {
return EventModelParser.parse(new StreamSource(in));
} catch (TransformerException e) {
throw new MissingResourceException(
"Error reading " + resourceName + ": " + e.getMessage(),
DefaultEventBroadcaster.class.getName(), "");
} finally {
IOUtils.closeQuietly(in);
}
}
}

+ 198
- 0
src/java/org/apache/fop/events/model/EventMethodModel.java View File

@@ -0,0 +1,198 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.xmlgraphics.util.XMLizable;

/**
* Represents an event method. Each method in an event producer interface will result in one
* instance of <code>EventMethodModel</code>.
*/
public class EventMethodModel implements Serializable, XMLizable {

private static final long serialVersionUID = -7548882973341444354L;
private String methodName;
private EventSeverity severity;
private List params = new java.util.ArrayList();
private String exceptionClass;
/**
* Creates an new instance.
* @param methodName the event method's name
* @param severity the event severity
*/
public EventMethodModel(String methodName, EventSeverity severity) {
this.methodName = methodName;
this.severity = severity;
}
/**
* Adds a method parameter.
* @param param the method parameter
*/
public void addParameter(Parameter param) {
this.params.add(param);
}
/**
* Adds a method parameter.
* @param type the type of the parameter
* @param name the name of the parameter
* @return the resulting Parameter instance
*/
public Parameter addParameter(Class type, String name) {
Parameter param = new Parameter(type, name);
addParameter(param);
return param;
}
/**
* Sets the event method name.
* @param name the event name
*/
public void setMethodName(String name) {
this.methodName = name;
}
/**
* Returns the event method name
* @return the event name
*/
public String getMethodName() {
return this.methodName;
}
/**
* Sets the event's severity level.
* @param severity the severity
*/
public void setSeverity(EventSeverity severity) {
this.severity = severity;
}
/**
* Returns the event's severity level.
* @return the severity
*/
public EventSeverity getSeverity() {
return this.severity;
}
/**
* Returns an unmodifiable list of parameters for this event method.
* @return the list of parameters
*/
public List getParameters() {
return Collections.unmodifiableList(this.params);
}
/**
* Sets the primary exception class for this event method. Note: Not all event methods throw
* exceptions!
* @param exceptionClass the exception class
*/
public void setExceptionClass(String exceptionClass) {
this.exceptionClass = exceptionClass;
}
/**
* Returns the primary exception class for this event method. This method returns null if
* the event is only informational or just a warning.
* @return the primary exception class or null
*/
public String getExceptionClass() {
return this.exceptionClass;
}
/** {@inheritDoc} */
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, "name", "name", "CDATA", getMethodName());
atts.addAttribute(null, "severity", "severity", "CDATA", getSeverity().getName());
if (getExceptionClass() != null) {
atts.addAttribute(null, "exception", "exception", "CDATA", getExceptionClass());
}
String elName = "method";
handler.startElement(null, elName, elName, atts);
Iterator iter = this.params.iterator();
while (iter.hasNext()) {
((XMLizable)iter.next()).toSAX(handler);
}
handler.endElement(null, elName, elName);
}
/**
* Represents an event parameter.
*/
public static class Parameter implements Serializable, XMLizable {
private static final long serialVersionUID = 6062500277953887099L;
private Class type;
private String name;
/**
* Creates a new event parameter.
* @param type the parameter type
* @param name the parameter name
*/
public Parameter(Class type, String name) {
this.type = type;
this.name = name;
}
/**
* Returns the parameter type.
* @return the parameter type
*/
public Class getType() {
return this.type;
}
/**
* Returns the parameter name.
* @return the parameter name
*/
public String getName() {
return this.name;
}

/** {@inheritDoc} */
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, "type", "type", "CDATA", getType().getName());
atts.addAttribute(null, "name", "name", "CDATA", getName());
String elName = "parameter";
handler.startElement(null, elName, elName, atts);
handler.endElement(null, elName, elName);
}
}
}

+ 135
- 0
src/java/org/apache/fop/events/model/EventModel.java View File

@@ -0,0 +1,135 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.xmlgraphics.util.XMLizable;

/**
* Represents a whole event model that supports multiple event producers.
*/
public class EventModel implements Serializable, XMLizable {

private static final long serialVersionUID = 7468592614934605082L;
private Map producers = new java.util.LinkedHashMap();
/**
* Creates a new, empty event model
*/
public EventModel() {
}
/**
* Adds the model of an event producer to the event model.
* @param producer the event producer model
*/
public void addProducer(EventProducerModel producer) {
this.producers.put(producer.getInterfaceName(), producer);
}
/**
* Returns an iterator over the contained event producer models.
* @return an iterator (Iterator&lt;EventProducerModel&gt;)
*/
public Iterator getProducers() {
return this.producers.values().iterator();
}

/**
* Returns the model of an event producer with the given interface name.
* @param interfaceName the fully qualified name of the event producer
* @return the model instance for the event producer (or null if it wasn't found)
*/
public EventProducerModel getProducer(String interfaceName) {
return (EventProducerModel)this.producers.get(interfaceName);
}
/**
* Returns the model of an event producer with the given interface.
* @param clazz the interface of the event producer
* @return the model instance for the event producer (or null if it wasn't found)
*/
public EventProducerModel getProducer(Class clazz) {
return getProducer(clazz.getName());
}
/** {@inheritDoc} */
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();
String elName = "event-model";
handler.startElement(null, elName, elName, atts);
Iterator iter = getProducers();
while (iter.hasNext()) {
((XMLizable)iter.next()).toSAX(handler);
}
handler.endElement(null, elName, elName);
}

private void writeXMLizable(XMLizable object, File outputFile) throws IOException {
Result res = new StreamResult(outputFile);
try {
SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();
TransformerHandler handler = tFactory.newTransformerHandler();
Transformer transformer = handler.getTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
handler.setResult(res);
handler.startDocument();
object.toSAX(handler);
handler.endDocument();
} catch (TransformerConfigurationException e) {
throw new IOException(e.getMessage());
} catch (TransformerFactoryConfigurationError e) {
throw new IOException(e.getMessage());
} catch (SAXException e) {
throw new IOException(e.getMessage());
}
}

/**
* Saves this event model to an XML file.
* @param modelFile the target file
* @throws IOException if an I/O error occurs
*/
public void saveToXML(File modelFile) throws IOException {
writeXMLizable(this, modelFile);
}

}

+ 33
- 0
src/java/org/apache/fop/events/model/EventModelFactory.java View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

/**
* This interface is used to instantiate (load, parse) event models.
*/
public interface EventModelFactory {

/**
* Creates a new EventModel instance.
* @return the new EventModel instance
*/
EventModel createEventModel();
}

+ 140
- 0
src/java/org/apache/fop/events/model/EventModelParser.java View File

@@ -0,0 +1,140 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.util.Stack;

import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.util.DefaultErrorListener;

/**
* This is a parser for the event model XML.
*/
public class EventModelParser {

/** Logger instance */
protected static Log log = LogFactory.getLog(EventModelParser.class);

private static SAXTransformerFactory tFactory
= (SAXTransformerFactory)SAXTransformerFactory.newInstance();

/**
* Parses an event model file into an EventModel instance.
* @param src the Source instance pointing to the XML file
* @return the created event model structure
* @throws TransformerException if an error occurs while parsing the XML file
*/
public static EventModel parse(Source src)
throws TransformerException {
Transformer transformer = tFactory.newTransformer();
transformer.setErrorListener(new DefaultErrorListener(log));
EventModel model = new EventModel();
SAXResult res = new SAXResult(getContentHandler(model));

transformer.transform(src, res);
return model;
}

/**
* Creates a new ContentHandler instance that you can send the event model XML to. The parsed
* content is accumulated in the model structure.
* @param model the EventModel
* @return the ContentHandler instance to receive the SAX stream from the XML file
*/
public static ContentHandler getContentHandler(EventModel model) {
return new Handler(model);
}

private static class Handler extends DefaultHandler {

private EventModel model;
private Stack objectStack = new Stack();

public Handler(EventModel model) {
this.model = model;
}

/** {@inheritDoc} */
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
try {
if ("event-model".equals(localName)) {
if (objectStack.size() > 0) {
throw new SAXException("event-model must be the root element");
}
objectStack.push(model);
} else if ("producer".equals(localName)) {
EventProducerModel producer = new EventProducerModel(
attributes.getValue("name"));
EventModel parent = (EventModel)objectStack.peek();
parent.addProducer(producer);
objectStack.push(producer);
} else if ("method".equals(localName)) {
EventSeverity severity = EventSeverity.valueOf(attributes.getValue("severity"));
String ex = attributes.getValue("exception");
EventMethodModel method = new EventMethodModel(
attributes.getValue("name"), severity);
if (ex != null && ex.length() > 0) {
method.setExceptionClass(ex);
}
EventProducerModel parent = (EventProducerModel)objectStack.peek();
parent.addMethod(method);
objectStack.push(method);
} else if ("parameter".equals(localName)) {
String className = attributes.getValue("type");
Class type;
try {
type = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new SAXException("Could not find Class for: " + className, e);
}
String name = attributes.getValue("name");
EventMethodModel parent = (EventMethodModel)objectStack.peek();
objectStack.push(parent.addParameter(type, name));
} else {
throw new SAXException("Invalid element: " + qName);
}
} catch (ClassCastException cce) {
throw new SAXException("XML format error: " + qName, cce);
}
}

/** {@inheritDoc} */
public void endElement(String uri, String localName, String qName) throws SAXException {
objectStack.pop();
}

}

}

+ 105
- 0
src/java/org/apache/fop/events/model/EventProducerModel.java View File

@@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import org.apache.xmlgraphics.util.XMLizable;

/**
* Represents the model of an event producer with multiple event methods.
*/
public class EventProducerModel implements Serializable, XMLizable {

private static final long serialVersionUID = 122267104123721902L;
private String interfaceName;
private Map methods = new java.util.LinkedHashMap();
/**
* Creates a new instance.
* @param interfaceName the fully qualified interface name of the event producer
*/
public EventProducerModel(String interfaceName) {
this.interfaceName = interfaceName;
}
/**
* Returns the fully qualified interface name of the event producer.
* @return the fully qualified interface name
*/
public String getInterfaceName() {
return this.interfaceName;
}
/**
* Sets the fully qualified interface name of the event producer.
* @param name the fully qualified interface name
*/
public void setInterfaceName(String name) {
this.interfaceName = name;
}
/**
* Adds a model instance of an event method.
* @param method the event method model
*/
public void addMethod(EventMethodModel method) {
this.methods.put(method.getMethodName(), method);
}
/**
* Returns the model instance of an event method for the given method name.
* @param methodName the method name
* @return the model instance (or null if no method with the given name exists)
*/
public EventMethodModel getMethod(String methodName) {
return (EventMethodModel)this.methods.get(methodName);
}
/**
* Returns an iterator over the contained event producer methods.
* @return an iterator (Iterator&lt;EventMethodModel&gt;)
*/
public Iterator getMethods() {
return this.methods.values().iterator();
}

/** {@inheritDoc} */
public void toSAX(ContentHandler handler) throws SAXException {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(null, "name", "name", "CDATA", getInterfaceName());
String elName = "producer";
handler.startElement(null, elName, elName, atts);
Iterator iter = getMethods();
while (iter.hasNext()) {
((XMLizable)iter.next()).toSAX(handler);
}
handler.endElement(null, elName, elName);
}

}

+ 82
- 0
src/java/org/apache/fop/events/model/EventSeverity.java View File

@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.events.model;

import java.io.ObjectStreamException;
import java.io.Serializable;

/** Enumeration class for event severities. */
public final class EventSeverity implements Serializable {

private static final long serialVersionUID = 4108175215810759243L;
/** info level */
public static final EventSeverity INFO = new EventSeverity("INFO");
/** warning level */
public static final EventSeverity WARN = new EventSeverity("WARN");
/** error level */
public static final EventSeverity ERROR = new EventSeverity("ERROR");
/** fatal error */
public static final EventSeverity FATAL = new EventSeverity("FATAL");
private String name;

/**
* Constructor to add a new named item.
* @param name Name of the item.
*/
private EventSeverity(String name) {
this.name = name;
}

/** @return the name of the enumeration */
public String getName() {
return this.name;
}
/**
* Returns the enumeration/singleton object based on its name.
* @param name the name of the enumeration value
* @return the enumeration object
*/
public static EventSeverity valueOf(String name) {
if (INFO.getName().equalsIgnoreCase(name)) {
return INFO;
} else if (WARN.getName().equalsIgnoreCase(name)) {
return WARN;
} else if (ERROR.getName().equalsIgnoreCase(name)) {
return ERROR;
} else if (FATAL.getName().equalsIgnoreCase(name)) {
return FATAL;
} else {
throw new IllegalArgumentException("Illegal value for enumeration: " + name);
}
}
private Object readResolve() throws ObjectStreamException {
return valueOf(getName());
}
/** {@inheritDoc} */
public String toString() {
return "EventSeverity:" + name;
}
}

+ 2
- 1
src/java/org/apache/fop/fo/ElementMapping.java View File

@@ -24,9 +24,10 @@ import java.util.HashMap;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.fop.util.QName;
import org.w3c.dom.DOMImplementation;

import org.apache.xmlgraphics.util.QName;

/**
* Abstract base class for Element Mappings (including FO Element Mappings)
* which provide the framework of valid elements and attibutes for a given

+ 1
- 1
src/java/org/apache/fop/fo/ElementMappingRegistry.java View File

@@ -23,6 +23,7 @@ import java.util.Iterator;
import java.util.Map;

import org.w3c.dom.DOMImplementation;

import org.xml.sax.Locator;

import org.apache.commons.logging.Log;
@@ -144,7 +145,6 @@ public class ElementMappingRegistry {
+ "No element mapping definition found for "
+ FONode.getNodeString(namespaceURI, localName), locator);
} else {
log.warn("Unknown formatting object " + namespaceURI + "^" + localName);
fobjMaker = new UnknownXMLObj.Maker(namespaceURI);
}
}

+ 1
- 1
src/java/org/apache/fop/fo/FOElementMapping.java View File

@@ -22,7 +22,7 @@ package org.apache.fop.fo;
// Java
import java.util.HashMap;

import org.apache.fop.util.QName;
import org.apache.xmlgraphics.util.QName;

/**
* Element mapping class for all XSL-FO elements.

+ 2
- 0
src/java/org/apache/fop/fo/FOEventHandler.java View File

@@ -48,6 +48,7 @@ import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fonts.FontEventAdapter;
import org.apache.fop.fonts.FontInfo;

/**
@@ -101,6 +102,7 @@ public abstract class FOEventHandler {
public FOEventHandler(FOUserAgent foUserAgent) {
this.foUserAgent = foUserAgent;
this.fontInfo = new FontInfo();
this.fontInfo.setEventListener(new FontEventAdapter(foUserAgent.getEventBroadcaster()));
}

/**

+ 126
- 46
src/java/org/apache/fop/fo/FONode.java View File

@@ -21,6 +21,8 @@ package org.apache.fop.fo;

// Java
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
@@ -29,6 +31,8 @@ import org.xml.sax.helpers.LocatorImpl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fo.extensions.ExtensionAttachment;
@@ -37,6 +41,7 @@ import org.apache.fop.fo.extensions.svg.SVGElementMapping;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.util.CharUtilities;
import org.apache.fop.util.ContentHandlerFactory;
import org.apache.fop.util.text.AdvancedMessageFormat.Function;

/**
* Base class for nodes in the XML tree
@@ -143,6 +148,10 @@ public abstract class FONode implements Cloneable {
return parent.getFOEventHandler();
}
/**
* Indicates whether this node is a child of an fo:marker.
* @return true if this node is a child of an fo:marker
*/
protected boolean inMarker() {
return getFOEventHandler().inMarker();
}
@@ -239,7 +248,7 @@ public abstract class FONode implements Cloneable {
* @param start starting array element to add
* @param end ending array element to add
* @param pList currently applicable PropertyList
* @param locator location in fo source file.
* @param locator location in the XSL-FO source file.
* @throws FOPException if there's a problem during processing
*/
protected void addCharacters(char[] data, int start, int end,
@@ -343,54 +352,50 @@ public abstract class FONode implements Cloneable {
}

/**
* Helper function to standardize property error exceptions
* (e.g., not specifying either an internal- or an external-destination
* property for an FO:link)
* @param problem text to display that indicates the problem
* @throws ValidationException the validation error provoked by the method call
* Returns an instance of the FOValidationEventProducer.
* @return an event producer for FO validation
*/
protected void attributeError(String problem)
throws ValidationException {
throw new ValidationException(errorText(locator) + getName()
+ ", " + problem, locator);
protected FOValidationEventProducer getFOValidationEventProducer() {
return FOValidationEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
}
/**
* Helper function to standardize attribute warnings
* (e.g., currently unsupported properties)
* @param problem text to display that indicates the problem
* Helper function to standardize "too many" error exceptions
* (e.g., two fo:declarations within fo:root)
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param nsURI namespace URI of incoming invalid node
* @param lName local name (i.e., no prefix) of incoming node
* @throws ValidationException the validation error provoked by the method call
*/
public void attributeWarning(String problem) {
log.warn(warningText(locator) + getName() + ", " + problem);
protected void tooManyNodesError(Locator loc, String nsURI, String lName)
throws ValidationException {
tooManyNodesError(loc, new QName(nsURI, lName));
}

/**
* Helper function to standardize "too many" error exceptions
* (e.g., two fo:declarations within fo:root)
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param nsURI namespace URI of incoming invalid node
* @param lName local name (i.e., no prefix) of incoming node
* @param offendingNode the qualified name of the offending node
* @throws ValidationException the validation error provoked by the method call
*/
protected void tooManyNodesError(Locator loc, String nsURI, String lName)
protected void tooManyNodesError(Locator loc, QName offendingNode)
throws ValidationException {
throw new ValidationException(errorText(loc) + "For " + getName()
+ ", only one " + getNodeString(nsURI, lName) + " may be declared.",
loc);
getFOValidationEventProducer().tooManyNodes(this, getName(), offendingNode, loc);
}

/**
* Helper function to standardize "too many" error exceptions
* (e.g., two fo:declarations within fo:root)
* This overrloaded method helps make the caller code better self-documenting
* This overloaded method helps make the caller code better self-documenting
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param offendingNode incoming node that would cause a duplication.
* @throws ValidationException the validation error provoked by the method call
*/
protected void tooManyNodesError(Locator loc, String offendingNode)
throws ValidationException {
throw new ValidationException(errorText(loc) + "For " + getName()
+ ", only one " + offendingNode + " may be declared.", loc);
tooManyNodesError(loc, new QName(FO_URI, offendingNode));
}

/**
@@ -402,9 +407,23 @@ public abstract class FONode implements Cloneable {
* @throws ValidationException the validation error provoked by the method call
*/
protected void nodesOutOfOrderError(Locator loc, String tooLateNode,
String tooEarlyNode) throws ValidationException {
throw new ValidationException(errorText(loc) + "For " + getName() + ", " + tooLateNode
+ " must be declared before " + tooEarlyNode + ".", loc);
String tooEarlyNode) throws ValidationException {
nodesOutOfOrderError(loc, tooLateNode, tooEarlyNode, false);
}
/**
* Helper function to standardize "out of order" exceptions
* (e.g., fo:layout-master-set appearing after fo:page-sequence)
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param tooLateNode string name of node that should be earlier in document
* @param tooEarlyNode string name of node that should be later in document
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @throws ValidationException the validation error provoked by the method call
*/
protected void nodesOutOfOrderError(Locator loc, String tooLateNode,
String tooEarlyNode, boolean canRecover) throws ValidationException {
getFOValidationEventProducer().nodeOutOfOrder(this, getName(),
tooLateNode, tooEarlyNode, canRecover, loc);
}
/**
@@ -417,24 +436,24 @@ public abstract class FONode implements Cloneable {
*/
protected void invalidChildError(Locator loc, String nsURI, String lName)
throws ValidationException {
invalidChildError(loc, nsURI, lName, null);
invalidChildError(loc, getName(), nsURI, lName, null);
}
/**
* Helper function to return "invalid child" exceptions with more
* complex validation rules (i.e., needing more explanation of the problem)
* @param loc org.xml.sax.Locator object of the error (*not* parent node)
* @param parentName the name of the parent element
* @param nsURI namespace URI of incoming invalid node
* @param lName local name (i.e., no prefix) of incoming node
* @param ruleViolated text explanation of problem
* @param ruleViolated name of the rule violated (used to lookup a resource in a bundle)
* @throws ValidationException the validation error provoked by the method call
*/
protected void invalidChildError(Locator loc, String nsURI, String lName,
protected void invalidChildError(Locator loc, String parentName, String nsURI, String lName,
String ruleViolated)
throws ValidationException {
throw new ValidationException(errorText(loc) + getNodeString(nsURI, lName)
+ " is not a valid child element of " + getName()
+ ((ruleViolated != null) ? ": " + ruleViolated : "."), loc);
getFOValidationEventProducer().invalidChild(this, parentName,
new QName(nsURI, lName), ruleViolated, loc);
}

/**
@@ -446,9 +465,22 @@ public abstract class FONode implements Cloneable {
*/
protected void missingChildElementError(String contentModel)
throws ValidationException {
throw new ValidationException(errorText(locator) + getName()
+ " is missing child elements. \nRequired Content Model: "
+ contentModel, locator);
getFOValidationEventProducer().missingChildElement(this, getName(),
contentModel, false, locator);
}

/**
* Helper function to throw an error caused by missing mandatory child elements.
* E.g., fo:layout-master-set not having any page-master child element.
* @param contentModel The XSL Content Model for the fo: object or a similar description
* indicating the necessary child elements.
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @throws ValidationException the validation error provoked by the method call
*/
protected void missingChildElementError(String contentModel, boolean canRecover)
throws ValidationException {
getFOValidationEventProducer().missingChildElement(this, getName(),
contentModel, canRecover, locator);
}

/**
@@ -458,8 +490,7 @@ public abstract class FONode implements Cloneable {
*/
protected void missingPropertyError(String propertyName)
throws ValidationException {
throw new ValidationException(errorText(locator) + getName()
+ " is missing required \"" + propertyName + "\" property.", locator);
getFOValidationEventProducer().missingProperty(this, getName(), propertyName, locator);
}

/**
@@ -513,9 +544,10 @@ public abstract class FONode implements Cloneable {
/**
* Returns a String containing as much context information as possible about a node. Call
* this methods only in exceptional conditions because this method may perform quite extensive
* this method only in exceptional conditions because this method may perform quite extensive
* information gathering inside the FO tree.
* @return a String containing
* @return a String containing context information
* @deprecated Not localized! Should rename getContextInfoAlt() to getContextInfo() when done!
*/
public String getContextInfo() {
StringBuffer sb = new StringBuffer();
@@ -542,6 +574,54 @@ public abstract class FONode implements Cloneable {
return sb.toString();
}
/**
* Returns a String containing as some context information about a node. It does not take the
* locator into consideration and returns null if no useful context information can be found.
* Call this method only in exceptional conditions because this method may perform quite
* extensive information gathering inside the FO tree. All text returned by this method that
* is not extracted from document content needs to be locale-independent.
* @return a String containing context information
*/
protected String getContextInfoAlt() {
String s = gatherContextInfo();
if (s != null) {
StringBuffer sb = new StringBuffer();
if (getLocalName() != null) {
sb.append(getName());
sb.append(", ");
}
sb.append("\"");
sb.append(s);
sb.append("\"");
return sb.toString();
} else {
return null;
}
}
/** Function for AdvancedMessageFormat to retrieve context info from an FONode. */
public static class GatherContextInfoFunction implements Function {

/** {@inheritDoc} */
public Object evaluate(Map params) {
Object obj = params.get("source");
if (obj instanceof PropertyList) {
PropertyList propList = (PropertyList)obj;
obj = propList.getFObj();
}
if (obj instanceof FONode) {
FONode node = (FONode)obj;
return node.getContextInfoAlt();
}
return null;
}

/** {@inheritDoc} */
public Object getName() {
return "gatherContextInfo";
}
}
/**
* Gathers context information for the getContextInfo() method.
* @return the collected context information or null, if none is available
@@ -687,7 +767,7 @@ public abstract class FONode implements Cloneable {
* of child nodes
* @return the parent node
*/
public FObj parentNode();
FObj parentNode();
/**
* Convenience method with return type of FONode
@@ -695,7 +775,7 @@ public abstract class FONode implements Cloneable {
* <code>(FONode) next();</code>)
* @return the next node (if any), as a type FONode
*/
public FONode nextNode();
FONode nextNode();
/**
* Convenience method with return type of FONode
@@ -703,7 +783,7 @@ public abstract class FONode implements Cloneable {
* <code>(FONode) previous();</code>)
* @return the previous node (if any), as a type FONode
*/
public FONode previousNode();
FONode previousNode();
/**
* Returns the first node in the list, and decreases the index,
@@ -711,7 +791,7 @@ public abstract class FONode implements Cloneable {
* @return the first node in the list
* @throws NoSuchElementException if the list is empty
*/
public FONode firstNode();
FONode firstNode();
/**
* Returns the last node in the list, and advances the
@@ -720,7 +800,7 @@ public abstract class FONode implements Cloneable {
* @return the last node in the list
* @throws NoSuchElementException if the list is empty
*/
public FONode lastNode();
FONode lastNode();

}
}

+ 3
- 6
src/java/org/apache/fop/fo/FOText.java View File

@@ -19,11 +19,11 @@

package org.apache.fop.fo;

// Java
import java.awt.Color;
import java.util.NoSuchElementException;

// FOP
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.flow.Block;
@@ -34,9 +34,6 @@ import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.SpaceProperty;

// SAX
import org.xml.sax.Locator;

/**
* A text node (PCDATA) in the formatting object tree.
*
@@ -396,7 +393,7 @@ public class FOText extends FONode {
return ca[i];
}
default:
log.warn("Invalid text-tranform value: " + textTransform);
assert false; //should never happen as the property subsystem catches that case
return ca[i];
}
}

+ 40
- 27
src/java/org/apache/fop/fo/FOTreeBuilder.java View File

@@ -31,6 +31,8 @@ import org.xml.sax.helpers.DefaultHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FormattingResults;
@@ -130,6 +132,7 @@ public class FOTreeBuilder extends DefaultHandler {
throw new IllegalStateException("FOTreeBuilder (and the Fop class) cannot be reused."
+ " Please instantiate a new instance.");
}
used = true;
empty = true;
rootFObj = null; // allows FOTreeBuilder to be reused
@@ -146,8 +149,10 @@ public class FOTreeBuilder extends DefaultHandler {
public void endDocument() throws SAXException {
this.delegate.endDocument();
if (this.rootFObj == null && empty) {
throw new ValidationException(
"Document is empty (something might be wrong with your XSLT stylesheet).");
FOValidationEventProducer eventProducer
= FOValidationEventProducer.Provider.get(
foEventHandler.getUserAgent().getEventBroadcaster());
eventProducer.emptyDocument(this);
}
rootFObj = null;
if (log.isDebugEnabled()) {
@@ -178,18 +183,6 @@ public class FOTreeBuilder extends DefaultHandler {
}
}

/**
* Finds the {@link Maker} used to create {@link FONode} objects of a particular type
*
* @param namespaceURI URI for the namespace of the element
* @param localName name of the Element
* @return the ElementMapping.Maker that can create an FO object for this element
* @throws FOPException if a Maker could not be found for a bound namespace.
*/
private Maker findFOMaker(String namespaceURI, String localName) throws FOPException {
return elementMappingRegistry.findFOMaker(namespaceURI, localName, locator);
}

/** {@inheritDoc} */
public void warning(SAXParseException e) {
log.warn(e.getLocalizedMessage());
@@ -258,22 +251,21 @@ public class FOTreeBuilder extends DefaultHandler {
if (rootFObj == null) {
empty = false;
if (!namespaceURI.equals(FOElementMapping.URI)
|| !localName.equals("root")) {
throw new ValidationException(
"Error: First element must be the fo:root formatting object. "
+ "Found " + FONode.getNodeString(namespaceURI, localName)
+ " instead."
+ " Please make sure you're producing a valid XSL-FO document.");
|| !localName.equals("root")) {
FOValidationEventProducer eventProducer
= FOValidationEventProducer.Provider.get(
foEventHandler.getUserAgent().getEventBroadcaster());
eventProducer.invalidFORoot(this, FONode.getNodeString(namespaceURI, localName),
getEffectiveLocator());
}
} else { // check that incoming node is valid for currentFObj
if (namespaceURI.equals(FOElementMapping.URI)
|| namespaceURI.equals(ExtensionElementMapping.URI)) {
if (currentFObj.getNamespaceURI().equals(FOElementMapping.URI)
|| currentFObj.getNamespaceURI().equals(ExtensionElementMapping.URI)) {
currentFObj.validateChildNode(locator, namespaceURI, localName);
}
}
ElementMapping.Maker fobjMaker =
findFOMaker(namespaceURI, localName);
ElementMapping.Maker fobjMaker = findFOMaker(namespaceURI, localName);

try {
foNode = fobjMaker.make(currentFObj);
@@ -342,8 +334,7 @@ public class FOTreeBuilder extends DefaultHandler {
if (currentPropertyList != null
&& currentPropertyList.getFObj() == currentFObj
&& !foEventHandler.inMarker()) {
currentPropertyList =
currentPropertyList.getParentPropertyList();
currentPropertyList = currentPropertyList.getParentPropertyList();
}
if (currentFObj.getNameId() == Constants.FO_MARKER) {
@@ -373,7 +364,29 @@ public class FOTreeBuilder extends DefaultHandler {
/** {@inheritDoc} */
public void endDocument() throws SAXException {
currentFObj = null;
}
}
/**
* Finds the {@link Maker} used to create {@link FONode} objects of a particular type
*
* @param namespaceURI URI for the namespace of the element
* @param localName name of the Element
* @return the ElementMapping.Maker that can create an FO object for this element
* @throws FOPException if a Maker could not be found for a bound namespace.
*/
private Maker findFOMaker(String namespaceURI, String localName) throws FOPException {
Maker maker = elementMappingRegistry.findFOMaker(namespaceURI, localName, locator);
if (maker instanceof UnknownXMLObj.Maker) {
FOValidationEventProducer eventProducer
= FOValidationEventProducer.Provider.get(
foEventHandler.getUserAgent().getEventBroadcaster());
eventProducer.unknownFormattingObject(this, currentFObj.getName(),
new QName(namespaceURI, localName),
getEffectiveLocator());
}
return maker;
}

}
}


+ 348
- 0
src/java/org/apache/fop/fo/FOValidationEventProducer.java View File

@@ -0,0 +1,348 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.fo;

import org.xml.sax.Locator;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOPException;
import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventProducer;
import org.apache.fop.fo.expr.PropertyException;

/**
* Event producer interface for XSL-FO validation messages.
*/
public interface FOValidationEventProducer extends EventProducer {

/**
* Provider class for the event producer.
*/
class Provider {
/**
* Returns an event producer.
* @param broadcaster the event broadcaster to use
* @return the event producer
*/
public static FOValidationEventProducer get(EventBroadcaster broadcaster) {
return (FOValidationEventProducer)broadcaster.getEventProducerFor(
FOValidationEventProducer.class);
}
}

/**
* Too many child nodes.
* @param source the event source
* @param elementName the name of the context node
* @param offendingNode the offending node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void tooManyNodes(Object source, String elementName, QName offendingNode,
Locator loc) throws ValidationException;
/**
* The node order is wrong.
* @param source the event source
* @param elementName the name of the context node
* @param tooLateNode string name of node that should be earlier in document
* @param tooEarlyNode string name of node that should be later in document
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
*/
void nodeOutOfOrder(Object source, String elementName,
String tooLateNode, String tooEarlyNode, boolean canRecover,
Locator loc) throws ValidationException;
/**
* An invalid child was encountered.
* @param source the event source
* @param elementName the name of the context node
* @param offendingNode the offending node
* @param ruleViolated the rule that was violated or null
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
*/
void invalidChild(Object source, String elementName, QName offendingNode, String ruleViolated,
Locator loc) throws ValidationException;

/**
* A required child element is missing.
* @param source the event source
* @param elementName the name of the context node
* @param contentModel the expected content model
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void missingChildElement(Object source, String elementName,
String contentModel, boolean canRecover,
Locator loc) throws ValidationException;

/**
* An element is missing a required property.
* @param source the event source
* @param elementName the name of the context node
* @param propertyName the name of the missing property
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void missingProperty(Object source, String elementName, String propertyName,
Locator loc) throws ValidationException;
/**
* An id was used twice in a document.
* @param source the event source
* @param elementName the name of the context node
* @param id the id that was reused
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void idNotUnique(Object source, String elementName, String id, boolean canRecover,
Locator loc) throws ValidationException;

/**
* There are multiple color profiles defined with the same name.
* @param source the event source
* @param elementName the name of the context node
* @param name the duplicate color profile name
* @param loc the location of the error or null
* @event.severity WARN
*/
void colorProfileNameNotUnique(Object source, String elementName, String name,
Locator loc);

/**
* There are multiple page masters defined with the same name.
* @param source the event source
* @param elementName the name of the context node
* @param name the duplicate page master name
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void masterNameNotUnique(Object source, String elementName, String name,
Locator loc) throws ValidationException;

/**
* A marker is not an initial child on a node.
* @param source the event source
* @param elementName the name of the context node
* @param mcname the marker class name
* @param loc the location of the error or null
* @event.severity ERROR
*/
void markerNotInitialChild(Object source, String elementName, String mcname, Locator loc);

/**
* A marker class name is not unique within the same parent.
* @param source the event source
* @param elementName the name of the context node
* @param mcname the marker class name
* @param loc the location of the error or null
* @event.severity ERROR
*/
void markerNotUniqueForSameParent(Object source, String elementName,
String mcname, Locator loc);

/**
* An invalid property was found.
* @param source the event source
* @param elementName the name of the context node
* @param attr the invalid attribute
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void invalidProperty(Object source, String elementName, QName attr, boolean canRecover,
Locator loc) throws ValidationException;

/**
* An invalid property value was encountered.
* @param source the event source
* @param elementName the name of the context node
* @param propName the property name
* @param propValue the property value
* @param e the property exception caused by the invalid value
* @param loc the location of the error or null
* @event.severity ERROR
*/
void invalidPropertyValue(Object source, String elementName,
String propName, String propValue, PropertyException e,
Locator loc);

/**
* A feature is not supported, yet.
* @param source the event source
* @param elementName the name of the context node
* @param feature the unsupported feature
* @param loc the location of the error or null
* @event.severity WARN
*/
void unimplementedFeature(Object source, String elementName, String feature,
Locator loc);

/**
* Missing internal-/external-destination on basic-link or bookmark.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void missingLinkDestination(Object source, String elementName, Locator loc)
throws ValidationException;

/**
* Indicates a problem while cloning a marker (ex. due to invalid property values).
* @param source the event source
* @param markerClassName the "marker-class-name" of the marker
* @param fe the FOP exception that cause this problem
* @param loc the location of the error or null
* @event.severity ERROR
*/
void markerCloningFailed(Object source, String markerClassName, FOPException fe, Locator loc);

/**
* A region name is mapped to multiple region classes.
* @param source the event source
* @param regionName the region name
* @param defaultRegionClass1 the first default region class
* @param defaultRegionClass2 the second default region class
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void regionNameMappedToMultipleRegionClasses(Object source, String regionName,
String defaultRegionClass1, String defaultRegionClass2, Locator loc)
throws ValidationException;

/**
* There are multiple flows with the same name.
* @param source the event source
* @param elementName the name of the context node
* @param flowName the flow name
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void duplicateFlowNameInPageSequence(Object source, String elementName, String flowName,
Locator loc) throws ValidationException;

/**
* A flow name could not be mapped to a region.
* @param source the event source
* @param elementName the name of the context node
* @param flowName the flow name
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void flowNameNotMapped(Object source, String elementName, String flowName,
Locator loc) throws ValidationException;

/**
* A page master could not be found.
* @param source the event source
* @param elementName the name of the context node
* @param masterReference the page master reference
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void masterNotFound(Object source, String elementName, String masterReference,
Locator loc) throws ValidationException;

/**
* An illegal region name was used.
* @param source the event source
* @param elementName the name of the context node
* @param regionName the region name
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void illegalRegionName(Object source, String elementName, String regionName,
Locator loc) throws ValidationException;

/**
* A non-zero border and/or padding has been encountered on a region.
* @param source the event source
* @param elementName the name of the context node
* @param regionName the region name
* @param canRecover indicates whether FOP can recover from this problem and continue working
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void nonZeroBorderPaddingOnRegion(Object source, String elementName, String regionName,
boolean canRecover, Locator loc) throws ValidationException;

/**
* If overflow property is set to "scroll", a column-count other than "1" may not be specified.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void columnCountErrorOnRegionBodyOverflowScroll(Object source, String elementName,
Locator loc) throws ValidationException;

/**
* fo:root must be root.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void invalidFORoot(Object source, String elementName,
Locator loc) throws ValidationException;
/**
* No FO document was found.
* @param source the event source
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void emptyDocument(Object source) throws ValidationException;
/**
* An unknown/unsupported formatting object has been encountered.
* @param source the event source
* @param elementName the name of the context node
* @param offendingNode the offending node
* @param loc the location of the error or null
* @event.severity WARN
*/
void unknownFormattingObject(Object source, String elementName,
QName offendingNode, Locator loc);
}

+ 47
- 30
src/java/org/apache/fop/fo/FObj.java View File

@@ -27,13 +27,15 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.extensions.ExtensionAttachment;
import org.apache.fop.fo.flow.Marker;
import org.apache.fop.fo.properties.PropertyMaker;
import org.apache.fop.util.QName;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;

/**
* Base class for representation of formatting objects and their processing.
@@ -171,25 +173,7 @@ public abstract class FObj extends FONode implements Constants {
if (!idrefs.contains(id)) {
idrefs.add(id);
} else {
if (getUserAgent().validateStrictly()) {
throw new ValidationException("Property id \"" + id
+ "\" previously used; id values must be unique"
+ " in document.", locator);
} else {
if (log.isWarnEnabled()) {
StringBuffer msg = new StringBuffer();
msg.append("Found non-unique id on ").append(getName());
if (locator.getLineNumber() != -1) {
msg.append(" (at ").append(locator.getLineNumber())
.append("/").append(locator.getColumnNumber())
.append(")");
}
msg.append("\nAny reference to it will be considered "
+ "a reference to the first occurrence "
+ "in the document.");
log.warn(msg);
}
}
getFOValidationEventProducer().idNotUnique(this, getName(), id, true, locator);
}
}
}
@@ -283,16 +267,22 @@ public abstract class FObj extends FONode implements Constants {
return false;
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public FONodeIterator getChildNodes() {
if (firstChild != null) {
if (hasChildren()) {
return new FObjIterator(this);
}
return null;
}

/**
* Indicates whether this formatting object has children.
* @return true if there are children
*/
public boolean hasChildren() {
return this.firstChild != null;
}
/**
* Return an iterator over the object's childNodes starting
* at the passed-in node (= first call to iterator.next() will
@@ -348,8 +338,8 @@ public abstract class FObj extends FONode implements Constants {
if (node instanceof FObj
|| (node instanceof FOText
&& ((FOText) node).willCreateArea())) {
log.error(
"fo:marker must be an initial child: " + mcname);
getFOValidationEventProducer().markerNotInitialChild(this, getName(),
mcname, locator);
return;
} else if (node instanceof FOText) {
iter.remove();
@@ -363,8 +353,8 @@ public abstract class FObj extends FONode implements Constants {
if (!markers.containsKey(mcname)) {
markers.put(mcname, marker);
} else {
log.error("fo:marker 'marker-class-name' "
+ "must be unique for same parent: " + mcname);
getFOValidationEventProducer().markerNotUniqueForSameParent(this, getName(),
mcname, locator);
}
}

@@ -382,6 +372,33 @@ public abstract class FObj extends FONode implements Constants {
return markers;
}

/** {@inheritDoc} */
protected String getContextInfoAlt() {
StringBuffer sb = new StringBuffer();
if (getLocalName() != null) {
sb.append(getName());
sb.append(", ");
}
if (hasId()) {
sb.append("id=").append(getId());
return sb.toString();
}
String s = gatherContextInfo();
if (s != null) {
sb.append("\"");
if (s.length() < 32) {
sb.append(s);
} else {
sb.append(s.substring(0, 32));
sb.append("...");
}
sb.append("\"");
return sb.toString();
} else {
return null;
}
}
/** {@inheritDoc} */
protected String gatherContextInfo() {
if (getLocator() != null) {

+ 30
- 37
src/java/org/apache/fop/fo/PropertyList.java View File

@@ -20,13 +20,13 @@
package org.apache.fop.fo;

// Java
import java.text.MessageFormat;

import org.xml.sax.Attributes;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FopFactory;
import org.apache.fop.fo.expr.PropertyException;
import org.apache.fop.fo.properties.CommonAbsolutePosition;
@@ -41,7 +41,6 @@ import org.apache.fop.fo.properties.CommonRelativePosition;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.PropertyMaker;
import org.apache.fop.util.QName;

/**
* Class containing the collection of properties for a given FObj.
@@ -150,7 +149,7 @@ public abstract class PropertyList {
* the default value.
* @param propId The Constants ID of the property whose value is desired.
* @return the Property corresponding to that name
* @throws PropertyException ...
* @throws PropertyException if there is a problem evaluating the property
*/
public Property get(int propId) throws PropertyException {
return get(propId, true, true);
@@ -166,7 +165,7 @@ public abstract class PropertyList {
* value is needed
* @param bTryDefault true when the default value may be used as a last resort
* @return the property
* @throws PropertyException ...
* @throws PropertyException if there is a problem evaluating the property
*/
public Property get(int propId, boolean bTryInherit,
boolean bTryDefault) throws PropertyException {
@@ -321,20 +320,18 @@ public abstract class PropertyList {
} else if (!factory.isNamespaceIgnored(attributeNS)) {
ElementMapping mapping = factory.getElementMappingRegistry().getElementMapping(
attributeNS);
QName attr = new QName(attributeNS, attributeName);
if (mapping != null) {
QName attName = new QName(attributeNS, attributeName);
if (mapping.isAttributeProperty(attName)
if (mapping.isAttributeProperty(attr)
&& mapping.getStandardPrefix() != null) {
convertAttributeToProperty(attributes,
mapping.getStandardPrefix() + ":" + attName.getLocalName(),
mapping.getStandardPrefix() + ":" + attr.getLocalName(),
attributeValue);
} else {
getFObj().addForeignAttribute(attName, attributeValue);
getFObj().addForeignAttribute(attr, attributeValue);
}
} else {
handleInvalidProperty(
"Error processing foreign attribute: "
+ attributeNS + "/@" + attributeName, attributeName);
handleInvalidProperty(attr);
}
}
}
@@ -345,11 +342,8 @@ public abstract class PropertyList {
* @param propertyName the property name to check
* @return true if the base property name and the subproperty name (if any)
* can be correctly mapped to an id
* @throws ValidationException in case the property name
* is invalid for the FO namespace
*/
protected boolean isValidPropertyName(String propertyName)
throws ValidationException {
protected boolean isValidPropertyName(String propertyName) {

int propId = FOPropertyMapping.getPropertyId(
findBasePropertyName(propertyName));
@@ -359,9 +353,6 @@ public abstract class PropertyList {
if (propId == -1
|| (subpropId == -1
&& findSubPropertyName(propertyName) != null)) {
String errorMessage = MessageFormat.format(
"Invalid property name ''{0}''.", new Object[] {propertyName});
handleInvalidProperty(errorMessage, propertyName);
return false;
}
return true;
@@ -382,19 +373,23 @@ public abstract class PropertyList {
if (attributeValue != null) {

if (!isValidPropertyName(attributeName)) {
//will log an error or throw an exception
if (attributeName.startsWith("xmlns:")) {
//Ignore namespace declarations
return;
}
FObj parentFO = fobj.findNearestAncestorFObj();
/* Handle "compound" properties, ex. space-before.minimum */
String basePropertyName = findBasePropertyName(attributeName);
String subPropertyName = findSubPropertyName(attributeName);

int propId = FOPropertyMapping.getPropertyId(basePropertyName);
int subpropId = FOPropertyMapping.getSubPropertyId(subPropertyName);
if (propId == -1
|| (subpropId == -1 && subPropertyName != null)) {
handleInvalidProperty(new QName(null, attributeName));
}
FObj parentFO = fobj.findNearestAncestorFObj();
PropertyMaker propertyMaker = findMaker(propId);
if (propertyMaker == null) {
@@ -417,8 +412,8 @@ public abstract class PropertyList {
}
prop = propertyMaker.make(this, attributeValue, parentFO);
} else { // e.g. "leader-length.maximum"
Property baseProperty =
findBaseProperty(attributes, parentFO, propId,
Property baseProperty
= findBaseProperty(attributes, parentFO, propId,
basePropertyName, propertyMaker);
prop = propertyMaker.make(baseProperty, subpropId,
this, attributeValue, parentFO);
@@ -427,8 +422,8 @@ public abstract class PropertyList {
putExplicit(propId, prop);
}
} catch (PropertyException e) {
log.error("Ignoring property: "
+ attributeName + "=\"" + attributeValue + "\" (" + e.getMessage() + ")");
fobj.getFOValidationEventProducer().invalidPropertyValue(this, fobj.getName(),
attributeName, attributeValue, e, fobj.locator);
}
}
}
@@ -465,18 +460,16 @@ public abstract class PropertyList {
}

/**
* @param message ...
* @param propName ...
* @throws ValidationException ...
* Handles an invalid property.
* @param attr the invalid attribute
* @throws ValidationException if an exception needs to be thrown depending on the
* validation settings
*/
protected void handleInvalidProperty(String message, String propName)
protected void handleInvalidProperty(QName attr)
throws ValidationException {
if (!propName.startsWith("xmlns")) {
if (fobj.getUserAgent().validateStrictly()) {
fobj.attributeError(message);
} else {
log.error(message + " Property ignored.");
}
if (!attr.getQName().startsWith("xmlns")) {
fobj.getFOValidationEventProducer().invalidProperty(this, fobj.getName(),
attr, true, fobj.locator);
}
}


+ 7
- 1
src/java/org/apache/fop/fo/expr/FromParentFunction.java View File

@@ -64,7 +64,13 @@ public class FromParentFunction extends FunctionBase {
* non-inherited properties too. Perhaps the result is different for
* a property line line-height which "inherits specified"???
*/
return pInfo.getPropertyList().getFromParent(FOPropertyMapping.getPropertyId(propName));
int propId = FOPropertyMapping.getPropertyId(propName);
if (propId < 0) {
throw new PropertyException(
"Unknown property name used with inherited-property-value function: "
+ propName);
}
return pInfo.getPropertyList().getFromParent(propId);
}

}

+ 5
- 0
src/java/org/apache/fop/fo/expr/InheritedPropFunction.java View File

@@ -58,6 +58,11 @@ public class InheritedPropFunction extends FunctionBase {
}

int propId = FOPropertyMapping.getPropertyId(propName);
if (propId < 0) {
throw new PropertyException(
"Unknown property name used with inherited-property-value function: "
+ propName);
}
return pInfo.getPropertyList().getInherited(propId);
}


+ 5
- 0
src/java/org/apache/fop/fo/expr/NearestSpecPropFunction.java View File

@@ -60,6 +60,11 @@ public class NearestSpecPropFunction extends FunctionBase {
// NOTE: special cases for shorthand property
// Should return COMPUTED VALUE
int propId = FOPropertyMapping.getPropertyId(propName);
if (propId < 0) {
throw new PropertyException(
"Unknown property name used with inherited-property-value function: "
+ propName);
}
return pInfo.getPropertyList().getNearestSpecified(propId);
}


+ 5
- 4
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java View File

@@ -19,14 +19,15 @@

package org.apache.fop.fo.extensions;

import java.util.HashMap;
import java.util.Set;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.fo.ElementMapping;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.UnknownXMLObj;
import org.apache.fop.fo.extensions.destination.Destination;
import org.apache.fop.util.QName;

import java.util.HashMap;
import java.util.Set;

/**
* Element mapping for FOP's proprietary extension to XSL-FO.

+ 7
- 7
src/java/org/apache/fop/fo/extensions/destination/Destination.java View File

@@ -19,15 +19,15 @@

package org.apache.fop.fo.extensions.destination;

import org.apache.fop.fo.ValidationException;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.pagination.Root;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.extensions.ExtensionElementMapping;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.apache.fop.fo.pagination.Root;

/**
* Class for named destinations in PDF.
@@ -54,7 +54,7 @@ public class Destination extends FONode {
Attributes attlist, PropertyList pList) throws FOPException {
internalDestination = attlist.getValue("internal-destination");
if (internalDestination == null || internalDestination.length() == 0) {
attributeError("Missing attribute: internal-destination must be specified.");
missingPropertyError("internal-destination");
}
}

+ 11
- 18
src/java/org/apache/fop/fo/flow/AbstractListItemPart.java View File

@@ -62,14 +62,16 @@ public abstract class AbstractListItemPart extends FObj {
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
}

@@ -79,17 +81,8 @@ public abstract class AbstractListItemPart extends FObj {
protected void endOfNode() throws FOPException {
if (!this.blockItemFound) {
String contentModel = "marker* (%block;)+";
if (getUserAgent().validateStrictly()) {
missingChildElementError(contentModel);
} else {
StringBuffer message = new StringBuffer(
errorText(getLocator()));
message.append(getName())
.append(" is missing child elements. ")
.append("Required Content Model: ")
.append(contentModel);
log.warn(message.toString());
}
getFOValidationEventProducer().missingChildElement(this, getName(),
contentModel, true, getLocator());
}
}


+ 3
- 1
src/java/org/apache/fop/fo/flow/AbstractPageNumberCitation.java View File

@@ -113,8 +113,10 @@ public abstract class AbstractPageNumberCitation extends FObj {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/** @return the Common Font Properties. */

+ 11
- 10
src/java/org/apache/fop/fo/flow/BasicLink.java View File

@@ -76,8 +76,7 @@ public class BasicLink extends Inline {
externalDestination = null;
} else if (externalDestination.length() == 0) {
// slightly stronger than spec "should be specified"
attributeError("Missing attribute: Either external-destination or " +
"internal-destination must be specified.");
getFOValidationEventProducer().missingLinkDestination(this, getName(), locator);
}
}

@@ -102,15 +101,17 @@ public class BasicLink extends Inline {
* XSL Content Model: marker* (#PCDATA|%inline;|%block;)*
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(#PCDATA|%inline;|%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(#PCDATA|%inline;|%block;)");
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockOrInlineItemFound = true;
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockOrInlineItemFound = true;
}
}


+ 16
- 16
src/java/org/apache/fop/fo/flow/BidiOverride.java View File

@@ -19,13 +19,14 @@

package org.apache.fop.fo.flow;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.SpaceProperty;
import org.xml.sax.Locator;

/**
* Class modelling the fo:bidi-override object.
@@ -96,22 +97,21 @@ public class BidiOverride extends FObjMixed {
* fo:inline-container."
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else if (!canHaveBlockLevelChildren && isBlockItem(nsURI, localName)) {
invalidChildError(loc, getParent().getName(), nsURI, getName(),
"rule.bidiOverrideContent");
} else {
blockOrInlineItemFound = true;
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else if (!canHaveBlockLevelChildren && isBlockItem(nsURI, localName)) {
String ruleViolated = "An fo:bidi-override"
+ " that is a descendant of an fo:leader or of the fo:inline child"
+ " of an fo:footnote may not have block-level children, unless it"
+ " has a nearer ancestor that is an fo:inline-container.";
invalidChildError(loc, nsURI, localName, ruleViolated);
} else {
blockOrInlineItemFound = true;
}
}


+ 10
- 8
src/java/org/apache/fop/fo/flow/BlockContainer.java View File

@@ -114,15 +114,17 @@ public class BlockContainer extends FObj {
* @todo - implement above restriction if possible
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
}


+ 5
- 2
src/java/org/apache/fop/fo/flow/Character.java View File

@@ -22,6 +22,8 @@ package org.apache.fop.fo.flow;
import java.awt.Color;
import java.util.NoSuchElementException;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.CharIterator;
@@ -35,7 +37,6 @@ import org.apache.fop.fo.properties.CommonHyphenation;
import org.apache.fop.fo.properties.CommonTextDecoration;
import org.apache.fop.fo.properties.Property;
import org.apache.fop.fo.properties.SpaceProperty;
import org.xml.sax.Locator;

/**
* Class modelling the fo:character object.
@@ -134,8 +135,10 @@ public class Character extends FObj {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/**

+ 13
- 5
src/java/org/apache/fop/fo/flow/ExternalGraphic.java View File

@@ -32,6 +32,7 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.URISpecification;
import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
@@ -78,11 +79,17 @@ public class ExternalGraphic extends AbstractGraphics {
try {
info = manager.getImageInfo(url, userAgent.getImageSessionContext());
} catch (ImageException e) {
log.error("Image not available: " + e.getMessage());
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageError(this, url, e, getLocator());
} catch (FileNotFoundException fnfe) {
log.error(fnfe.getMessage());
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageNotFound(this, url, fnfe, getLocator());
} catch (IOException ioe) {
log.error("I/O error while loading image: " + ioe.getMessage());
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.imageIOError(this, url, ioe, getLocator());
}
if (info != null) {
this.intrinsicWidth = info.getSize().getWidthMpt();
@@ -93,7 +100,6 @@ public class ExternalGraphic extends AbstractGraphics {
= FixedLength.getInstance(-baseline);
}
}
//TODO Report to caller so he can decide to throw an exception
}

/** {@inheritDoc} */
@@ -107,8 +113,10 @@ public class ExternalGraphic extends AbstractGraphics {
* <br>XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/** @return the "src" property */

+ 5
- 2
src/java/org/apache/fop/fo/flow/Float.java View File

@@ -46,7 +46,8 @@ public class Float extends FObj {
super(parent);
if (!notImplementedWarningGiven) {
log.warn("fo:float is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}
@@ -63,10 +64,12 @@ public class Float extends FObj {
* XSL Content Model: (%block;)+
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
}
}
}

/**

+ 5
- 3
src/java/org/apache/fop/fo/flow/Footnote.java View File

@@ -82,12 +82,13 @@ public class Footnote extends FObj {
* generates an absolutely positioned area.
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("inline")) {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("inline")) {
if (footnoteCitation != null) {
tooManyNodesError(loc, "fo:inline");
}
} else if (FO_URI.equals(nsURI) && localName.equals("footnote-body")) {
} else if (localName.equals("footnote-body")) {
if (footnoteCitation == null) {
nodesOutOfOrderError(loc, "fo:inline", "fo:footnote-body");
} else if (footnoteBody != null) {
@@ -96,6 +97,7 @@ public class Footnote extends FObj {
} else {
invalidChildError(loc, nsURI, localName);
}
}
}

/**

+ 3
- 1
src/java/org/apache/fop/fo/flow/FootnoteBody.java View File

@@ -73,10 +73,12 @@ public class FootnoteBody extends FObj {
* XSL Content Model: (%block;)+
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
}
}
}

/** {@inheritDoc} */

+ 3
- 1
src/java/org/apache/fop/fo/flow/InitialPropertySet.java View File

@@ -72,8 +72,10 @@ public class InitialPropertySet extends FObj {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/**

+ 15
- 18
src/java/org/apache/fop/fo/flow/Inline.java View File

@@ -81,8 +81,8 @@ public class Inline extends InlineLevel {
int lvlInCntr = findAncestor(FO_INLINE_CONTAINER);

if (lvlLeader > 0) {
if (lvlInCntr < 0 ||
(lvlInCntr > 0 && lvlInCntr > lvlLeader)) {
if (lvlInCntr < 0
|| (lvlInCntr > 0 && lvlInCntr > lvlLeader)) {
canHaveBlockLevelChildren = false;
}
} else if (lvlFootnote > 0) {
@@ -110,23 +110,20 @@ public class Inline extends InlineLevel {
* nearer ancestor that is an fo:inline-container." (paraphrased)
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else if (!canHaveBlockLevelChildren && isBlockItem(nsURI, localName)) {
invalidChildError(loc, getParent().getName(), nsURI, getName(), "rule.inlineContent");
} else {
blockOrInlineItemFound = true;
}
} else if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else if (!canHaveBlockLevelChildren && isBlockItem(nsURI, localName)) {
String ruleViolated =
" An fo:inline that is a descendant of an fo:leader" +
" or fo:footnote may not have block-level children," +
" unless it has a nearer ancestor that is an" +
" fo:inline-container.";
invalidChildError(loc, nsURI, localName, ruleViolated);
} else {
blockOrInlineItemFound = true;
}
}


+ 10
- 8
src/java/org/apache/fop/fo/flow/InlineContainer.java View File

@@ -86,15 +86,17 @@ public class InlineContainer extends FObj {
* XSL Content Model: marker* (%block;)+
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
}


+ 20
- 23
src/java/org/apache/fop/fo/flow/InstreamForeignObject.java View File

@@ -20,12 +20,17 @@
package org.apache.fop.fo.flow;

import java.awt.geom.Point2D;

import org.xml.sax.Locator;

import org.apache.xmlgraphics.util.QName;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.XMLObj;
import org.xml.sax.Locator;

/**
* Class modelling the fo:instream-foreign-object object.
@@ -39,6 +44,7 @@ public class InstreamForeignObject extends AbstractGraphics {

//Additional value
private Point2D intrinsicDimensions;
private boolean instrisicSizeDetermined;
private Length intrinsicAlignmentAdjust;
@@ -68,11 +74,11 @@ public class InstreamForeignObject extends AbstractGraphics {
* XSL Content Model: one (1) non-XSL namespace child
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
} else if (firstChild != null) {
tooManyNodesError(loc, "child element");
tooManyNodesError(loc, new QName(nsURI, null, localName));
}
}

@@ -81,32 +87,28 @@ public class InstreamForeignObject extends AbstractGraphics {
return "instream-foreign-object";
}
/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int getNameId() {
return FO_INSTREAM_FOREIGN_OBJECT;
}

/**
* Preloads the image so the intrinsic size is available.
*/
/** Preloads the image so the intrinsic size is available. */
private void prepareIntrinsicSize() {
if (intrinsicDimensions == null) {
if (!this.instrisicSizeDetermined) {
XMLObj child = (XMLObj) firstChild;
Point2D csize = new Point2D.Float(-1, -1);
intrinsicDimensions = child.getDimension(csize);
if (intrinsicDimensions == null) {
log.error("Intrinsic dimensions of "
+ " instream-foreign-object could not be determined");
ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.ifoNoIntrinsicSize(this, getLocator());
}
intrinsicAlignmentAdjust = child.getIntrinsicAlignmentAdjust();
this.instrisicSizeDetermined = true;
}
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int getIntrinsicWidth() {
prepareIntrinsicSize();
if (intrinsicDimensions != null) {
@@ -116,9 +118,7 @@ public class InstreamForeignObject extends AbstractGraphics {
}
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int getIntrinsicHeight() {
prepareIntrinsicSize();
if (intrinsicDimensions != null) {
@@ -128,11 +128,8 @@ public class InstreamForeignObject extends AbstractGraphics {
}
}

/**
* {@inheritDoc}
*/
public Length getIntrinsicAlignmentAdjust()
{
/** {@inheritDoc} */
public Length getIntrinsicAlignmentAdjust() {
prepareIntrinsicSize();
return intrinsicAlignmentAdjust;
}

+ 10
- 8
src/java/org/apache/fop/fo/flow/ListBlock.java View File

@@ -108,15 +108,17 @@ public class ListBlock extends FObj {
* XSL Content Model: marker* (list-item)+
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (hasListItem) {
nodesOutOfOrderError(loc, "fo:marker", "fo:list-item");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (hasListItem) {
nodesOutOfOrderError(loc, "fo:marker", "fo:list-item");
}
} else if (localName.equals("list-item")) {
hasListItem = true;
} else {
invalidChildError(loc, nsURI, localName);
}
} else if (FO_URI.equals(nsURI) && localName.equals("list-item")) {
hasListItem = true;
} else {
invalidChildError(loc, nsURI, localName);
}
}


+ 17
- 15
src/java/org/apache/fop/fo/flow/ListItem.java View File

@@ -98,22 +98,24 @@ public class ListItem extends FObj {
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (label != null) {
nodesOutOfOrderError(loc, "fo:marker", "fo:list-item-label");
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (label != null) {
nodesOutOfOrderError(loc, "fo:marker", "fo:list-item-label");
}
} else if (localName.equals("list-item-label")) {
if (label != null) {
tooManyNodesError(loc, "fo:list-item-label");
}
} else if (localName.equals("list-item-body")) {
if (label == null) {
nodesOutOfOrderError(loc, "fo:list-item-label", "fo:list-item-body");
} else if (body != null) {
tooManyNodesError(loc, "fo:list-item-body");
}
} else {
invalidChildError(loc, nsURI, localName);
}
} else if (FO_URI.equals(nsURI) && localName.equals("list-item-label")) {
if (label != null) {
tooManyNodesError(loc, "fo:list-item-label");
}
} else if (FO_URI.equals(nsURI) && localName.equals("list-item-body")) {
if (label == null) {
nodesOutOfOrderError(loc, "fo:list-item-label", "fo:list-item-body");
} else if (body != null) {
tooManyNodesError(loc, "fo:list-item-body");
}
} else {
invalidChildError(loc, nsURI, localName);
}
}


+ 7
- 6
src/java/org/apache/fop/fo/flow/Marker.java View File

@@ -59,9 +59,8 @@ public class Marker extends FObjMixed {
*/
public void bind(PropertyList pList) throws FOPException {
if (findAncestor(FO_FLOW) < 0) {
invalidChildError(locator, FO_URI, "marker",
"An fo:marker is permitted only as the descendant "
+ "of an fo:flow");
invalidChildError(locator, getParent().getName(), FO_URI, getName(),
"rule.markerDescendantOfFlow");
}
markerClassName = pList.get(PR_MARKER_CLASS_NAME).getString();
@@ -112,9 +111,11 @@ public class Marker extends FObjMixed {
* @todo implement "additional" constraint, possibly within fo:retrieve-marker
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
}
}
}

+ 2
- 1
src/java/org/apache/fop/fo/flow/MultiCase.java View File

@@ -46,7 +46,8 @@ public class MultiCase extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:multi-case is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}

+ 6
- 3
src/java/org/apache/fop/fo/flow/MultiProperties.java View File

@@ -49,7 +49,8 @@ public class MultiProperties extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:multi-properties is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}
@@ -69,13 +70,14 @@ public class MultiProperties extends FObj {
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("multi-property-set")) {
if (FO_URI.equals(nsURI)) {
if (localName.equals("multi-property-set")) {
if (hasWrapper) {
nodesOutOfOrderError(loc, "fo:multi-property-set", "fo:wrapper");
} else {
hasMultiPropertySet = true;
}
} else if (FO_URI.equals(nsURI) && localName.equals("wrapper")) {
} else if (localName.equals("wrapper")) {
if (hasWrapper) {
tooManyNodesError(loc, "fo:wrapper");
} else {
@@ -84,6 +86,7 @@ public class MultiProperties extends FObj {
} else {
invalidChildError(loc, nsURI, localName);
}
}
}
/** {@inheritDoc} */

+ 5
- 2
src/java/org/apache/fop/fo/flow/MultiPropertySet.java View File

@@ -45,7 +45,8 @@ public class MultiPropertySet extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:multi-property-set is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}
@@ -63,8 +64,10 @@ public class MultiPropertySet extends FObj {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/** {@inheritDoc} */

+ 7
- 4
src/java/org/apache/fop/fo/flow/MultiSwitch.java View File

@@ -47,7 +47,8 @@ public class MultiSwitch extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:multi-switch is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}
@@ -75,9 +76,11 @@ public class MultiSwitch extends FObj {
* XSL Content Model: (multi-case+)
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (!(FO_URI.equals(nsURI) && localName.equals("multi-case"))) {
invalidChildError(loc, nsURI, localName);
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (!localName.equals("multi-case")) {
invalidChildError(loc, nsURI, localName);
}
}
}


+ 7
- 4
src/java/org/apache/fop/fo/flow/MultiToggle.java View File

@@ -47,7 +47,8 @@ public class MultiToggle extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:multi-toggle is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
getName(), getLocator());
notImplementedWarningGiven = true;
}
}
@@ -65,9 +66,11 @@ public class MultiToggle extends FObj {
* XSL Content Model: (#PCDATA|%inline;|%block;)*
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (!isBlockOrInlineItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
}
}
}


+ 3
- 1
src/java/org/apache/fop/fo/flow/PageNumber.java View File

@@ -117,8 +117,10 @@ public class PageNumber extends FObj {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/** @return the Common Font Properties. */

+ 14
- 17
src/java/org/apache/fop/fo/flow/RetrieveMarker.java View File

@@ -21,6 +21,8 @@ package org.apache.fop.fo.flow;

import java.util.Iterator;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
@@ -30,7 +32,6 @@ import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableFObj;
import org.xml.sax.Locator;

/**
* Class modelling the fo:retrieve-marker object.
@@ -48,21 +49,18 @@ public class RetrieveMarker extends FObjMixed {

/**
* Create a retrieve marker object.
*
* @param parent FONode that is the parent of this object
* @see org.apache.fop.fo.FONode#FONode(FONode)
*/
public RetrieveMarker(FONode parent) {
super(parent);
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
if (findAncestor(FO_STATIC_CONTENT) < 0) {
invalidChildError(locator, FO_URI, "retrieve-marker",
"An fo:retrieve-marker is permitted only as the " +
" descendant of an fo:static-content.");
invalidChildError(locator, getParent().getName(), FO_URI, getName(),
"rule.retrieveMarkerDescendatOfStaticContent");
}

retrieveClassName = pList.get(PR_RETRIEVE_CLASS_NAME).getString();
@@ -81,8 +79,10 @@ public class RetrieveMarker extends FObjMixed {
* XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/**
@@ -206,13 +206,12 @@ public class RetrieveMarker extends FObjMixed {
try {
cloneFromMarker(marker);
} catch (FOPException exc) {
log.error("fo:retrieve-marker unable to clone "
+ "subtree of fo:marker (marker-class-name="
+ marker.getMarkerClassName() + ")", exc);
getFOValidationEventProducer().markerCloningFailed(this,
marker.getMarkerClassName(), exc, getLocator());
return;
}
} else if (log.isInfoEnabled()) {
log.info("Empty marker retrieved...");
} else if (log.isDebugEnabled()) {
log.debug("Empty marker retrieved...");
}
return;
}
@@ -222,9 +221,7 @@ public class RetrieveMarker extends FObjMixed {
return "retrieve-marker";
}

/**
* {@inheritDoc}
*/
/** {@inheritDoc} */
public int getNameId() {
return FO_RETRIEVE_MARKER;
}

+ 14
- 11
src/java/org/apache/fop/fo/flow/Wrapper.java View File

@@ -19,12 +19,13 @@

package org.apache.fop.fo.flow;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.xml.sax.Locator;

/**
* Class modelling the fo:wrapper object.
@@ -66,17 +67,19 @@ public class Wrapper extends FObjMixed {
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && "marker".equals(localName)) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
if (FO_URI.equals(nsURI)) {
if ("marker".equals(localName)) {
if (blockOrInlineItemFound) {
nodesOutOfOrderError(loc, "fo:marker",
"(#PCDATA|%inline;|%block;)");
}
} else if (isBlockOrInlineItem(nsURI, localName)) {
//delegate validation to parent
FONode.validateChildNode(this.parent, loc, nsURI, localName);
blockOrInlineItemFound = true;
} else {
invalidChildError(loc, nsURI, localName);
}
} else if (isBlockOrInlineItem(nsURI, localName)) {
//delegate validation to parent
FONode.validateChildNode(this.parent, loc, nsURI, localName);
blockOrInlineItemFound = true;
} else {
invalidChildError(loc, nsURI, localName);
}
}


+ 8
- 4
src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java View File

@@ -120,13 +120,17 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
void endTableRow() {
assert currentTableRow != null;
if (currentRowIndex > 0 && currentTableRow.getBreakBefore() != Constants.EN_AUTO) {
currentTableRow.attributeWarning("break-before ignored because of row spanning "
+ "in progress (See XSL 1.1, 7.20.2)");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
currentTableRow.getUserAgent().getEventBroadcaster());
eventProducer.breakIgnoredDueToRowSpanning(this, currentTableRow.getName(), true,
currentTableRow.getLocator());
}
if (currentRowIndex < rows.size() - 1
&& currentTableRow.getBreakAfter() != Constants.EN_AUTO) {
currentTableRow.attributeWarning("break-after ignored because of row spanning "
+ "in progress (See XSL 1.1, 7.20.1)");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
currentTableRow.getUserAgent().getEventBroadcaster());
eventProducer.breakIgnoredDueToRowSpanning(this, currentTableRow.getName(), false,
currentTableRow.getLocator());
}
for (Iterator iter = ((List) rows.get(currentRowIndex)).iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();

+ 20
- 19
src/java/org/apache/fop/fo/flow/table/Table.java View File

@@ -22,6 +22,8 @@ package org.apache.fop.fo.flow.table;
import java.util.ArrayList;
import java.util.List;

import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.ValidationPercentBaseContext;
@@ -35,7 +37,6 @@ import org.apache.fop.fo.properties.KeepProperty;
import org.apache.fop.fo.properties.LengthPairProperty;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.fo.properties.TableColLength;
import org.xml.sax.Locator;

/**
* Class modelling the fo:table object.
@@ -126,20 +127,22 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength();

if (!blockProgressionDimension.getOptimum(null).isAuto()) {
attributeWarning("only a value of \"auto\" for block-progression-dimension has a"
+ " well-specified behavior on fo:table. Falling back to \"auto\"");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.nonAutoBPDOnTable(this, getLocator());
// Anyway, the bpd of a table is not used by the layout code
}
if (tableLayout == EN_AUTO) {
attributeWarning("table-layout=\"auto\" is currently not supported by FOP");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
"table-layout=\"auto\"", getLocator());
}
if (!isSeparateBorderModel()
&& getCommonBorderPaddingBackground().hasPadding(
ValidationPercentBaseContext.getPseudoContext())) {
//See "17.6.2 The collapsing border model" in CSS2
attributeWarning("In collapsing border model a table does not have padding"
+ " (see http://www.w3.org/TR/REC-CSS2/tables.html#collapsing-borders)"
+ ", but a non-zero value for padding was found. The padding will be ignored.");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.noTablePaddingWithCollapsingBorderModel(this, getLocator());
}

/* Store reference to the property list, so
@@ -163,7 +166,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
* XSL Content Model: (marker*,table-column*,table-header?,table-footer?,table-body+)
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if ("marker".equals(localName)) {
if (tableColumnFound || tableHeaderFound || tableFooterFound
@@ -193,15 +196,11 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
} else {
tableFooterFound = true;
if (tableBodyFound) {
if (getUserAgent().validateStrictly()) {
nodesOutOfOrderError(loc, "fo:table-footer", "(table-body+)");
} else if (!isSeparateBorderModel()) {
nodesOutOfOrderError(loc, "fo:table-footer", "(table-body+)."
+ " This table uses the collapsing border"
+ " model. In order to resolve borders in an efficient way"
+ " the table-footer must be known before any table-body"
+ " is parsed. Either put the footer at the correct place"
+ " or switch to the separate border model");
nodesOutOfOrderError(loc, "fo:table-footer", "(table-body+)", true);
if (!isSeparateBorderModel()) {
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.footerOrderCannotRecover(this, getName(), getLocator());
}
}
}
@@ -210,8 +209,6 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
} else {
invalidChildError(loc, nsURI, localName);
}
} else {
invalidChildError(loc, nsURI, localName);
}
}

@@ -225,6 +222,10 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
"(marker*,table-column*,table-header?,table-footer?"
+ ",table-body+)");
}
if (!hasChildren()) {
getParent().removeChild(this);
return;
}
if (!inMarker()) {
rowGroupBuilder.endTable();
/* clean up */

+ 25
- 22
src/java/org/apache/fop/fo/flow/table/TableAndCaption.java View File

@@ -62,7 +62,8 @@ public class TableAndCaption extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:table-and-caption is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
"fo:table-and-caption", getLocator());
notImplementedWarningGiven = true;
}
}
@@ -83,30 +84,32 @@ public class TableAndCaption extends FObj {
* XSL Content Model: marker* table-caption? table
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
throws ValidationException {

if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (tableCaptionFound) {
nodesOutOfOrderError(loc, "fo:marker", "fo:table-caption");
} else if (tableFound) {
nodesOutOfOrderError(loc, "fo:marker", "fo:table");
}
} else if (FO_URI.equals(nsURI) && localName.equals("table-caption")) {
if (tableCaptionFound) {
tooManyNodesError(loc, "fo:table-caption");
} else if (tableFound) {
nodesOutOfOrderError(loc, "fo:table-caption", "fo:table");
} else {
tableCaptionFound = true;
}
} else if (FO_URI.equals(nsURI) && localName.equals("table")) {
if (tableFound) {
tooManyNodesError(loc, "fo:table");
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (tableCaptionFound) {
nodesOutOfOrderError(loc, "fo:marker", "fo:table-caption");
} else if (tableFound) {
nodesOutOfOrderError(loc, "fo:marker", "fo:table");
}
} else if (localName.equals("table-caption")) {
if (tableCaptionFound) {
tooManyNodesError(loc, "fo:table-caption");
} else if (tableFound) {
nodesOutOfOrderError(loc, "fo:table-caption", "fo:table");
} else {
tableCaptionFound = true;
}
} else if (localName.equals("table")) {
if (tableFound) {
tooManyNodesError(loc, "fo:table");
} else {
tableFound = true;
}
} else {
tableFound = true;
invalidChildError(loc, nsURI, localName);
}
} else {
invalidChildError(loc, nsURI, localName);
}
}


+ 11
- 18
src/java/org/apache/fop/fo/flow/table/TableBody.java View File

@@ -23,13 +23,14 @@ import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.Locator;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;

/**
* Class modelling the fo:table-body object.
@@ -119,13 +120,8 @@ public class TableBody extends TableCellContainer {
getFOEventHandler().endBody(this);

if (!(tableRowsFound || tableCellsFound)) {
if (getUserAgent().validateStrictly()) {
missingChildElementError("marker* (table-row+|table-cell+)");
} else {
log.error("fo:table-body must not be empty. "
+ "Expected: marker* (table-row+|table-cell+)");
getParent().removeChild(this);
}
missingChildElementError("marker* (table-row+|table-cell+)", true);
getParent().removeChild(this);
} else {
finishLastRowGroup();
}
@@ -167,23 +163,20 @@ public class TableBody extends TableCellContainer {
} else if (localName.equals("table-row")) {
tableRowsFound = true;
if (tableCellsFound) {
invalidChildError(loc, nsURI, localName, "Either fo:table-rows"
+ " or fo:table-cells may be children of an " + getName()
+ " but not both");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.noMixRowsAndCells(this, getName(), getLocator());
}
} else if (localName.equals("table-cell")) {
tableCellsFound = true;
if (tableRowsFound) {
invalidChildError(loc, nsURI, localName,
"Either fo:table-rows or fo:table-cells "
+ "may be children of an "
+ getName() + " but not both");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.noMixRowsAndCells(this, getName(), getLocator());
}
} else {
invalidChildError(loc, nsURI, localName);
}
} else {
invalidChildError(loc, nsURI, localName);
}
}


+ 12
- 9
src/java/org/apache/fop/fo/flow/table/TableCaption.java View File

@@ -57,7 +57,8 @@ public class TableCaption extends FObj {
super(parent);

if (!notImplementedWarningGiven) {
log.warn("fo:table-caption is not yet implemented.");
getFOValidationEventProducer().unimplementedFeature(this, getName(),
"fo:table-caption", getLocator());
notImplementedWarningGiven = true;
}
}
@@ -83,15 +84,17 @@ public class TableCaption extends FObj {
* XSL Content Model: marker* (%block;)
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
throws ValidationException {
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
}


+ 13
- 15
src/java/org/apache/fop/fo/flow/table/TableCell.java View File

@@ -102,17 +102,13 @@ public class TableCell extends TableFObj {
*/
public void endOfNode() throws FOPException {
if (!blockItemFound) {
if (getUserAgent().validateStrictly()) {
missingChildElementError("marker* (%block;)+");
} else if (firstChild != null) {
log.warn("fo:table-cell content that is not "
+ "enclosed by a fo:block will be dropped/ignored.");
}
missingChildElementError("marker* (%block;)+", true);
}
if ((startsRow() || endsRow())
&& getParent().getNameId() == FO_TABLE_ROW ) {
log.warn("starts-row/ends-row for fo:table-cells "
+ "non-applicable for children of an fo:table-row.");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.startEndRowUnderTableRowWarning(this, getLocator());
}
getFOEventHandler().endCell(this);
}
@@ -123,14 +119,16 @@ public class TableCell extends TableFObj {
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI) && localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
if (FO_URI.equals(nsURI)) {
if (localName.equals("marker")) {
if (blockItemFound) {
nodesOutOfOrderError(loc, "fo:marker", "(%block;)");
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
} else if (!isBlockItem(nsURI, localName)) {
invalidChildError(loc, nsURI, localName);
} else {
blockItemFound = true;
}
}


+ 3
- 4
src/java/org/apache/fop/fo/flow/table/TableCellContainer.java View File

@@ -24,7 +24,6 @@ import java.util.List;
import org.apache.fop.apps.FOPException;
import org.apache.fop.datatypes.Length;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.ValidationException;

/**
* A common class for fo:table-body and fo:table-row which both can contain fo:table-cell.
@@ -47,9 +46,9 @@ public abstract class TableCellContainer extends TableFObj implements ColumnNumb
Table t = getTable();
if (t.hasExplicitColumns()) {
if (colNumber + colSpan - 1 > t.getNumberOfColumns()) {
throw new ValidationException(FONode.errorText(locator) + "column-number or "
+ "number of cells in the row overflows the number of fo:table-column "
+ "specified for the table.");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.tooManyCells(this, getLocator());
}
} else {
t.ensureColumnNumber(colNumber + colSpan - 1);

+ 14
- 7
src/java/org/apache/fop/fo/flow/table/TableColumn.java View File

@@ -82,12 +82,16 @@ public class TableColumn extends TableFObj {
super.bind(pList);

if (numberColumnsRepeated <= 0) {
throw new PropertyException("number-columns-repeated must be 1 or bigger, "
+ "but got " + numberColumnsRepeated);
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.valueMustBeBiggerGtEqOne(this,
"number-columns-repeated", numberColumnsRepeated, getLocator());
}
if (numberColumnsSpanned <= 0) {
throw new PropertyException("number-columns-spanned must be 1 or bigger, "
+ "but got " + numberColumnsSpanned);
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.valueMustBeBiggerGtEqOne(this,
"number-columns-spanned", numberColumnsSpanned, getLocator());
}

/* check for unspecified width and replace with default of
@@ -96,8 +100,9 @@ public class TableColumn extends TableFObj {
*/
if (columnWidth.getEnum() == EN_AUTO) {
if (!this.implicitColumn && !getTable().isAutoLayout()) {
log.warn("table-layout=\"fixed\" and column-width unspecified "
+ "=> falling back to proportional-column-width(1)");
TableEventProducer eventProducer = TableEventProducer.Provider.get(
getUserAgent().getEventBroadcaster());
eventProducer.warnImplicitColumns(this, getLocator());
}
columnWidth = new TableColLength(1.0, this);
}
@@ -146,7 +151,9 @@ public class TableColumn extends TableFObj {
protected void validateChildNode(Locator loc,
String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}

/**
@@ -240,7 +247,7 @@ public class TableColumn extends TableFObj {
*
* @param propId the id for the property to retrieve
* @return the requested Property
* @throws PropertyException
* @throws PropertyException if there is a problem evaluating the property
*/
public Property getProperty(int propId) throws PropertyException {
return this.pList.get(propId);

+ 159
- 0
src/java/org/apache/fop/fo/flow/table/TableEventProducer.java View File

@@ -0,0 +1,159 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.fo.flow.table;

import org.xml.sax.Locator;

import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.events.EventProducer;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.expr.PropertyException;

/**
* Event producer interface for table-specific XSL-FO validation messages.
*/
public interface TableEventProducer extends EventProducer {

/** Provider class for the event producer. */
class Provider {
/**
* Returns an event producer.
* @param broadcaster the event broadcaster to use
* @return the event producer
*/
public static TableEventProducer get(EventBroadcaster broadcaster) {
return (TableEventProducer)broadcaster.getEventProducerFor(
TableEventProducer.class);
}
}

/**
* A value other than "auto" has been specified on fo:table.
* @param source the event source
* @param loc the location of the error or null
* @event.severity WARN
*/
void nonAutoBPDOnTable(Object source, Locator loc);

/**
* Padding on fo:table is ignored if the collapsing border model is active.
* @param source the event source
* @param loc the location of the error or null
* @event.severity WARN
*/
void noTablePaddingWithCollapsingBorderModel(Object source, Locator loc);

/**
* No mixing of table-rows and table-cells is allowed for direct children of table-body.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void noMixRowsAndCells(Object source, String elementName, Locator loc)
throws ValidationException;

/**
* The table-footer was found after the table-body. FOP cannot recover with collapsed border
* model.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void footerOrderCannotRecover(Object source, String elementName, Locator loc)
throws ValidationException;
/**
* starts-row/ends-row for fo:table-cells non-applicable for children of an fo:table-row
* @param source the event source
* @param loc the location of the error or null
* @event.severity WARN
*/
void startEndRowUnderTableRowWarning(Object source, Locator loc);

/**
* Column-number or number of cells in the row overflows the number of fo:table-column
* specified for the table.
* @param source the event source
* @param loc the location of the error or null
* @throws ValidationException the validation error provoked by the method call
* @event.severity FATAL
*/
void tooManyCells(Object source, Locator loc) throws ValidationException;

/**
* Property value must be 1 or bigger.
* @param source the event source
* @param propName the property name
* @param actualValue the actual value
* @param loc the location of the error or null
* @throws PropertyException the property error provoked by the method call
* @event.severity FATAL
*/
void valueMustBeBiggerGtEqOne(Object source, String propName,
int actualValue, Locator loc) throws PropertyException;

/**
* table-layout=\"fixed\" and column-width unspecified
* => falling back to proportional-column-width(1)
* @param source the event source
* @param loc the location of the error or null
* @event.severity WARN
*/
void warnImplicitColumns(Object source, Locator loc);

/**
* padding-* properties are not applicable.
* @param source the event source
* @param elementName the name of the context node
* @param loc the location of the error or null
* @event.severity WARN
*/
void paddingNotApplicable(Object source, String elementName, Locator loc);

/**
* Cell overlap.
* @param source the event source
* @param elementName the name of the context node
* @param column the column index of the overlapping cell
* @param loc the location of the error or null
* @throws PropertyException the property error provoked by the method call
* @event.severity FATAL
*/
void cellOverlap(Object source, String elementName, int column,
Locator loc) throws PropertyException;

/**
* Break ignored due to row spanning.
* @param source the event source
* @param elementName the name of the context node
* @param breakBefore true for "break-before", false for "break-after"
* @param loc the location of the error or null
* @event.severity WARN
*/
void breakIgnoredDueToRowSpanning(Object source, String elementName, boolean breakBefore,
Locator loc);

}

+ 0
- 0
src/java/org/apache/fop/fo/flow/table/TableFObj.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save