View Javadoc

    1   /**
    2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
    3    */
    4   package net.sourceforge.pmd.renderers;
    5
    6   import java.lang.reflect.Constructor;
    7   import java.lang.reflect.InvocationTargetException;
    8   import java.lang.reflect.Modifier;
    9   import java.util.Collections;
    10  import java.util.Map;
    11  import java.util.Properties;
    12  import java.util.TreeMap;
    13  import java.util.logging.Logger;
    14
    15  import net.sourceforge.pmd.PropertyDescriptor;
    16
    17  /**
    18   * This class handles the creation of Renderers.
    19   * @see Renderer
    20   */
    21  public class RendererFactory {
    22
    23      private static final Logger LOG = Logger.getLogger(RendererFactory.class.getName());
    24
    25      public static final Map<String, Class<? extends Renderer>> REPORT_FORMAT_TO_RENDERER;
    26      static {
    27  	Map<String, Class<? extends Renderer>> map = new TreeMap<String, Class<? extends Renderer>>();
    28  	map.put(XMLRenderer.NAME, XMLRenderer.class);
    29  	map.put(IDEAJRenderer.NAME, IDEAJRenderer.class);
    30  	map.put(TextColorRenderer.NAME, TextColorRenderer.class);
    31  	map.put(TextRenderer.NAME, TextRenderer.class);
    32  	map.put(TextPadRenderer.NAME, TextPadRenderer.class);
    33  	map.put(EmacsRenderer.NAME, EmacsRenderer.class);
    34  	map.put(CSVRenderer.NAME, CSVRenderer.class);
    35  	map.put(HTMLRenderer.NAME, HTMLRenderer.class);
    36  	map.put(XSLTRenderer.NAME, XSLTRenderer.class);
    37  	map.put(YAHTMLRenderer.NAME, YAHTMLRenderer.class);
    38  	map.put(SummaryHTMLRenderer.NAME, SummaryHTMLRenderer.class);
    39  	map.put(VBHTMLRenderer.NAME, VBHTMLRenderer.class);
    40  	REPORT_FORMAT_TO_RENDERER = Collections.unmodifiableMap(map);
    41      }
    42
    43      /**
    44       * Construct an instance of a Renderer based on report format name.
    45       * @param reportFormat The report format name.
    46       * @param properties Initialization properties for the corresponding Renderer.
    47       * @return A Renderer instance.
    48       */
    49      public static Renderer createRenderer(String reportFormat, Properties properties) {
    50  	Class<? extends Renderer> rendererClass = getRendererClass(reportFormat);
    51  	Constructor<? extends Renderer> constructor = getRendererConstructor(rendererClass);
    52
    53  	Renderer renderer;
    54  	try {
    55  	    if (constructor.getParameterTypes().length > 0) {
    56  		LOG.warning("The renderer uses a deprecated mechanism to use the properties. Please define the needed properties with this.definePropertyDescriptor(..).");
    57  		renderer = constructor.newInstance(properties);
    58  	    } else {
    59  		renderer = constructor.newInstance();
    60
    61  		for (PropertyDescriptor<?> prop : renderer.getPropertyDescriptors()) {
    62  		    String value = properties.getProperty(prop.name());
    63  		    if (value != null) {
    64  			@SuppressWarnings("unchecked")
    65  			PropertyDescriptor<Object> prop2 = (PropertyDescriptor<Object>)prop;
    66  			Object valueFrom = prop2.valueFrom(value);
    67  			renderer.setProperty(prop2, valueFrom);
    68  		    }
    69  		}
    70  	    }
    71  	} catch (InstantiationException e) {
    72  	    throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage());
    73  	} catch (IllegalAccessException e) {
    74  	    throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage());
    75  	} catch (InvocationTargetException e) {
    76  	    throw new IllegalArgumentException("Unable to construct report renderer class: "
    77  		    + e.getTargetException().getLocalizedMessage());
    78  	}
    79  	// Warn about legacy report format usages
    80  	if (REPORT_FORMAT_TO_RENDERER.containsKey(reportFormat) && !reportFormat.equals(renderer.getName())) {
    81  	    LOG.warning("Report format '" + reportFormat + "' is deprecated, and has been replaced with '"
    82  		    + renderer.getName()
    83  		    + "'. Future versions of PMD will remove support for this deprecated Report format usage.");
    84  	}
    85  	return renderer;
    86      }
    87
    88      @SuppressWarnings("unchecked")
    89      private static Class<? extends Renderer> getRendererClass(String reportFormat) {
    90  	Class<? extends Renderer> rendererClass = REPORT_FORMAT_TO_RENDERER.get(reportFormat);
    91
    92  	// Look up a custom renderer class
    93  	if (rendererClass == null && !"".equals(reportFormat)) {
    94  	    try {
    95  		Class<?> clazz = Class.forName(reportFormat);
    96  		if (!Renderer.class.isAssignableFrom(clazz)) {
    97  		    throw new IllegalArgumentException("Custom report renderer class does not implement the "
    98  			    + Renderer.class.getName() + " interface.");
    99  		} else {
    100 		    rendererClass = (Class<? extends Renderer>) clazz;
    101 		}
    102 	    } catch (ClassNotFoundException e) {
    103 		throw new IllegalArgumentException("Can't find the custom format " + reportFormat + ": "
    104 			+ e.getClass().getName());
    105 	    }
    106 	}
    107 	return rendererClass;
    108     }
    109
    110     private static Constructor<? extends Renderer> getRendererConstructor(Class<? extends Renderer> rendererClass) {
    111 	Constructor<? extends Renderer> constructor = null;
    112
    113 	// 1) Properties constructor? - deprecated
    114 	try {
    115 	    constructor = rendererClass.getConstructor(Properties.class);
    116 	    if (!Modifier.isPublic(constructor.getModifiers())) {
    117 		constructor = null;
    118 	    }
    119 	} catch (NoSuchMethodException e) {
    120 	    // Ok
    121 	}
    122
    123 	// 2) No-arg constructor?
    124 	try {
    125 	    constructor = rendererClass.getConstructor();
    126 	    if (!Modifier.isPublic(constructor.getModifiers())) {
    127 		constructor = null;
    128 	    }
    129 	} catch (NoSuchMethodException e2) {
    130 	    // Ok
    131 	}
    132
    133 	if (constructor == null) {
    134 	    throw new IllegalArgumentException(
    135 		    "Unable to find either a public java.util.Properties or no-arg constructors for Renderer class: "
    136 			    + rendererClass.getName());
    137 	}
    138 	return constructor;
    139     }
    140 }