blob: a77ee6a033ec7fbc72f97b1f231fb2065e23290a [file] [log] [blame]
/*
* 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.render;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.util.Service;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.fo.FOEventHandler;
/**
* Factory for FOEventHandlers and Renderers.
*/
public class RendererFactory {
/** the logger */
private static Log log = LogFactory.getLog(RendererFactory.class);
private Map rendererMakerMapping = new java.util.HashMap();
private Map eventHandlerMakerMapping = new java.util.HashMap();
/**
* Main constructor.
*/
public RendererFactory() {
discoverRenderers();
discoverFOEventHandlers();
}
/**
* Add a new RendererMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param maker the RendererMaker
*/
public void addRendererMaker(AbstractRendererMaker maker) {
String[] mimes = maker.getSupportedMimeTypes();
for (int i = 0; i < mimes.length; i++) {
//This overrides any renderer previously set for a MIME type
if (rendererMakerMapping.get(mimes[i]) != null) {
log.trace("Overriding renderer for " + mimes[i]
+ " with " + maker.getClass().getName());
}
rendererMakerMapping.put(mimes[i], maker);
}
}
/**
* Add a new FOEventHandlerMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param maker the FOEventHandlerMaker
*/
public void addFOEventHandlerMaker(AbstractFOEventHandlerMaker maker) {
String[] mimes = maker.getSupportedMimeTypes();
for (int i = 0; i < mimes.length; i++) {
//This overrides any event handler previously set for a MIME type
if (eventHandlerMakerMapping.get(mimes[i]) != null) {
log.trace("Overriding FOEventHandler for " + mimes[i]
+ " with " + maker.getClass().getName());
}
eventHandlerMakerMapping.put(mimes[i], maker);
}
}
/**
* Add a new RendererMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param className the fully qualified class name of the RendererMaker
*/
public void addRendererMaker(String className) {
try {
AbstractRendererMaker makerInstance
= (AbstractRendererMaker)Class.forName(className).newInstance();
addRendererMaker(makerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
+ className);
} catch (InstantiationException e) {
throw new IllegalArgumentException("Could not instantiate "
+ className);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not access "
+ className);
} catch (ClassCastException e) {
throw new IllegalArgumentException(className
+ " is not an "
+ AbstractRendererMaker.class.getName());
}
}
/**
* Add a new FOEventHandlerMaker. If another maker has already been registered for a
* particular MIME type, this call overwrites the existing one.
* @param className the fully qualified class name of the FOEventHandlerMaker
*/
public void addFOEventHandlerMaker(String className) {
try {
AbstractFOEventHandlerMaker makerInstance
= (AbstractFOEventHandlerMaker)Class.forName(className).newInstance();
addFOEventHandlerMaker(makerInstance);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Could not find "
+ className);
} catch (InstantiationException e) {
throw new IllegalArgumentException("Could not instantiate "
+ className);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Could not access "
+ className);
} catch (ClassCastException e) {
throw new IllegalArgumentException(className
+ " is not an "
+ AbstractFOEventHandlerMaker.class.getName());
}
}
/**
* Returns a RendererMaker which handles the given MIME type.
* @param mime the requested output format
* @return the requested RendererMaker or null if none is available
*/
public AbstractRendererMaker getRendererMaker(String mime) {
AbstractRendererMaker maker
= (AbstractRendererMaker)rendererMakerMapping.get(mime);
return maker;
}
/**
* Returns a FOEventHandlerMaker which handles the given MIME type.
* @param mime the requested output format
* @return the requested FOEventHandlerMaker or null if none is available
*/
public AbstractFOEventHandlerMaker getFOEventHandlerMaker(String mime) {
AbstractFOEventHandlerMaker maker
= (AbstractFOEventHandlerMaker)eventHandlerMakerMapping.get(mime);
return maker;
}
/**
* Creates a Renderer object based on render-type desired
* @param userAgent the user agent for access to configuration
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
* @return the new Renderer instance
* @throws FOPException if the renderer cannot be properly constructed
*/
public Renderer createRenderer(FOUserAgent userAgent, String outputFormat)
throws FOPException {
if (userAgent.getRendererOverride() != null) {
return userAgent.getRendererOverride();
} else {
AbstractRendererMaker maker = getRendererMaker(outputFormat);
if (maker == null) {
throw new UnsupportedOperationException(
"No renderer for the requested format available: " + outputFormat);
}
Renderer rend = maker.makeRenderer(userAgent);
rend.setUserAgent(userAgent);
RendererConfigurator configurator = maker.getConfigurator(userAgent);
if (configurator != null) {
configurator.configure(rend);
}
return rend;
}
}
/**
* Creates FOEventHandler instances based on the desired output.
* @param userAgent the user agent for access to configuration
* @param outputFormat the MIME type of the output format to use (ex. "application/pdf").
* @param out the OutputStream where the output is written to (if applicable)
* @return the newly constructed FOEventHandler
* @throws FOPException if the FOEventHandler cannot be properly constructed
*/
public FOEventHandler createFOEventHandler(FOUserAgent userAgent,
String outputFormat, OutputStream out) throws FOPException {
if (userAgent.getFOEventHandlerOverride() != null) {
return userAgent.getFOEventHandlerOverride();
} else {
AbstractFOEventHandlerMaker maker = getFOEventHandlerMaker(outputFormat);
if (maker == null) {
AbstractRendererMaker rendMaker = getRendererMaker(outputFormat);
if (rendMaker == null && userAgent.getRendererOverride() == null) {
throw new UnsupportedOperationException(
"Don't know how to handle \"" + outputFormat + "\" as an output format."
+ " Neither an FOEventHandler, nor a Renderer could be found"
+ " for this output format.");
} else {
if (out == null
&& userAgent.getRendererOverride() == null
&& rendMaker.needsOutputStream()) {
throw new FOPException(
"OutputStream has not been set");
}
//Found a Renderer so we need to construct an AreaTreeHandler.
return new AreaTreeHandler(userAgent, outputFormat, out);
}
} else {
return maker.makeFOEventHandler(userAgent, out);
}
}
}
/**
* @return an array of all supported MIME types
*/
public String[] listSupportedMimeTypes() {
List lst = new java.util.ArrayList();
Iterator iter = this.rendererMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
}
iter = this.eventHandlerMakerMapping.keySet().iterator();
while (iter.hasNext()) {
lst.add(((String)iter.next()));
}
Collections.sort(lst);
return (String[])lst.toArray(new String[lst.size()]);
}
/**
* Discovers Renderer implementations through the classpath and dynamically
* registers them.
*/
private void discoverRenderers() {
// add mappings from available services
Iterator providers
= Service.providers(Renderer.class);
if (providers != null) {
while (providers.hasNext()) {
AbstractRendererMaker maker = (AbstractRendererMaker)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding maker for Renderer: "
+ maker.getClass().getName());
}
addRendererMaker(maker);
} catch (IllegalArgumentException e) {
log.error("Error while adding maker for Renderer", e);
}
}
}
}
/**
* Discovers FOEventHandler implementations through the classpath and dynamically
* registers them.
*/
private void discoverFOEventHandlers() {
// add mappings from available services
Iterator providers
= Service.providers(FOEventHandler.class);
if (providers != null) {
while (providers.hasNext()) {
AbstractFOEventHandlerMaker maker = (AbstractFOEventHandlerMaker)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding maker for FOEventHandler: "
+ maker.getClass().getName());
}
addFOEventHandlerMaker(maker);
} catch (IllegalArgumentException e) {
log.error("Error while adding maker for FOEventHandler", e);
}
}
}
}
}