Coverage Report - net.sf.statcvs.output.RepoMapPageMaker
 
Classes in this File Line Coverage Branch Coverage Complexity
RepoMapPageMaker
0%
0/175
0%
0/110
3
 
 1  
 /*
 2  
  StatCVS - CVS statistics generation
 3  
  Copyright (C) 2006 Benoit Xhenseval
 4  
 
 5  
  This library is free software; you can redistribute it and/or
 6  
  modify it under the terms of the GNU Lesser General Public
 7  
  License as published by the Free Software Foundation; either
 8  
  version 2.1 of the License, or (at your option) any later version.
 9  
 
 10  
  This library is distributed in the hope that it will be useful,
 11  
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
  Lesser General Public License for more details.
 14  
 
 15  
  You should have received a copy of the GNU Lesser General Public
 16  
  License along with this library; if not, write to the Free Software
 17  
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 
 19  
  */
 20  
 package net.sf.statcvs.output;
 21  
 
 22  
 import java.io.BufferedWriter;
 23  
 import java.io.File;
 24  
 import java.io.FileWriter;
 25  
 import java.io.IOException;
 26  
 import java.io.InputStream;
 27  
 import java.io.Writer;
 28  
 import java.util.Calendar;
 29  
 import java.util.Date;
 30  
 import java.util.Iterator;
 31  
 import java.util.SortedSet;
 32  
 
 33  
 import net.sf.statcvs.Messages;
 34  
 import net.sf.statcvs.model.Directory;
 35  
 import net.sf.statcvs.model.Repository;
 36  
 import net.sf.statcvs.model.Revision;
 37  
 import net.sf.statcvs.model.VersionedFile;
 38  
 import net.sf.statcvs.pages.HTML;
 39  
 import net.sf.statcvs.pages.NavigationNode;
 40  
 import net.sf.statcvs.pages.Page;
 41  
 import net.sf.statcvs.util.FileUtils;
 42  
 
 43  
 /**
 44  
  * New report that Repo Map, a jtreemap-based report (applet) that shows the
 45  
  * entire source tree in a hierarchical manner, the size of each box is related
 46  
  * to LOC and the colour to the changes over the last 30 days (red -loc, green
 47  
  * +loc).
 48  
  *
 49  
  * @author Benoit Xhenseval (www.objectlab.co.uk)
 50  
  * @see http://jtreemap.sourceforge.net for more about JTreeMap.
 51  
  */
 52  
 public class RepoMapPageMaker {
 53  
     private static final int DAYS_FROM_LAST_DATE = 30;
 54  
 
 55  
     private static final String WEB_FILE_PATH = "web-files/";
 56  
 
 57  
     private static final String REPO_FILE = "repomap-data.txt";
 58  
 
 59  
     private final Date deadline;
 60  
 
 61  
     private final Date currentDate;
 62  
 
 63  
     private final ReportConfig config;
 64  
 
 65  0
     private int indent = 0;
 66  
 
 67  0
     /**
 68  
      * @see net.sf.statcvs.output.HTMLPage#HTMLPage(Repository)
 69  
      */
 70  0
     public RepoMapPageMaker(final ReportConfig config) {
 71  0
         final Calendar cal = Calendar.getInstance();
 72  0
         if (config != null && config.getRepository() != null && config.getRepository().getLastDate() != null) {
 73  0
             cal.setTime(config.getRepository().getLastDate());
 74  0
         }
 75  0
         currentDate = cal.getTime();
 76  0
         cal.add(Calendar.DATE, -DAYS_FROM_LAST_DATE);
 77  0
         deadline = cal.getTime();
 78  0
         this.config = config;
 79  0
     }
 80  0
 
 81  0
     public NavigationNode toFile() {
 82  0
         final Page page = this.config.createPage("repomap", Messages.getString("REPOMAP_TITLE"), Messages.getString("REPOMAP_TITLE"));
 83  0
         page.addRawAttribute(Messages.getString("REPOMAP_START_DATE"), HTML.getDate(deadline));
 84  0
         page.addRawAttribute(Messages.getString("REPOMAP_END_DATE"), HTML.getDate(currentDate));
 85  0
 
 86  0
         page.addRawContent("<p>" + Messages.getString("REPOMAP_DESCRIPTION") + "</p>");
 87  0
         page.addRawContent("<p>" + getApplet() + "</p>");
 88  0
         page.addRawContent("<p><small>This page uses <a href=\"http://jtreemap.sourceforge.net\">JTreeMap</a>.</small></p>");
 89  0
         buildXmlForJTreeMap();
 90  0
 
 91  0
         return page;
 92  
     }
 93  0
 
 94  
     private String getApplet() {
 95  0
         return "<applet archive=\"./" + Messages.getString("JTREEMAP_JAR") + "\" code=\"net.sf.jtreemap.swing.example.JTreeMapAppletExample\""
 96  
                 + " width=\"940\" height=\"600\"><param name=\"dataFile\" value=\"" + REPO_FILE + "\"/>" + "<param name=\"viewTree\" value=\"true\"/>"
 97  0
                 + "<param name=\"showWeight\" value=\"true\"/>" + "<param name=\"valuePrefix\" value=\"Change:\"/>"
 98  
                 + "<param name=\"weightPrefix\" value=\"LOC:\"/>" + "<param name=\"dataFileType\" value=\"xml\"/>"
 99  
                 + "<param name=\"colorProvider\" value=\"HSBLog\"/>" + "</applet>";
 100  
     }
 101  
 
 102  
     private void buildXmlForJTreeMap() {
 103  0
         BufferedWriter out = null;
 104  
         try {
 105  0
             copyJar(Messages.getString("JTREEMAP_JAR"));
 106  0
             out = new BufferedWriter(new FileWriter(ConfigurationOptions.getOutputDir() + REPO_FILE));
 107  0
             out.write("<?xml version='1.0' encoding='ISO-8859-1'?>\n");
 108  0
             // out.append("<!DOCTYPE root SYSTEM \"TreeMap.dtd\" >\n");
 109  0
             out.write("<root>\n");
 110  0
             final Iterator it = config.getRepository().getDirectories().iterator();
 111  0
             if (it.hasNext()) {
 112  0
                 final Directory dir = (Directory) it.next();
 113  0
                 doDirectory(out, dir);
 114  0
             }
 115  0
             out.write("</root>");
 116  0
         } catch (final IOException e) {
 117  0
             e.printStackTrace();
 118  0
         } finally {
 119  0
             if (out != null) {
 120  0
                 try {
 121  0
                     out.close();
 122  0
                 } catch (final IOException e) {
 123  0
                     //                                        SvnConfigurationOptions.getTaskLogger().error(e.toString());
 124  0
                 }
 125  
             }
 126  0
         }
 127  0
     }
 128  0
 
 129  0
     private void copyJar(final String jtreemapJar) throws IOException {
 130  0
         InputStream stream = null;
 131  
         try {
 132  0
             stream = RepoMapPageMaker.class.getResourceAsStream(WEB_FILE_PATH + jtreemapJar);
 133  0
             if (stream != null) {
 134  0
                 FileUtils.copyFile(stream, new File(ConfigurationOptions.getOutputDir() + jtreemapJar));
 135  0
             } else {
 136  0
                 throw new IOException("The stream to " + (WEB_FILE_PATH + jtreemapJar) + " failed, is it copied in the jar?");
 137  
             }
 138  0
         } finally {
 139  0
             if (stream != null) {
 140  0
                 stream.close();
 141  0
             }
 142  0
         }
 143  0
     }
 144  
 
 145  0
     private void addSpaces(final int count, final BufferedWriter out) throws IOException {
 146  0
         out.write(getSpaces(count));
 147  0
     }
 148  0
 
 149  0
     private String getSpaces(final int count) {
 150  0
         final StringBuffer result = new StringBuffer();
 151  0
         for (int i = 0; i < count; i++) {
 152  0
             result.append("  ");
 153  0
         }
 154  0
         return result.toString();
 155  
     }
 156  0
 
 157  
     private void doDirectory(final BufferedWriter out, final Directory dir) throws IOException {
 158  0
         indent++;
 159  
         //                SvnConfigurationOptions.getTaskLogger().log("Directory:" + getSpaces(indent) + dir.getName());
 160  0
 
 161  0
         if (dir.isEmpty()) {
 162  0
             indent--;
 163  0
             return;
 164  0
         }
 165  0
 
 166  0
         final SortedSet set = dir.getSubdirectories();
 167  0
         final SortedSet files = dir.getFiles();
 168  0
         final String name = dir.isRoot() ? Messages.getString("NAVIGATION_ROOT") : dir.getName();
 169  0
         boolean addedBranch = false;
 170  0
         if (indent > 1 && set != null && !set.isEmpty()) {
 171  0
             out.write("\n");
 172  0
             addSpaces(indent, out);
 173  0
             out.write("<branch>\n");
 174  0
             addSpaces(indent + 2, out);
 175  0
             labelTag(out, name);
 176  0
             addedBranch = true;
 177  0
         } else if (indent == 1) {
 178  0
             addSpaces(indent, out);
 179  0
             labelTag(out, name);
 180  0
         }
 181  0
         if (set != null) {
 182  0
             for (final Iterator it2 = set.iterator(); it2.hasNext();) {
 183  0
                 doDirectory(out, (Directory) it2.next());
 184  0
             }
 185  0
         }
 186  0
         addedBranch = handleEachFileInDir(out, files, name, addedBranch);
 187  0
         if (addedBranch) {
 188  0
             addSpaces(indent, out);
 189  0
             out.write("</branch>\n");
 190  0
         }
 191  0
         indent--;
 192  0
     }
 193  0
 
 194  0
     private boolean handleEachFileInDir(final BufferedWriter out, final SortedSet files, final String name, boolean addedBranch) throws IOException {
 195  0
         if (files != null && !files.isEmpty()) {
 196  0
             for (final Iterator file = files.iterator(); file.hasNext();) {
 197  0
                 final VersionedFile vfile = (VersionedFile) file.next();
 198  0
 
 199  0
                 int loc = vfile.getCurrentLinesOfCode();
 200  
 
 201  0
                 //                                SvnConfigurationOptions.getTaskLogger().log("File:" + vfile.getFilename() + " LOC:" + loc);
 202  
 
 203  0
                 final int delta = calculateTotalDelta(vfile);
 204  0
                 if (loc == 0) {
 205  0
                     loc = Math.abs(delta);
 206  0
                 }
 207  0
                 if (loc == 0) {
 208  0
                     continue;
 209  0
                 }
 210  0
                 if (!addedBranch) {
 211  0
                     out.write("\n");
 212  0
                     addSpaces(indent, out);
 213  0
                     out.write("<branch>\n");
 214  0
                     addSpaces(indent + 2, out);
 215  0
                     labelTag(out, name);
 216  0
                     out.write("\n");
 217  0
                     addedBranch = true;
 218  0
                 }
 219  0
                 addSpaces(indent + 2, out);
 220  0
                 out.write("<leaf>");
 221  0
                 labelTag(out, vfile.getFilename());
 222  0
                 tag(out, "weight", String.valueOf(loc));
 223  0
                 final double percentage = ((double) delta) / (double) loc * 100.0;
 224  0
                 tag(out, "value", String.valueOf(percentage));
 225  0
                 out.write("</leaf>\n");
 226  0
                 //                                SvnConfigurationOptions.getTaskLogger().log("===========>>> LOC=" + loc + " totalDelta=" + delta + " Delta%=" + percentage);
 227  0
             }
 228  
         }
 229  0
         return addedBranch;
 230  
     }
 231  0
 
 232  
     private int calculateTotalDelta(final VersionedFile vfile) {
 233  0
         int delta = 0;
 234  0
         final SortedSet revisions = vfile.getRevisions();
 235  0
         // take all deltas for the last 30 days.
 236  0
         for (final Iterator rev = revisions.iterator(); rev.hasNext();) {
 237  0
             final Revision revision = (Revision) rev.next();
 238  0
 
 239  0
             //                        SvnConfigurationOptions.getTaskLogger().log(
 240  
             //                                "Revision " + revision.getDate() + " file:" + vfile.getFilename() + " Dead:" + vfile.isDead() + " LOC:" + revision.getLines() + " delta:"
 241  
             //                                        + revision.getLinesDelta());
 242  
 
 243  0
             if (deadline.before(revision.getDate())) {
 244  0
                 delta += revision.getLinesDelta();
 245  0
 
 246  0
                 //                                SvnConfigurationOptions.getTaskLogger().log(
 247  
                 //                                        "Revision " + revision.getRevisionNumber() + " Delta:" + revision.getLinesDelta() + " totalDelta:" + delta + " LOC:"
 248  
                 //                                                + revision.getLines() + " Dead:" + revision.isDead());
 249  
             }
 250  0
         }
 251  0
         return delta;
 252  0
     }
 253  0
 
 254  
     private void labelTag(final Writer result, final String name) throws IOException {
 255  0
         if (name == null || name.length() == 0) {
 256  0
             tag(result, "label", "[root]");
 257  0
         } else {
 258  0
             tag(result, "label", name);
 259  
         }
 260  0
     }
 261  
 
 262  0
     private void tag(final Writer result, final String tagName, final String value) throws IOException {
 263  0
         result.write("<");
 264  0
         result.write(tagName);
 265  0
         result.write(">");
 266  0
         result.write(value);
 267  0
         result.write("</");
 268  0
         result.write(tagName);
 269  0
         result.write(">");
 270  0
     }
 271  0
 }