Overview

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 */ );

Observer Interface

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 operations
Since 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 operations
The 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.

Details and Examples

handleEvent Parameters

The handleEvent method interface requires 3 parameters:

Allowed Operations

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);

Example: Custom Fontmapping

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);
}