001 package org.hackystat.sensor.ant.javancss; 002 003 import java.io.File; 004 import java.util.ArrayList; 005 import java.util.HashMap; 006 import java.util.List; 007 import java.util.Map; 008 import java.util.Set; 009 010 import org.hackystat.sensor.ant.javancss.jaxb.Function; 011 import org.hackystat.sensor.ant.javancss.jaxb.Functions; 012 013 /** 014 * A data structure that takes as input the list of Java files that were processed by JavaNCSS 015 * and the Functions instance that JavaNCSS produced as a result of processing. Constructs 016 * a data structure that maps the list of Java files to a string containing a list of 017 * comma-separated integers, each one representing a CCN value for one of the methods in that class. 018 * If no CCN data was found for that file, null is returned. 019 * 020 * @author Philip Johnson 021 */ 022 public class CcnData { 023 024 /** Maps the fully qualified Java file to a list of ints indicating its methods' ccn's. */ 025 private Map<File, List<Integer>> file2Ccns = new HashMap<File, List<Integer>>(); 026 private Map<File, Integer> file2TotalLines = new HashMap<File, Integer>(); 027 028 /** 029 * Constructs the File2CcnList, which is a mapping from a Java file path to a list of integers 030 * representing the cyclometric complexity values found for all of its interior methods. 031 * @param files The Java files whose CCN numbers are to be found. 032 * @param functions The Functions object contains CCN data. 033 */ 034 public CcnData(List<File> files, Functions functions) { 035 for (Function function : functions.getFunction()) { 036 String methodSignature = function.getName(); 037 File javaFile = findJavaFile(files, methodSignature); 038 // Update our data structure only if we found a Java file corresponding to the method sig. 039 if (javaFile != null) { 040 // First, add the found ccn value to our list of ccn values. 041 if (!file2Ccns.containsKey(javaFile)) { 042 file2Ccns.put(javaFile, new ArrayList<Integer>()); 043 file2TotalLines.put(javaFile, 0); 044 } 045 // Second, update the mapping from file to TotalLines. 046 file2Ccns.get(javaFile).add(function.getCcn().intValue()); 047 int lines = 0; 048 try { 049 lines = Integer.valueOf(function.getNcss()); 050 } 051 catch (Exception e) { 052 System.out.println("Warning: could not make an integer from: " + 053 function.getNcss() + ". Ignoring this value for NCSS"); 054 } 055 int newTotalLines = file2TotalLines.get(javaFile) + lines; 056 file2TotalLines.put(javaFile, newTotalLines); 057 } 058 } 059 } 060 061 /** 062 * Takes a methodSignature, and returns the Java file associated with it, or null if no 063 * corresponding Java file could be found. 064 * 065 * Method signatures look like: 066 * <pre> 067 * org.hackystat.sensor.xmldata.MessageDelegate.MessageDelegate(XmlDataController) 068 * MessageDelegate.MessageDelegate(XmlDataController) 069 * </pre> 070 * @param files The list of all Files. 071 * @param methodSignature The method signature of interest. 072 * @return The Java file, if one matches the method signature. 073 */ 074 private File findJavaFile(List<File> files, String methodSignature) { 075 // Find the '.' that's just before the start of the method name and signature. 076 int index = methodSignature.lastIndexOf('.'); 077 // Now slice off the method name and signature. 078 String fullyQualifiedClassName = methodSignature.substring(0, index); 079 // Now create a path by replacing the remaining '.' with file.separator. 080 String filePath = fullyQualifiedClassName.replace(".", System.getProperty("file.separator")); 081 // Add the .java 082 String javaPath = filePath + ".java"; 083 // Now we hopefully have something like: org/hackystat/sensor/xmldata/MessageDelegate.java 084 // So see if any of our files ends with this string. If so, we've found a match and return it. 085 for (File file : files) { 086 if (file.getAbsolutePath().endsWith(javaPath)) { 087 return file; 088 } 089 } 090 // We didn't find it, so return null. 091 return null; 092 } 093 094 /** 095 * Returns a string containing a comma-separated list of CCN values for the given file, or null 096 * if no CCN data is present. 097 * @param file The file whose CCN data is to be retrieved. 098 * @return The CCN data string, or null. 099 */ 100 public String getCcnData (File file) { 101 List<Integer> ccnValues = file2Ccns.get(file); 102 if (ccnValues == null) { 103 return null; 104 } 105 // Otherwise we have data, so construct the string. 106 StringBuilder ccnData = new StringBuilder(); 107 for (Integer value : ccnValues) { 108 ccnData.append(value).append(","); 109 } 110 // strip off the final ",". 111 return ccnData.substring(0, ccnData.length() - 1); 112 } 113 114 /** 115 * Returns the totallines value for file, or null if not found. 116 * @param file The file whose total lines we're interested in. 117 * @return The number of lines, or null. 118 */ 119 public int getTotalLines(File file) { 120 return file2TotalLines.get(file); 121 } 122 123 /** 124 * Returns a set containing the java file paths in this CcnData instance. 125 * @return The Java file paths with CcnData. 126 */ 127 public Set<File> getFiles () { 128 return file2Ccns.keySet(); 129 } 130 }