blob: d4d9b89d29d3951378a706b6532d2544604ba49e [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.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.util.Service;
/**
* This class holds references to various image handlers. It also
* supports automatic discovery of additional handlers available through
* the class path.
*/
public class ImageHandlerRegistry {
/** the logger */
private static Log log = LogFactory.getLog(ImageHandlerRegistry.class);
private static final Comparator<ImageHandler> HANDLER_COMPARATOR
= new Comparator<ImageHandler>() {
public int compare(ImageHandler o1, ImageHandler o2) {
ImageHandler h1 = o1;
ImageHandler h2 = o2;
return h1.getPriority() - h2.getPriority();
}
};
/** Map containing image handlers for various {@link Image} subclasses. */
private Map<Class<? extends Image>, ImageHandler> handlers
= new java.util.HashMap<Class<? extends Image>, ImageHandler>();
/** List containing the same handlers as above but ordered by priority */
private List<ImageHandler> handlerList = new java.util.LinkedList<ImageHandler>();
private int handlerRegistrations;
/**
* Default constructor.
*/
public ImageHandlerRegistry() {
discoverHandlers();
}
/**
* Add an PDFImageHandler. The handler itself is inspected to find out what it supports.
* @param classname the fully qualified class name
*/
public void addHandler(String classname) {
try {
ImageHandler handlerInstance
= (ImageHandler)Class.forName(classname).getDeclaredConstructor().newInstance();
addHandler(handlerInstance);
} 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 "
+ ImageHandler.class.getName());
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
/**
* Add an image handler. The handler itself is inspected to find out what it supports.
* @param handler the ImageHandler instance
*/
public synchronized void addHandler(ImageHandler handler) {
Class<? extends Image> imageClass = handler.getSupportedImageClass();
//List
this.handlers.put(imageClass, handler);
//Sorted insert (sort by priority)
ListIterator<ImageHandler> iter = this.handlerList.listIterator();
while (iter.hasNext()) {
ImageHandler h = iter.next();
if (HANDLER_COMPARATOR.compare(handler, h) < 0) {
iter.previous();
break;
}
}
iter.add(handler);
this.handlerRegistrations++;
}
/**
* Returns an {@link ImageHandler} which handles an specific image type given the MIME type
* of the image.
* @param targetContext the target rendering context that is used for identifying compatibility
* @param image the Image to be handled
* @return the image handler responsible for handling the image or null if none is available
*/
public ImageHandler getHandler(RenderingContext targetContext, Image image) {
for (ImageHandler h : this.handlerList) {
if (h.isCompatible(targetContext, image)) {
//Return the first handler in the prioritized list that is compatible
return h;
}
}
return null;
}
/**
* Returns the ordered array of supported image flavors. The array needs to be ordered by
* priority so the image loader framework can return the preferred image type.
* @param context the rendering context
* @return the array of image flavors
*/
public synchronized ImageFlavor[] getSupportedFlavors(RenderingContext context) {
//Extract all ImageFlavors into a single array
List<ImageFlavor> flavors = new java.util.ArrayList<ImageFlavor>();
for (ImageHandler handler : this.handlerList) {
if (handler.isCompatible(context, null)) {
ImageFlavor[] f = handler.getSupportedImageFlavors();
Collections.addAll(flavors, f);
}
}
return flavors.toArray(new ImageFlavor[flavors.size()]);
}
/**
* Discovers ImageHandler implementations through the classpath and dynamically
* registers them.
*/
private void discoverHandlers() {
// add mappings from available services
Iterator providers = Service.providers(ImageHandler.class);
if (providers != null) {
while (providers.hasNext()) {
ImageHandler handler = (ImageHandler)providers.next();
try {
if (log.isDebugEnabled()) {
log.debug("Dynamically adding ImageHandler: "
+ handler.getClass().getName());
}
addHandler(handler);
} catch (IllegalArgumentException e) {
log.error("Error while adding ImageHandler", e);
}
}
}
}
}