package org.hipi.image; //import org.hipi.image.HipiImage; import org.hipi.image.HipiImage.HipiImageType; import org.apache.hadoop.mapreduce.Mapper; import java.lang.reflect.Method; /** * Factory for creating concrete objects derived from the abstract HipiImage base class. * A HipiImageFactory object may be constructed using either a {@link HipiImageType} that indicates * the type of HipiImage object that is desired or from a {@link org.apache.hadoop.mapreduce.Mapper} * object. In the latter case, HipiImageFactory class uses the Java reflection utils to locate and * interrogatethe map method in the provided Mapper class to determine the type of HipiImage object * that is desired. Specifically, it looks for a map method in the Mapper class whose first argument * (key) is a {@link HipiImageHeader} object and verifies that the second argument (value) can be * assigned to a {@link HipiImage} object. If successful, new objects of the desired type can be * produced by calling the {@link HipiImageFactory#createImage} method. This functionality is * particularly useful for the {@link org.hipi.imagebundle.mapreduce.HibRecordReader} class. */ public class HipiImageFactory { private static final HipiImageFactory staticFloatImageFactory = new HipiImageFactory(HipiImageType.FLOAT); public static HipiImageFactory getFloatImageFactory() { return staticFloatImageFactory; } private static final HipiImageFactory staticByteImageFactory = new HipiImageFactory(HipiImageType.BYTE); public static HipiImageFactory getByteImageFactory() { return staticByteImageFactory; } private Class<?> imageClass = null; private HipiImageType imageType = HipiImageType.UNDEFINED; public HipiImageFactory(Class<? extends Mapper<?,?,?,?>> mapperClass) throws InstantiationException, IllegalAccessException, ExceptionInInitializerError, SecurityException, RuntimeException { findImageClass(mapperClass); HipiImage image = (HipiImage)imageClass.newInstance(); imageType = image.getType(); } public HipiImageFactory(HipiImageType imageType) throws IllegalArgumentException { // Call appropriate decode function based on type of image object switch (imageType) { case FLOAT: imageClass = FloatImage.class; break; case BYTE: imageClass = ByteImage.class; break; case RAW: imageClass = RawImage.class; case UNDEFINED: default: throw new IllegalArgumentException("Unexpected image type. Cannot proceed."); } this.imageType = imageType; } private void findImageClass(Class<? extends Mapper<?,?,?,?>> mapperClass) throws SecurityException, RuntimeException { for (Method method : mapperClass.getMethods()) { // Find map method (there will be at least two: one in concrete // base class and one in abstract Mapper superclass) if (!method.getName().equals("map")) { continue; } // Get parameter list of map method Class<?> params[] = method.getParameterTypes(); if (params.length != 3) { continue; } // Use the fact that first parameter should be ImageHeader // object to identify target map method if (params[0] != HipiImageHeader.class) { continue; } // Store pointer to requested image class imageClass = params[1]; } if (imageClass == null) { throw new RuntimeException("Failed to determine image class used in " + "mapper (second argument in map method)."); } if (!HipiImage.class.isAssignableFrom(imageClass)) { throw new RuntimeException("Found image class [" + imageClass + "], but it's not " + "derived from HipiImage as required."); } } public HipiImageType getType() { return imageType; } public HipiImage createImage(HipiImageHeader imageHeader) throws InstantiationException, IllegalAccessException, ExceptionInInitializerError, SecurityException, IllegalArgumentException { HipiImage image = (HipiImage)imageClass.newInstance(); image.setHeader(imageHeader); return image; } }