/* * 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.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 used by the renderers. It also * supports automatic discovery of additional handlers available through * the class path. */ public abstract class AbstractImageHandlerRegistry { /** the logger */ private static Log log = LogFactory.getLog(AbstractImageHandlerRegistry.class); private static final Comparator HANDLER_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { ImageHandlerBase h1 = (ImageHandlerBase)o1; ImageHandlerBase h2 = (ImageHandlerBase)o2; return h1.getPriority() - h2.getPriority(); } }; /** Map containing image handlers for various MIME types */ private final Map/**/ handlers = new java.util.HashMap/**/(); /** List containing the same handlers as above but ordered by priority */ private final List/**/ handlerList = new java.util.LinkedList/**/(); /** Sorted Set of registered handlers */ private ImageFlavor[] supportedFlavors = new ImageFlavor[0]; private int handlerRegistrations; private int lastSync; /** * Default constructor. */ public AbstractImageHandlerRegistry() { discoverHandlers(); } /** * Add an ImageHandler. The handler itself is inspected to find out what it supports. * @param classname the fully qualified class name */ public void addHandler(String classname) { try { ImageHandlerBase handlerInstance = (ImageHandlerBase)Class.forName(classname).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 " + getHandlerClass().getName()); } } /** * Add an image handler. The handler itself is inspected to find out what it supports. * @param handler the ImageHandler instance */ public synchronized void addHandler(ImageHandlerBase handler) { this.handlers.put(handler.getSupportedImageClass(), handler); //Sorted insert ListIterator iter = this.handlerList.listIterator(); while (iter.hasNext()) { ImageHandlerBase h = (ImageHandlerBase)iter.next(); if (getHandlerComparator().compare(handler, h) < 0) { iter.previous(); break; } } iter.add(handler); this.handlerRegistrations++; } /** * Returns an ImageHandler which handles an specific image type given the MIME type * of the image. * @param img the Image to be handled * @return the ImageHandler responsible for handling the image or null if none is available */ public ImageHandlerBase getHandler(Image img) { return getHandler(img.getClass()); } /** * Returns an ImageHandler which handles an specific image type given the MIME type * of the image. * @param imageClass the Image subclass for which to get a handler * @return the ImageHandler responsible for handling the image or null if none is available */ public synchronized ImageHandlerBase getHandler(Class imageClass) { ImageHandlerBase handler = null; Class cl = imageClass; while (cl != null) { handler = (ImageHandlerBase)handlers.get(cl); if (handler != null) { break; } cl = cl.getSuperclass(); } return handler; } /** * Returns the ordered array of supported image flavors. * @return the array of image flavors */ public synchronized ImageFlavor[] getSupportedFlavors() { if (this.lastSync != this.handlerRegistrations) { //Extract all ImageFlavors into a single array List flavors = new java.util.ArrayList(); Iterator iter = this.handlerList.iterator(); while (iter.hasNext()) { ImageFlavor[] f = ((ImageHandlerBase)iter.next()).getSupportedImageFlavors(); for (int i = 0; i < f.length; i++) { flavors.add(f[i]); } } this.supportedFlavors = (ImageFlavor[])flavors.toArray(new ImageFlavor[flavors.size()]); this.lastSync = this.handlerRegistrations; } return this.supportedFlavors; } /** * Discovers ImageHandler implementations through the classpath and dynamically * registers them. */ private void discoverHandlers() { // add mappings from available services Class imageHandlerClass = getHandlerClass(); Iterator providers = Service.providers(imageHandlerClass); if (providers != null) { while (providers.hasNext()) { ImageHandlerBase handler = (ImageHandlerBase)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); } } } } /** * Returns the ImageHandler comparator * * @return the ImageHandler comparator */ public Comparator getHandlerComparator() { return HANDLER_COMPARATOR; } /** * Returns the ImageHandler implementing class * * @return the ImageHandler implementing class */ public abstract Class getHandlerClass(); }