Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 259   Methods: 10
NCLOC: 134   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
MAuditStreamHandler.java 0% 0% 0% 0%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant.taskdefs.optional.metamata;
 55   
 
 56   
 import java.io.BufferedReader;
 57   
 import java.io.IOException;
 58   
 import java.io.InputStream;
 59   
 import java.io.InputStreamReader;
 60   
 import java.io.OutputStream;
 61   
 import java.util.Date;
 62   
 import java.util.Enumeration;
 63   
 import java.util.Hashtable;
 64   
 import java.util.Vector;
 65   
 import javax.xml.parsers.DocumentBuilder;
 66   
 import javax.xml.parsers.DocumentBuilderFactory;
 67   
 import org.apache.tools.ant.BuildException;
 68   
 import org.apache.tools.ant.Project;
 69   
 import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;
 70   
 import org.apache.tools.ant.taskdefs.LogOutputStream;
 71   
 import org.apache.tools.ant.taskdefs.StreamPumper;
 72   
 import org.apache.tools.ant.util.DOMElementWriter;
 73   
 import org.apache.tools.ant.util.DateUtils;
 74   
 import org.w3c.dom.Document;
 75   
 import org.w3c.dom.Element;
 76   
 
 77   
 /**
 78   
  * This is a very bad stream handler for the MAudit task.
 79   
  * All report to stdout that does not match a specific report pattern is dumped
 80   
  * to the Ant output as warn level. The report that match the pattern is stored
 81   
  * in a map with the key being the filepath that caused the error report.
 82   
  * <p>
 83   
  * The limitation with the choosen implementation is clear:
 84   
  * <ul>
 85   
  * <li>it does not handle multiline report( message that has \n ). the part until
 86   
  * the \n will be stored and the other part (which will not match the pattern)
 87   
  * will go to Ant output in Warn level.
 88   
  * <li>it does not report error that goes to stderr.
 89   
  * </ul>
 90   
  *
 91   
  * @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
 92   
  */
 93   
 class MAuditStreamHandler implements ExecuteStreamHandler {
 94   
 
 95   
     /** parent task */
 96   
     private MAudit task;
 97   
 
 98   
     /** reader for stdout */
 99   
     private BufferedReader br;
 100   
 
 101   
     /**
 102   
      * this is where the XML output will go, should mostly be a file
 103   
      * the caller is responsible for flushing and closing this stream
 104   
      */
 105   
     private OutputStream xmlOut = null;
 106   
 
 107   
     /** error stream, might be useful to spit out error messages */
 108   
     private OutputStream errStream;
 109   
 
 110   
     /** thread pumping out error stream */
 111   
     private Thread errThread;
 112   
 
 113   
     /**
 114   
      * the multimap. The key in the map is the filepath that caused the audit
 115   
      * error and the value is a vector of MAudit.Violation entries.
 116   
      */
 117   
     private Hashtable auditedFiles = new Hashtable();
 118   
 
 119   
     /** program start timestamp for reporting purpose */
 120   
     private Date program_start;
 121   
 
 122  0
     MAuditStreamHandler(MAudit task, OutputStream xmlOut) {
 123  0
         this.task = task;
 124  0
         this.xmlOut = xmlOut;
 125   
     }
 126   
 
 127   
     /** Ignore. */
 128  0
     public void setProcessInputStream(OutputStream os) {
 129   
     }
 130   
 
 131   
     /** Ignore. */
 132  0
     public void setProcessErrorStream(InputStream is) {
 133  0
         errStream = new LogOutputStream(task, Project.MSG_ERR);
 134  0
         errThread = createPump(is, errStream);
 135   
     }
 136   
 
 137   
     /** Set the inputstream */
 138  0
     public void setProcessOutputStream(InputStream is) throws IOException {
 139  0
         br = new BufferedReader(new InputStreamReader(is));
 140   
     }
 141   
 
 142   
     /** Invokes parseOutput. This will block until the end :-(*/
 143  0
     public void start() throws IOException {
 144  0
         program_start = new Date();
 145  0
         errThread.start();
 146  0
         parseOutput(br);
 147   
     }
 148   
 
 149   
     /**
 150   
      * Pretty dangerous business here. It serializes what was extracted from
 151   
      * the MAudit output and write it to the output.
 152   
      */
 153  0
     public void stop() {
 154   
         // make sure to flush err stream
 155  0
         try {
 156  0
             errThread.join();
 157   
         } catch (InterruptedException e) {
 158   
         }
 159  0
         try {
 160  0
             errStream.flush();
 161   
         } catch (IOException e) {
 162   
         }
 163   
         // serialize the content as XML, move this to another method
 164   
         // this is the only code that could be needed to be overriden
 165  0
         Document doc = getDocumentBuilder().newDocument();
 166  0
         Element rootElement = doc.createElement("classes");
 167  0
         Enumeration keys = auditedFiles.keys();
 168  0
         Hashtable filemapping = task.getFileMapping();
 169  0
         final Date now = new Date();
 170  0
         rootElement.setAttribute("snapshot_created", DateUtils.format(now, DateUtils.ISO8601_DATETIME_PATTERN));
 171  0
         rootElement.setAttribute("elapsed_time", String.valueOf(now.getTime() - program_start.getTime()));
 172  0
         rootElement.setAttribute("program_start", DateUtils.format(now, DateUtils.ISO8601_DATETIME_PATTERN));
 173  0
         rootElement.setAttribute("audited", String.valueOf(filemapping.size()));
 174  0
         rootElement.setAttribute("reported", String.valueOf(auditedFiles.size()));
 175  0
         int errors = 0;
 176  0
         while (keys.hasMoreElements()) {
 177  0
             String filepath = (String) keys.nextElement();
 178  0
             Vector v = (Vector) auditedFiles.get(filepath);
 179  0
             String fullclassname = (String) filemapping.get(filepath);
 180  0
             if (fullclassname == null) {
 181  0
                 task.getProject().log("Could not find class mapping for " + filepath, Project.MSG_WARN);
 182  0
                 continue;
 183   
             }
 184  0
             int pos = fullclassname.lastIndexOf('.');
 185  0
             String pkg = (pos == -1) ? "" : fullclassname.substring(0, pos);
 186  0
             String clazzname = (pos == -1) ? fullclassname : fullclassname.substring(pos + 1);
 187  0
             Element clazz = doc.createElement("class");
 188  0
             clazz.setAttribute("package", pkg);
 189  0
             clazz.setAttribute("name", clazzname);
 190  0
             final int violationCount = v.size();
 191  0
             clazz.setAttribute("violations", String.valueOf(violationCount));
 192  0
             errors += violationCount;
 193  0
             for (int i = 0; i < violationCount; i++) {
 194  0
                 MAuditParser.Violation violation = (MAuditParser.Violation) v.elementAt(i);
 195  0
                 Element error = doc.createElement("violation");
 196  0
                 error.setAttribute("line", violation.line);
 197  0
                 error.setAttribute("message", violation.error);
 198  0
                 clazz.appendChild(error);
 199   
             }
 200  0
             rootElement.appendChild(clazz);
 201   
         }
 202  0
         rootElement.setAttribute("violations", String.valueOf(errors));
 203   
 
 204   
         // now write it to the outputstream, not very nice code
 205  0
         DOMElementWriter domWriter = new DOMElementWriter();
 206  0
         try {
 207  0
             domWriter.write(rootElement, xmlOut);
 208   
         } catch (IOException e){
 209  0
             throw new BuildException(e);
 210   
         }
 211   
     }
 212   
 
 213  0
     protected static DocumentBuilder getDocumentBuilder() {
 214  0
         try {
 215  0
             return DocumentBuilderFactory.newInstance().newDocumentBuilder();
 216   
         } catch (Exception exc) {
 217  0
             throw new ExceptionInInitializerError(exc);
 218   
         }
 219   
     }
 220   
 
 221   
     /**
 222   
      * Creates a stream pumper to copy the given input stream to the given output stream.
 223   
      */
 224  0
     protected Thread createPump(InputStream is, OutputStream os) {
 225  0
         final Thread result = new Thread(new StreamPumper(is, os));
 226  0
         result.setDaemon(true);
 227  0
         return result;
 228   
     }
 229   
 
 230   
 
 231   
     /** read each line and process it */
 232  0
     protected void parseOutput(BufferedReader br) throws IOException {
 233  0
         String line = null;
 234  0
         final MAuditParser parser = new MAuditParser();
 235  0
         while ((line = br.readLine()) != null) {
 236  0
             final MAuditParser.Violation violation = parser.parseLine(line);
 237  0
             if (violation != null) {
 238  0
                 addViolation(violation.file, violation);
 239   
             } else {
 240   
                 // this doesn't match..report it as info, it could be
 241   
                 // either the copyright, summary or a multiline message (damn !)
 242  0
                 task.log(line, Project.MSG_INFO);
 243   
             }
 244   
         }
 245   
     }
 246   
 
 247   
     /** add a violation entry for the file */
 248  0
     private void addViolation(String file, MAuditParser.Violation entry) {
 249  0
         Vector violations = (Vector) auditedFiles.get(file);
 250   
         // if there is no decl for this file yet, create it.
 251  0
         if (violations == null) {
 252  0
             violations = new Vector();
 253  0
             auditedFiles.put(file, violations);
 254   
         }
 255  0
         violations.addElement(entry);
 256   
     }
 257   
 
 258   
 }
 259