Observers allow hooking up on any request sent to the renderer engines. Main use case is to do additional initialization, cache cleaning, define fonts mappings etc. when the connection changes or a document is opened, closed or similar.
Observers are registered at the Renderer factory and can be added for particular or just all events:
((Renderer) renderer).addObserver (observer /*, subjects or empty, for just all subjects */ );
Observers must implement the com.priint.comet.renderer.RendererObserver interface:
package com.priint.comet.renderer; import java.util.Map; import com.priint.comet.renderer.exception.RendererException; public interface RendererObserver { public EventChain handleEvent( final Event event, final RendererControl renderer, final Map<String,Object> eventData) throws RendererException; }Example:
RendererObserver observer = new RendererObserver() { @Override public EventChain handleEvent(Event event, RendererControl renderer, Map<String, Object> eventData) throws RendererException { System.out.println("Event=" + event + ", renderer=" + renderer); return EventChain.CONTINUE; } }; ((Renderer) renderer).addObserver(observer, Event.OPEN_DOCUMENT_BEFORE); // ... further renderer operationsSince the RendererObserer interface defines only one method, we can use lambda expressions as well:
((Renderer) renderer).addObserver( (event, renderer, eventData) -> { System.out.println("Event=" + event + ", renderer=" + renderer); return EventChain.CONTINUE; }, Event.OPEN_DOCUMENT_BEFORE); // ... further renderer operationsThe handleEvent method must return either
EventChain.CONTINUE
or EventChain.TERMINATE
. In the latter case, the event processing is terminated and a EventTerminatedException
exception is thrown.
The handleEvent method interface requires 3 parameters:
Event event
(enumeration type): the event of the event, such as OPEN_DOCUMENT_BEFORE, OPEN_DOCUMENT_AFTER, CONNECT_BEFORE etc.RendererControl renderer
: the renderer instance. This is one of the rare situations, when you have direct access to the actual (native) renderer, which handles the current request (see Overview section above, usually we just hold an instance of a RendererDocument). Though, only very limited operation is exposed through the RendererControl interface.Map<String,Object> eventData
: these are all parameters passed to the request. It is not possible to change the parameters (to be precise: changing values in the map does not affect the parameters sent to the renderer). To access particular parameters by name, use string literals defined in com.priint.comet.renderer.Constants
, e.g. Contants.SCRIPT_ARGUMENT
eventData provided for AFTER
notifications include two additional value pairs:
Contants.RESULT
: the result of the renderer request. In case of exceptions during processing, the result is null
Contants.EXCEPTION
: exception during processing. In case of successful finishing, the exception is null
Main purpose of handling events is to perform additional initialization for in certain situations, add custom error handling or further notification etc.
Calls to methods exposed via the RendererControl interface are not routed to handleEvent
again, but calls to methods e.g. available through the RendererDocument
instance (which can be accessed via (RendererDocument)eventData.get(Constants.DOCUMENT))
are.
This example will lead to infinite recursion, whenever a PDF is rendered for a document:
((Renderer) renderer).addObserver( (event, renderer, eventData) -> { RendererDocument document = (RendererDocument)eventData.get(Constants.DOCUMENT); // causes re-invocation of handleEvent method document.createPdf(); return EventChain.CONTINUE; }, Event.CREATE_PDF_BEFORE);
The following examples adds custom font mapping based on the connection name:
public FontMap getMappingForConnection(String connectionName) throws RendererException { String fontmapXml = ""; // try { FontMap customFonts = RendererUtils.objectFromXML(new StringReader(fontmapXml), FontMap.class); return customFonts; } catch (JAXBException e) { throw new XmlException("Error while reading fontmap from input '" + fontmapXml + "'", e); } } public void addConnectionObserver() throws RendererException { ((Renderer) renderer).addObserver( (event, renderer, eventData) -> { // first clear any user space font mapping applied for the old connection renderer.clearUserFontMapping(); // load font map for the new connection FontMap customFonts = this.getMappingForConnection((String)eventData.get(Constants.NAME)); // and apply: renderer.setUserFontMapping(customFonts); return EventChain.CONTINUE; }, Event.CONNECT_BEFORE); }