XSLTRenderer.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 
005 package net.sourceforge.pmd.renderers;
006 
007 import java.io.ByteArrayInputStream;
008 import java.io.File;
009 import java.io.FileInputStream;
010 import java.io.FileNotFoundException;
011 import java.io.IOException;
012 import java.io.InputStream;
013 import java.io.StringWriter;
014 import java.io.Writer;
015 import java.util.Properties;
016 
017 import javax.xml.parsers.DocumentBuilder;
018 import javax.xml.parsers.DocumentBuilderFactory;
019 import javax.xml.parsers.ParserConfigurationException;
020 import javax.xml.transform.Transformer;
021 import javax.xml.transform.TransformerConfigurationException;
022 import javax.xml.transform.TransformerException;
023 import javax.xml.transform.TransformerFactory;
024 import javax.xml.transform.dom.DOMSource;
025 import javax.xml.transform.stream.StreamResult;
026 import javax.xml.transform.stream.StreamSource;
027 
028 import org.w3c.dom.Document;
029 import org.xml.sax.SAXException;
030 
031 /**
032  * Renderer to XML format with a XSL Transformation applied.
033  
034  @author Romain Pelisse, belaran@gmail.com
035  */
036 public class XSLTRenderer extends XMLRenderer {
037 
038     public static final String NAME = "xslt";
039 
040     public static final String XSLT_FILENAME = "xsltFilename";
041 
042     private Transformer transformer;
043     private String xsltFilename = "/etc/pmd-nicerhtml.xsl";
044     private Writer outputWriter;
045 
046     public XSLTRenderer(Properties properties) {
047   super(properties);
048   super.setName(NAME);
049   super.setDescription("XML with a XSL Transformation applied.");
050   super.defineProperty(XSLT_FILENAME, "The XSLT file name.");
051 
052   String xsltFilename = properties.getProperty(XSLT_FILENAME);
053   if (xsltFilename != null) {
054       File file = new File(xsltFilename);
055       if (file.exists() && file.canRead()) {
056     this.xsltFilename = xsltFilename;
057       }
058   }
059     }
060 
061     /**
062      * {@inheritDoc}
063      */
064     @Override
065     public void start() throws IOException {
066   // We keep the inital writer to put the final html output
067   this.outputWriter = getWriter();
068   // We use a new one to store the XML...
069   Writer w = new StringWriter();
070   setWriter(w);
071   // If don't find the xsl no need to bother doing the all report,
072   // so we check this here...
073   InputStream xslt = null;
074   File file = new File(this.xsltFilename);
075   if (file.exists() && file.canRead()) {
076       xslt = new FileInputStream(file);
077   else {
078       xslt = this.getClass().getResourceAsStream(xsltFilename);
079   }
080   if (xslt == null) {
081       throw new FileNotFoundException("Can't file XSLT sheet :" + xsltFilename);
082   }
083   this.prepareTransformer(xslt);
084   // Now we build the XML file
085   super.start();
086     }
087 
088     /**
089      * Prepare the transformer, doing the proper "building"...
090      *
091      @param xslt The stylesheet provided as an InputStream
092      */
093     private void prepareTransformer(InputStream xslt) {
094   if (xslt != null) {
095       try {
096     //Get a TransformerFactory object
097     TransformerFactory factory = TransformerFactory.newInstance();
098     StreamSource src = new StreamSource(xslt);
099     //Get an XSL Transformer object
100     this.transformer = factory.newTransformer(src);
101       catch (TransformerConfigurationException e) {
102     e.printStackTrace();
103       }
104   }
105     }
106 
107     /**
108      * {@inheritDoc}
109      */
110     @Override
111     public void end() throws IOException {
112   // First we finish the XML report
113   super.end();
114   // Now we transform it using XSLT
115   Writer writer = super.getWriter();
116   if (writer instanceof StringWriter) {
117       StringWriter w = (StringWriterwriter;
118       StringBuffer buffer = w.getBuffer();
119       // FIXME: If we change the encoding in XMLRenderer, we should change this too !
120       InputStream xml = new ByteArrayInputStream(buffer.toString().getBytes(this.encoding));
121       Document doc = this.getDocument(xml);
122       this.transform(doc);
123   else {
124       // Should not happen !
125       new RuntimeException("Wrong writer").printStackTrace();
126   }
127 
128     }
129 
130     private void transform(Document doc) {
131   DOMSource source = new DOMSource(doc);
132   this.setWriter(new StringWriter());
133   StreamResult result = new StreamResult(this.outputWriter);
134   try {
135       transformer.transform(source, result);
136   catch (TransformerException e) {
137       e.printStackTrace();
138   }
139     }
140 
141     private Document getDocument(InputStream xml) {
142   try {
143       DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
144       return parser.parse(xml);
145   catch (ParserConfigurationException e) {
146       e.printStackTrace();
147   catch (SAXException e) {
148       e.printStackTrace();
149   catch (IOException e) {
150       e.printStackTrace();
151   }
152   return null;
153     }
154 }