001 /**
002 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003 */
004 package net.sourceforge.pmd.renderers;
005
006 import java.lang.reflect.Constructor;
007 import java.lang.reflect.InvocationTargetException;
008 import java.lang.reflect.Modifier;
009 import java.util.Collections;
010 import java.util.Map;
011 import java.util.Properties;
012 import java.util.TreeMap;
013 import java.util.logging.Logger;
014
015 /**
016 * This class handles the creation of Renderers.
017 * @see Renderer
018 */
019 public class RendererFactory {
020
021 private static final Logger LOG = Logger.getLogger(RendererFactory.class.getName());
022
023 public static final Map<String, Class<? extends Renderer>> REPORT_FORMAT_TO_RENDERER;
024 static {
025 Map<String, Class<? extends Renderer>> map = new TreeMap<String, Class<? extends Renderer>>();
026 map.put(XMLRenderer.NAME, XMLRenderer.class);
027 map.put(IDEAJRenderer.NAME, IDEAJRenderer.class);
028 map.put(TextColorRenderer.NAME, TextColorRenderer.class);
029 map.put("papari", TextColorRenderer.class); // TODO Remove when we drop backward compatibility.
030 map.put(TextRenderer.NAME, TextRenderer.class);
031 map.put(TextPadRenderer.NAME, TextPadRenderer.class);
032 map.put(EmacsRenderer.NAME, EmacsRenderer.class);
033 map.put(CSVRenderer.NAME, CSVRenderer.class);
034 map.put(HTMLRenderer.NAME, HTMLRenderer.class);
035 map.put("nicehtml", XSLTRenderer.class); // TODO Remove when we drop backward compatibility.
036 map.put(XSLTRenderer.NAME, XSLTRenderer.class);
037 map.put(YAHTMLRenderer.NAME, YAHTMLRenderer.class);
038 map.put(SummaryHTMLRenderer.NAME, SummaryHTMLRenderer.class);
039 map.put(VBHTMLRenderer.NAME, VBHTMLRenderer.class);
040 REPORT_FORMAT_TO_RENDERER = Collections.unmodifiableMap(map);
041 }
042
043 /**
044 * Construct an instance of a Renderer based on report format name.
045 * @param reportFormat The report format name.
046 * @param properties Initialization properties for the corresponding Renderer.
047 * @return A Renderer instance.
048 */
049 public static Renderer createRenderer(String reportFormat, Properties properties) {
050 Class<? extends Renderer> rendererClass = getRendererClass(reportFormat);
051 Constructor<? extends Renderer> constructor = getRendererConstructor(rendererClass);
052
053 Renderer renderer;
054 try {
055 if (constructor.getParameterTypes().length > 0) {
056 renderer = constructor.newInstance(properties);
057 } else {
058 renderer = constructor.newInstance();
059 }
060 } catch (InstantiationException e) {
061 throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage());
062 } catch (IllegalAccessException e) {
063 throw new IllegalArgumentException("Unable to construct report renderer class: " + e.getLocalizedMessage());
064 } catch (InvocationTargetException e) {
065 throw new IllegalArgumentException("Unable to construct report renderer class: "
066 + e.getTargetException().getLocalizedMessage());
067 }
068 // Warn about legacy report format usages
069 if (REPORT_FORMAT_TO_RENDERER.containsKey(reportFormat) && !reportFormat.equals(renderer.getName())) {
070 LOG.warning("Report format '" + reportFormat + "' is deprecated, and has been replaced with '"
071 + renderer.getName()
072 + "'. Future versions of PMD will remove support for this deprecated Report format usage.");
073 }
074 return renderer;
075 }
076
077 @SuppressWarnings("unchecked")
078 private static Class<? extends Renderer> getRendererClass(String reportFormat) {
079 Class<? extends Renderer> rendererClass = REPORT_FORMAT_TO_RENDERER.get(reportFormat);
080
081 // Look up a custom renderer class
082 if (rendererClass == null && !"".equals(reportFormat)) {
083 try {
084 Class<?> clazz = Class.forName(reportFormat);
085 if (!Renderer.class.isAssignableFrom(clazz)) {
086 throw new IllegalArgumentException("Custom report renderer class does not implement the "
087 + Renderer.class.getName() + " interface.");
088 } else {
089 rendererClass = (Class<? extends Renderer>) clazz;
090 }
091 } catch (ClassNotFoundException e) {
092 throw new IllegalArgumentException("Can't find the custom format " + reportFormat + ": "
093 + e.getClass().getName());
094 }
095 }
096 return rendererClass;
097 }
098
099 private static Constructor<? extends Renderer> getRendererConstructor(Class<? extends Renderer> rendererClass) {
100 Constructor<? extends Renderer> constructor = null;
101
102 // 1) Properties constructor?
103 try {
104 constructor = rendererClass.getConstructor(Properties.class);
105 if (!Modifier.isPublic(constructor.getModifiers())) {
106 constructor = null;
107 }
108 } catch (NoSuchMethodException e) {
109 // Ok
110 }
111
112 // 2) No-arg constructor?
113 try {
114 constructor = rendererClass.getConstructor();
115 if (!Modifier.isPublic(constructor.getModifiers())) {
116 constructor = null;
117 }
118 } catch (NoSuchMethodException e2) {
119 // Ok
120 }
121
122 if (constructor == null) {
123 throw new IllegalArgumentException(
124 "Unable to find either a public java.util.Properties or no-arg constructors for Renderer class: "
125 + rendererClass.getName());
126 }
127 return constructor;
128 }
129 }
|