aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/events
diff options
context:
space:
mode:
authorAdrian Cumiskey <acumiskey@apache.org>2008-04-14 13:05:52 +0000
committerAdrian Cumiskey <acumiskey@apache.org>2008-04-14 13:05:52 +0000
commit309f4e2998c676913e64070adda8dca5e3768fad (patch)
tree4e84f80a026d6f52e57a7a4701ae2dc14f8d5a08 /src/java/org/apache/fop/events
parent7045f7e0124c6a6f00736b0d1d81f89824fd1271 (diff)
downloadxmlgraphics-fop-309f4e2998c676913e64070adda8dca5e3768fad.tar.gz
xmlgraphics-fop-309f4e2998c676913e64070adda8dca5e3768fad.zip
Merged revisions 647692,647742,647745 via svnmerge from
https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk ................ r647692 | jeremias | 2008-04-14 09:25:22 +0100 (Mon, 14 Apr 2008) | 3 lines Initialized merge tracking via "svnmerge" with revisions "1-615152" from https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_ProcessingFeedback ................ r647742 | jeremias | 2008-04-14 12:53:29 +0100 (Mon, 14 Apr 2008) | 298 lines 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). ........ ................ r647745 | jeremias | 2008-04-14 13:01:06 +0100 (Mon, 14 Apr 2008) | 1 line svnmerge didn't work for me in this case. Remove svn merge info. ................ git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AFPGOCAResources@647787 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/events')
-rw-r--r--src/java/org/apache/fop/events/CompositeEventListener.java69
-rw-r--r--src/java/org/apache/fop/events/DefaultEventBroadcaster.java160
-rw-r--r--src/java/org/apache/fop/events/Event.java150
-rw-r--r--src/java/org/apache/fop/events/EventBroadcaster.java61
-rw-r--r--src/java/org/apache/fop/events/EventExceptionManager.java84
-rw-r--r--src/java/org/apache/fop/events/EventFormatter.java196
-rw-r--r--src/java/org/apache/fop/events/EventFormatter.xml101
-rw-r--r--src/java/org/apache/fop/events/EventFormatter_de.xml23
-rw-r--r--src/java/org/apache/fop/events/EventListener.java37
-rw-r--r--src/java/org/apache/fop/events/EventProducer.java31
-rw-r--r--src/java/org/apache/fop/events/FOPEventListenerProxy.java73
-rw-r--r--src/java/org/apache/fop/events/FOPEventModelFactory.java37
-rw-r--r--src/java/org/apache/fop/events/LoggingEventListener.java92
-rw-r--r--src/java/org/apache/fop/events/PropertyExceptionFactory.java47
-rw-r--r--src/java/org/apache/fop/events/ResourceEventProducer.java136
-rw-r--r--src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java43
-rw-r--r--src/java/org/apache/fop/events/ValidationExceptionFactory.java51
-rw-r--r--src/java/org/apache/fop/events/model/AbstractEventModelFactory.java61
-rw-r--r--src/java/org/apache/fop/events/model/EventMethodModel.java198
-rw-r--r--src/java/org/apache/fop/events/model/EventModel.java135
-rw-r--r--src/java/org/apache/fop/events/model/EventModelFactory.java33
-rw-r--r--src/java/org/apache/fop/events/model/EventModelParser.java140
-rw-r--r--src/java/org/apache/fop/events/model/EventProducerModel.java105
-rw-r--r--src/java/org/apache/fop/events/model/EventSeverity.java82
24 files changed, 2145 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/events/CompositeEventListener.java b/src/java/org/apache/fop/events/CompositeEventListener.java
new file mode 100644
index 000000000..a65728b71
--- /dev/null
+++ b/src/java/org/apache/fop/events/CompositeEventListener.java
@@ -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);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/DefaultEventBroadcaster.java b/src/java/org/apache/fop/events/DefaultEventBroadcaster.java
new file mode 100644
index 000000000..bb1752a72
--- /dev/null
+++ b/src/java/org/apache/fop/events/DefaultEventBroadcaster.java
@@ -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;
+ }
+ });
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/Event.java b/src/java/org/apache/fop/events/Event.java
new file mode 100644
index 000000000..d3da1809e
--- /dev/null
+++ b/src/java/org/apache/fop/events/Event.java
@@ -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;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/EventBroadcaster.java b/src/java/org/apache/fop/events/EventBroadcaster.java
new file mode 100644
index 000000000..6c8df7375
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventBroadcaster.java
@@ -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);
+
+}
diff --git a/src/java/org/apache/fop/events/EventExceptionManager.java b/src/java/org/apache/fop/events/EventExceptionManager.java
new file mode 100644
index 000000000..093ae7010
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventExceptionManager.java
@@ -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();
+ }
+}
diff --git a/src/java/org/apache/fop/events/EventFormatter.java b/src/java/org/apache/fop/events/EventFormatter.java
new file mode 100644
index 000000000..56964039b
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventFormatter.java
@@ -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";
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/EventFormatter.xml b/src/java/org/apache/fop/events/EventFormatter.xml
new file mode 100644
index 000000000..f17da1161
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventFormatter.xml
@@ -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>
diff --git a/src/java/org/apache/fop/events/EventFormatter_de.xml b/src/java/org/apache/fop/events/EventFormatter_de.xml
new file mode 100644
index 000000000..c65d24f73
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventFormatter_de.xml
@@ -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>
diff --git a/src/java/org/apache/fop/events/EventListener.java b/src/java/org/apache/fop/events/EventListener.java
new file mode 100644
index 000000000..f8293aed9
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventListener.java
@@ -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);
+
+}
diff --git a/src/java/org/apache/fop/events/EventProducer.java b/src/java/org/apache/fop/events/EventProducer.java
new file mode 100644
index 000000000..88da771a4
--- /dev/null
+++ b/src/java/org/apache/fop/events/EventProducer.java
@@ -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 {
+
+}
diff --git a/src/java/org/apache/fop/events/FOPEventListenerProxy.java b/src/java/org/apache/fop/events/FOPEventListenerProxy.java
new file mode 100644
index 000000000..d4c237844
--- /dev/null
+++ b/src/java/org/apache/fop/events/FOPEventListenerProxy.java
@@ -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);
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/FOPEventModelFactory.java b/src/java/org/apache/fop/events/FOPEventModelFactory.java
new file mode 100644
index 000000000..5a75042fa
--- /dev/null
+++ b/src/java/org/apache/fop/events/FOPEventModelFactory.java
@@ -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);
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/LoggingEventListener.java b/src/java/org/apache/fop/events/LoggingEventListener.java
new file mode 100644
index 000000000..9ba8ed2df
--- /dev/null
+++ b/src/java/org/apache/fop/events/LoggingEventListener.java
@@ -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;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/PropertyExceptionFactory.java b/src/java/org/apache/fop/events/PropertyExceptionFactory.java
new file mode 100644
index 000000000..667c4a16e
--- /dev/null
+++ b/src/java/org/apache/fop/events/PropertyExceptionFactory.java
@@ -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;
+ }
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/events/ResourceEventProducer.java b/src/java/org/apache/fop/events/ResourceEventProducer.java
new file mode 100644
index 000000000..21da4f1d7
--- /dev/null
+++ b/src/java/org/apache/fop/events/ResourceEventProducer.java
@@ -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);
+
+}
diff --git a/src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java b/src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java
new file mode 100644
index 000000000..06ce8dd25
--- /dev/null
+++ b/src/java/org/apache/fop/events/UnsupportedOperationExceptionFactory.java
@@ -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;
+ }
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/events/ValidationExceptionFactory.java b/src/java/org/apache/fop/events/ValidationExceptionFactory.java
new file mode 100644
index 000000000..9dba84007
--- /dev/null
+++ b/src/java/org/apache/fop/events/ValidationExceptionFactory.java
@@ -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;
+ }
+
+
+} \ No newline at end of file
diff --git a/src/java/org/apache/fop/events/model/AbstractEventModelFactory.java b/src/java/org/apache/fop/events/model/AbstractEventModelFactory.java
new file mode 100644
index 000000000..ee980f34e
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/AbstractEventModelFactory.java
@@ -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);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/model/EventMethodModel.java b/src/java/org/apache/fop/events/model/EventMethodModel.java
new file mode 100644
index 000000000..930cda53d
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventMethodModel.java
@@ -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);
+ }
+
+ }
+}
diff --git a/src/java/org/apache/fop/events/model/EventModel.java b/src/java/org/apache/fop/events/model/EventModel.java
new file mode 100644
index 000000000..61e221b3b
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventModel.java
@@ -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);
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/model/EventModelFactory.java b/src/java/org/apache/fop/events/model/EventModelFactory.java
new file mode 100644
index 000000000..cd760501c
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventModelFactory.java
@@ -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();
+
+}
diff --git a/src/java/org/apache/fop/events/model/EventModelParser.java b/src/java/org/apache/fop/events/model/EventModelParser.java
new file mode 100644
index 000000000..600e495c5
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventModelParser.java
@@ -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();
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/fop/events/model/EventProducerModel.java b/src/java/org/apache/fop/events/model/EventProducerModel.java
new file mode 100644
index 000000000..938609cd9
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventProducerModel.java
@@ -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);
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/events/model/EventSeverity.java b/src/java/org/apache/fop/events/model/EventSeverity.java
new file mode 100644
index 000000000..d37c53c1e
--- /dev/null
+++ b/src/java/org/apache/fop/events/model/EventSeverity.java
@@ -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;
+ }
+
+}