SOYC Dashboard git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4221 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java new file mode 100644 index 0000000..6575008 --- /dev/null +++ b/tools/soyc-vis/src/com/google/gwt/soyc/CodeCollection.java
@@ -0,0 +1,58 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.soyc; + +import java.util.TreeSet; + +public class CodeCollection { + + public String codeType = ""; + public TreeSet<String> classes = new TreeSet<String>(); + public TreeSet<String> stories = new TreeSet<String>(); + public float cumPartialSize = 0f; + public int cumSize = 0; + public CodeCollection(String type){ + codeType = type; + } + + + public int getCumSize(){ + cumSize = 0; + for (String className : classes){ + if (! GlobalInformation.classToSize.containsKey(className)){ + System.err.println("*** NO SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + cumSize += GlobalInformation.classToSize.get(className); + } + } + return cumSize; + } + + public float getCumPartialSize(){ + cumPartialSize = 0f; + for (String className : classes){ + if (!GlobalInformation.classToPartialSize.containsKey(className)){ + System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + cumPartialSize += GlobalInformation.classToPartialSize.get(className); + } + } + return cumPartialSize; + } +}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java new file mode 100644 index 0000000..40b377c --- /dev/null +++ b/tools/soyc-vis/src/com/google/gwt/soyc/GlobalInformation.java
@@ -0,0 +1,94 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + + +package com.google.gwt.soyc; + +import java.util.HashMap; +import java.util.TreeMap; +import java.util.HashSet; +import java.util.TreeSet; + +public class GlobalInformation { + + public static HashMap<String, HashSet<String>> storiesToCorrClasses = new HashMap<String, HashSet<String>>(); + public static HashMap<String, String> storiesToLitType = new HashMap<String, String>(); + + public static HashMap<String, Integer> packageToSize = new HashMap<String, Integer>(); + public static HashMap<String, Float> packageToPartialSize = new HashMap<String, Float>(); + + public static HashMap<String, String> classToPackage = new HashMap<String, String>(); + + //TODO(kprobst): not currently used, but will be for dependencies + //public static HashMap<String, HashSet<String>> classToWhatItDependsOn = new HashMap<String, HashSet<String>>(); + + public static HashMap<String, Integer> classToSize = new HashMap<String, Integer>(); + public static HashMap<String, Float> classToPartialSize = new HashMap<String, Float>(); + public static TreeMap<String, TreeSet<String>> packageToClasses = new TreeMap<String, TreeSet<String>>(); + + public static HashSet<String> nonAttributedStories = new HashSet<String>(); + public static int nonAttributedBytes = 0; + public static int numBytesDoubleCounted = 0; + + public static int cumSizeAllCode = 0; + public static float cumPartialSizeFromPackages = 0f; + public static int cumSizeFromPackages = 0; + + public static HashMap<Integer, HashSet<String>> fragmentToStories = new HashMap<Integer, HashSet<String>>(); + public static HashMap<Integer, Float> fragmentToPartialSize = new HashMap<Integer, Float>(); + public static int numFragments = 0; + public static int numSplitPoints = 0; + public static int cumSizeInitialFragment = 0; + + public static void computePackageSizes(){ + cumSizeFromPackages = 0; + packageToSize.clear(); + for (String packageName : packageToClasses.keySet()){ + packageToSize.put(packageName, 0); + for (String className : packageToClasses.get(packageName)){ + if (! classToSize.containsKey(className)){ + System.err.println("*** NO SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + int curSize = classToSize.get(className); + cumSizeFromPackages += curSize; + int newSize = curSize + packageToSize.get(packageName); + packageToSize.put(packageName, newSize); + } + } + } + } + + public static void computePartialPackageSizes(){ + cumPartialSizeFromPackages = 0; + packageToPartialSize.clear(); + for (String packageName : packageToClasses.keySet()){ + packageToPartialSize.put(packageName, 0f); + for (String className : packageToClasses.get(packageName)){ + if (! classToPartialSize.containsKey(className)){ + System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + float curSize = classToPartialSize.get(className); + cumPartialSizeFromPackages += curSize; + float newSize = curSize + packageToPartialSize.get(packageName); + packageToPartialSize.put(packageName, newSize); + } + } + } + } + +}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java new file mode 100644 index 0000000..ce17b5d --- /dev/null +++ b/tools/soyc-vis/src/com/google/gwt/soyc/LiteralsCollection.java
@@ -0,0 +1,53 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.soyc; + +import java.util.HashMap; +import java.util.Map; +import java.util.HashSet; +import java.util.TreeMap; + +public class LiteralsCollection { + public String literalType = ""; + public Map<String, HashSet<String>> literalToLocations = new TreeMap<String, HashSet<String>>(); + public Map<String, HashSet<String> > storyToLocations = new HashMap<String, HashSet<String>>(); + public TreeMap<String, String> stringLiteralToType = new TreeMap<String, String>(); + public Map<String, Integer> stringTypeToSize = new HashMap<String, Integer>(); + public Map<String, Integer> stringTypeToCount = new HashMap<String, Integer>(); + public int cumSize = 0; + public int cumStringSize = 0; + + public LiteralsCollection(String type){ + literalType = type; + } + + /** + * Utility method + */ + public void printAllStrings(){ + int iSum = 0; + System.out.println("--- now printing strings ---"); + for (String st : stringLiteralToType.keySet()){ + int numBytes = st.getBytes().length; + iSum += numBytes; + System.out.println(st + "[" + numBytes + "]"); + } + System.out.println("sum: " + iSum); + System.out.println("--- done printing strings ---"); + } + +}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java new file mode 100644 index 0000000..d538be3 --- /dev/null +++ b/tools/soyc-vis/src/com/google/gwt/soyc/MakeTopLevelHtmlForPerm.java
@@ -0,0 +1,1046 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.soyc; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.TreeMap; + +public class MakeTopLevelHtmlForPerm { + + public static void makeHTMLShell(HashMap<String, CodeCollection> nameToCodeColl, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{ + //this will contain the place holder iframes where the actual information is going to go. + + String fileName = "SoycDashboard-index.html"; + + final PrintWriter outFile = new PrintWriter(fileName); + outFile.println("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<title>Story of Your Compile - Top Level Dashboard for Permutation</title>"); + + outFile.println("<style type=\"text/css\">"); + outFile.println("body {background-color: #728FCE}"); + outFile.println("h2 {background-color: transparent}"); + outFile.println("p {background-color: fuchsia}"); + outFile.println("</style>"); + outFile.println("</head>"); + + + outFile.println("<body>"); + outFile.println("<center>"); + outFile.println("<h3>Story of Your Compile Dashboard</h3>"); + outFile.println("<hr>"); + if (GlobalInformation.cumSizeInitialFragment != 0){ + outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span>, Size of Initial Download: <span style=\"color:maroon\">" + GlobalInformation.cumSizeInitialFragment + "</span></b>"); + } + else{ + outFile.println("<b>Full code size: <span style=\"color:maroon\">" + GlobalInformation.cumSizeAllCode + "</span></b>"); + } + outFile.println("</center>"); + outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">"); + outFile.println("<b>Package breakdown</b>"); + outFile.println(" </div>"); + outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">"); + outFile.println("<b>Code type breakdown</b>"); + outFile.println(" </div>"); + + + outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">"); + outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>"); + outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Package Name</div>"); + outFile.println(" </div>"); + + + outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px;\">"); + outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>"); + outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Code Type</div>"); + outFile.println(" </div>"); + + + + outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">"); + outFile.println("<iframe src=\"packageBreakdown.html\" width=100% height=100% scrolling=auto></iframe>"); + outFile.println(" </div>"); + makePackageHtml("packageBreakdown.html"); + + outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">"); + outFile.println("<iframe src=\"codeTypeBreakdown.html\" width=100% height=100% scrolling=auto></iframe>"); + outFile.println(" </div>"); + makeCodeTypeHtml("codeTypeBreakdown.html", nameToCodeColl); + + outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">"); + outFile.println("<b>Literals breakdown</b>"); + outFile.println(" </div>"); + outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">"); + outFile.println("<b>String literals breakdown</b>"); + outFile.println(" </div>"); + + + outFile.println(" <div style=\"width:50%; float:left; padding-top: 10px;\">"); + outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>"); + outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Literal Type</div>"); + outFile.println(" </div>"); + + + outFile.println(" <div style=\"width:48%; float:right; padding-top: 10px; \">"); + outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>"); + outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">String Literal Type</div>"); + outFile.println(" </div>"); + + + outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:left;\">"); + outFile.println("<iframe src=\"literalsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>"); + outFile.println("</div>"); + makeLiteralsHtml("literalsBreakdown.html", nameToLitColl); + + outFile.println("<div style=\"height:35%; width:48%; margin:0 auto; background-color:white; float:right;\">"); + outFile.println("<iframe src=\"stringLiteralsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>"); + outFile.println(" </div>"); + makeStringLiteralsHtml("stringLiteralsBreakdown.html", nameToLitColl); + + + + if (GlobalInformation.fragmentToStories.size() == 1){ + outFile.println(" <div style=\"width:100%; float:left; padding-top: 10px;\">"); + outFile.println("<b>Fragments breakdown</b>"); + outFile.println(" </div>"); + + outFile.println(" <div style=\"width:100%; float:left; padding-top: 10px;\">"); + outFile.println("<div style=\"width: 110px; float: left; font-size:16px;\">Size</div>"); + outFile.println("<div style=\"width: 200px; float: left; text-align:left; font-size:16px; \">Fragment Name</div>"); + outFile.println(" </div>"); + + outFile.println("<div style=\"height:35%; width:50%; margin:0 auto; background-color:white; float:left;\">"); + outFile.println("<iframe src=\"fragmentsBreakdown.html\" width=100% height=100% scrolling=auto></iframe>"); + outFile.println("</div>"); + makeFragmentsHtml("fragmentsBreakdown.html"); + } + + outFile.println(" </body>"); + outFile.println("</html>"); + outFile.close(); + + } + + + private static void makePackageHtml(String outFileName) throws IOException{ + + + TreeMap<Float, String> sortedPackages = new TreeMap<Float, String>(Collections.reverseOrder()); + float maxSize = 0f; + float sumSize = 0f; + for (String packageName : GlobalInformation.packageToPartialSize.keySet()){ + sortedPackages.put(GlobalInformation.packageToPartialSize.get(packageName), packageName); + sumSize += GlobalInformation.packageToPartialSize.get(packageName); + if (GlobalInformation.packageToPartialSize.get(packageName) > maxSize){ + maxSize = GlobalInformation.packageToPartialSize.get(packageName); + } + } + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">"); + outFile.println("</head>"); + outFile.println("<body>"); + + int yOffset = 0; + for (Float size : sortedPackages.keySet()){ + + String packageName = sortedPackages.get(size); + String drillDownFileName = packageName + "Classes.html"; + + float ratio = (size / maxSize) * 79; + + if (ratio < 3){ + ratio = 3; + } + + float perc = (size / sumSize) * 100; + + outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc); + outFile.println("%</div>\n"); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+packageName+"</a></div>"); + + yOffset = yOffset + 25; + + } + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + + } + + + private static void makeFragmentsHtml(String outFileName) throws IOException{ + + TreeMap<Float, Integer> sortedFragments = new TreeMap<Float, Integer>(Collections.reverseOrder()); + float maxSize = 0f; + float sumSize = 0f; + for (Integer fragmentName : GlobalInformation.fragmentToPartialSize.keySet()){ + sortedFragments.put(GlobalInformation.fragmentToPartialSize.get(fragmentName), fragmentName); + sumSize += GlobalInformation.fragmentToPartialSize.get(fragmentName); + if (GlobalInformation.fragmentToPartialSize.get(fragmentName) > maxSize){ + maxSize = GlobalInformation.fragmentToPartialSize.get(fragmentName); + } + } + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">"); + outFile.println("</head>"); + outFile.println("<body>"); + + int yOffset = 0; + for (Float size : sortedFragments.keySet()){ + + Integer fragmentName = sortedFragments.get(size); + String drillDownFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html"; + + float ratio = (size / maxSize) * 79; + + if (ratio < 3){ + ratio = 3; + } + + float perc = (size / sumSize) * 100; + + outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:80px;\">%.1f", perc); + outFile.println("%</div>\n"); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:120px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">fragment"+ Integer.toString(fragmentName) +"</a></div>"); + + yOffset = yOffset + 25; + + } + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + + } + + + + + private static void makeCodeTypeHtml(String outFileName, HashMap<String, CodeCollection> nameToCodeColl) throws IOException{ + + + float maxSize = 0f; + float sumSize = 0f; + TreeMap<Float, String> sortedCodeTypes = new TreeMap<Float, String>(Collections.reverseOrder()); + + //TODO(kprobst): turn this into a multimap? com.google.common.collect.TreeMultimap + for (String codeType : nameToCodeColl.keySet()){ + float curSize = nameToCodeColl.get(codeType).getCumPartialSize(); + sumSize += curSize; + + if (curSize != 0f){ + sortedCodeTypes.put(curSize, codeType); + if (curSize > maxSize){ + maxSize = curSize; + } + } + } + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">"); + outFile.println("</head>"); + outFile.println("<body>"); + + int yOffset = 0; + for (Float size : sortedCodeTypes.keySet()){ + + String codeType = sortedCodeTypes.get(size); + String drillDownFileName = codeType + "Classes.html"; + + float ratio = (size / maxSize) * 79; + float perc = (size / sumSize) * 100; + + if (ratio < 3){ + ratio = 3; + } + + outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc); + outFile.println("%</div>\n"); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+codeType+"</a></div>"); + + yOffset = yOffset + 25; + + } + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + + + } + + + + private static void makeLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{ + + + float maxSize = 0f; + float sumSize = 0f; + TreeMap<Float, String> sortedLitTypes = new TreeMap<Float, String>(Collections.reverseOrder()); + + for (String literal : nameToLitColl.keySet()){ + float curSize = nameToLitColl.get(literal).cumSize; + sumSize += curSize; + + if (curSize != 0f){ + sortedLitTypes.put(curSize, literal); + + if (curSize > maxSize){ + maxSize = curSize; + } + } + } + + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">"); + outFile.println("</head>"); + outFile.println("<body>"); + + int yOffset = 0; + for (Float size : sortedLitTypes.keySet()){ + + String literal = sortedLitTypes.get(size); + String drillDownFileName = literal + "Lits.html"; + + float ratio = (size / maxSize) * 79; + float perc = (size / sumSize) * 100; + + if (ratio < 3){ + ratio = 3; + } + + outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc); + outFile.println("%</div>\n"); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+literal+"</a></div>"); + + yOffset = yOffset + 25; + + } + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + + } + + + private static void makeStringLiteralsHtml(String outFileName, TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{ + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"roundedCorners.css\" media=\"screen\">"); + outFile.println("</head>"); + outFile.println("<body>"); + + + if (nameToLitColl.get("string").stringTypeToSize.size() > 0){ + + float maxSize = 0f; + float sumSize = 0f; + TreeMap<Float, String> sortedStLitTypes = new TreeMap<Float, String>(Collections.reverseOrder()); + + for (String stringLiteral : nameToLitColl.get("string").stringTypeToSize.keySet()){ + float curSize = nameToLitColl.get("string").stringTypeToSize.get(stringLiteral); + sumSize += curSize; + + if (curSize != 0f){ + sortedStLitTypes.put(curSize, stringLiteral); + + if (curSize > maxSize){ + maxSize = curSize; + } + } + } + + + int yOffset = 0; + for (Float size : sortedStLitTypes.keySet()){ + + String stringLiteral = sortedStLitTypes.get(size); + String drillDownFileName = stringLiteral + "Strings.html"; + + float ratio = (size / maxSize) * 79; + float perc = (size / sumSize) * 100; + + if (ratio < 3){ + ratio = 3; + } + + outFile.println("<div id=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 110px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">%.1f", perc); + outFile.println("%</div>\n"); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:110px;\"><a href=\"" + drillDownFileName + "\" target=\"_top\">"+stringLiteral+"</a></div>"); + + yOffset = yOffset + 25; + + } + + } + + else{ + outFile.println("No string literals found for this application."); + + } + + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + + + + public static void makePackageClassesHtmls() throws IOException{ + + for (String packageName : GlobalInformation.packageToClasses.keySet()){ + + String outFileName = packageName + "Classes.html"; + TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder()); + float maxSize = 0f; + + //TODO(kprobst): not currently used, but will be for dependencies + //int maxDepCount = 0; + + for (String className : GlobalInformation.packageToClasses.get(packageName)){ + + float curSize = 0f; + if (! GlobalInformation.classToPartialSize.containsKey(className)){ + System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + curSize = GlobalInformation.classToPartialSize.get(className); + } + + //TODO(kprobst): not currently used, but will be for dependencies + /*int depCount = 0; + if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){ + depCount = GlobalInformation.classToWhatItDependsOn.get(className).size(); + }*/ + + if (curSize != 0f){ + + sortedClasses.put(curSize, className); + if (curSize > maxSize){ + maxSize = curSize; + } + //TODO(kprobst): not currently used, but will be for dependencies + /*if (depCount > maxDepCount){ + maxDepCount = depCount; + }*/ + } + } + + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">"); + outFile.println("<title>Classes in package \"" + packageName + "\"</title>"); + outFile.println("</head>"); + outFile.println("<body>"); + + + outFile.println("<center>"); + outFile.println("<h2>Classes in package \"" + packageName + "\"</h2>"); + outFile.println("</center>"); + outFile.println("<hr>"); + + outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\""); + + + int yOffset = 0; + for (Float size : sortedClasses.keySet()){ + + String className = sortedClasses.get(size); + + //TODO(kprobst): switch out the commented/uncommented lines below when showing dependencies + //float ratio = (size / maxSize) * 45; + float ratio = (size / maxSize) * 85; + + if (ratio < 3){ + ratio = 3; + } + + //TODO(kprobst): not currently used, but will be for dependencies +/* // get the dependency count + int depCount = 0; + if (GlobalInformation.classToWhatItDependsOn.containsKey(className)){ + depCount = GlobalInformation.classToWhatItDependsOn.get(className).size(); + } + float depRatio = (depCount / maxDepCount) * 25; + if (depRatio < 3){ + depRatio = 3; + }*/ + + outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + + //TODO(kprobst): not currently used, but will be for dependencies + // place holder for mock-up of dependency display +/* outFile.println("<div class=\"box-right\" style=\"width:" + depRatio + "%; top: " + yOffset + "px; left: 50%\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + + outFile.println("<div class=\"box-right\" style=\"width:10%; top: " + yOffset + "px; left: 75%\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); */ + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>"); + + yOffset = yOffset + 25; + + } + + outFile.println("</div>"); + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + } + + + public static void makeCodeTypeClassesHtmls(HashMap<String, CodeCollection> nameToCodeColl) throws IOException{ + + for (String codeType : nameToCodeColl.keySet()){ + + //construct file name + String outFileName = codeType + "Classes.html"; + + + float maxSize = 0f; + TreeMap<Float, String> sortedClasses = new TreeMap<Float, String>(Collections.reverseOrder()); + for (String className : nameToCodeColl.get(codeType).classes){ + if (GlobalInformation.classToPartialSize.containsKey(className)){ + + float curSize = 0f; + if (! GlobalInformation.classToPartialSize.containsKey(className)){ + System.err.println("*** NO PARTIAL SIZE FOUND FOR CLASS " + className + " *****"); + } + else{ + curSize = GlobalInformation.classToPartialSize.get(className); + } + + if (curSize != 0f){ + sortedClasses.put(curSize, className); + if (curSize > maxSize){ + maxSize = curSize; + } + } + } + } + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + + outFile.println("<style type=\"text/css\">"); + outFile.println("body {background-color: #728FCE}"); + outFile.println("h2 {background-color: transparent}"); + outFile.println("p {background-color: fuchsia}"); + outFile.println("</style>"); + + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<link rel=\"stylesheet\" href=\"classLevel.css\" media=\"screen\">"); + outFile.println("<title>Classes of type \"" + codeType + "\"</title>"); + outFile.println("</head>"); + outFile.println("<body>"); + + + + outFile.println("<center>"); + outFile.println("<h2>Classes of type \"" + codeType + "\"</h2>"); + outFile.println("</center>"); + outFile.println("<hr>"); + + outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 90px; left:70px; position:absolute; background-color:white\""); + + + int yOffset = 0; + for (Float size : sortedClasses.keySet()){ + + String className = sortedClasses.get(size); + + float ratio = (size / maxSize) * 85; + + if (ratio < 3){ + ratio = 3; + } + + outFile.println("<div class=\"box\" style=\"width:" + ratio + "%; top: " + yOffset + "px; left: 60px;\">"); + outFile.println("<div id=\"lb\">"); + outFile.println("<div id=\"rb\">"); + outFile.println("<div id=\"bb\"><div id=\"blc\"><div id=\"brc\">"); + outFile.println("<div id=\"tb\"><div id=\"tlc\"><div id=\"trc\">"); + outFile.println("<div id=\"content\">"); + outFile.println("</div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div></div></div></div>"); + outFile.println("</div>"); + + int yOffsetText = yOffset+8; + outFile.printf("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:5px;\">%.1f</div>\n", size); + outFile.println("<div class=\"barlabel\" style=\"top:" + yOffsetText + "px; left:70px;\">"+className+"</div>"); + + yOffset = yOffset + 25; + + } + + outFile.println("</div>"); + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + } + + + + public static void makeLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{ + + + for (String literalType : nameToLitColl.keySet()){ + + String outFileName = literalType + "Lits.html"; + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<title>Literals of type \"" + literalType + "\"</title>"); + outFile.println("</head>"); + + outFile.println("<style type=\"text/css\">"); + outFile.println("body {background-color: #728FCE}"); + outFile.println("h2 {background-color: transparent}"); + outFile.println("p {background-color: fuchsia}"); + outFile.println(".tablediv {"); + outFile.println("display: table;"); + outFile.println("width:100%;"); + outFile.println("background-color:#eee;"); + outFile.println("border:1px solid #666666;"); + outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/"); + outFile.println("border-collapse:separate;"); + outFile.println("}"); + outFile.println(".celldiv {"); + outFile.println("float:left;/*fix for buggy browsers*/"); + outFile.println("display: table-cell;"); + outFile.println("width:50%;"); + outFile.println("font-size: 14px;"); + outFile.println("background-color:white;"); + outFile.println("}"); + outFile.println(".rowdiv {"); + outFile.println("display: table-row;"); + //outFile.println("width:90%;"); + outFile.println("}"); + outFile.println("</style>"); + + outFile.println("<body>"); + outFile.println("<center>"); + outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>"); + outFile.println("</center>"); + outFile.println("<hr>"); + + outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\""); + outFile.println("<div class=\"tablediv\">"); + for (String literal : nameToLitColl.get(literalType).literalToLocations.keySet()){ + + if (literal.trim().compareTo("") == 0){ + literal = "[whitespace only string]"; + } + + + String newLiteral = ""; + if(literal.length() > 100){ + int i; + for (i = 100; i < literal.length(); i=i+100){ + String part1 = literal.substring(i-100, i); + newLiteral = newLiteral + part1 + " "; + } + if (i-100 > 0){ + newLiteral = newLiteral + literal.substring(i-100); + } + } + else{ + newLiteral = literal; + } + + String escliteral = escapeXml(newLiteral); + outFile.println("<div class=\"rowdiv\">"); + outFile.println("<div class=\"celldiv\">" + escliteral + "</div>"); + + for (String location : nameToLitColl.get(literalType).literalToLocations.get(literal)){ + + String newLocation = ""; + if(location.length() > 100){ + int i; + for (i = 100; i < location.length(); i=i+100){ + String part1 = location.substring(i-100, i); + newLocation = newLocation + part1 + " "; + } + if (i-100 > 0){ + newLocation = newLocation + location.substring(i-100); + } + } + else{ + newLocation = location; + } + + outFile.println("<div class=\"celldiv\">" + newLocation + "</div>"); + } + outFile.println("</div>"); + } + outFile.println("</div>"); + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + } + + /** + * Makes html file for fragment classes. + * TODO(kprobst): update this once we have SOYC updated to supply enough information + * @throws IOException + */ + public static void makeFragmentClassesHtmls() throws IOException{ + + + for (Integer fragmentName : GlobalInformation.fragmentToStories.keySet()){ + HashSet<String> alreadyPrintedClasses = new HashSet<String>(); + + String outFileName = "fragment" + Integer.toString(fragmentName) + "Classes.html"; + + final PrintWriter outFile = new PrintWriter(outFileName); + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<title>Classes correlated with fragment " + Integer.toString(fragmentName) + " </title>"); + outFile.println("</head>"); + + outFile.println("<style type=\"text/css\">"); + outFile.println("body {background-color: #728FCE}"); + outFile.println("h2 {background-color: transparent}"); + outFile.println("p {background-color: fuchsia}"); + outFile.println(".tablediv {"); + outFile.println("display: table;"); + outFile.println("width:100%;"); + outFile.println("background-color:#eee;"); + outFile.println("border:1px solid #666666;"); + outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/"); + outFile.println("border-collapse:separate;"); + outFile.println("}"); + outFile.println(".celldiv {"); + outFile.println("float:left;/*fix for buggy browsers*/"); + outFile.println("display: table-cell;"); + outFile.println("width:49.5%;"); + outFile.println("font-size: 14px;"); + outFile.println("background-color:white;"); + outFile.println("}"); + outFile.println(".rowdiv {"); + outFile.println("display: table-row;"); + outFile.println("width:100%;"); + outFile.println("}"); + outFile.println("</style>"); + + outFile.println("<body>"); + outFile.println("<center>"); + outFile.println("<h2>Classes correlated with fragment " + Integer.toString(fragmentName) + "</h2>"); + outFile.println("</center>"); + outFile.println("<hr>"); + + outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\""); + outFile.println("<div class=\"tablediv\">"); + + for (String storyName : GlobalInformation.fragmentToStories.get(fragmentName)){ + if (GlobalInformation.storiesToCorrClasses.containsKey(storyName)){ + for (String className : GlobalInformation.storiesToCorrClasses.get(storyName)){ + + if (! alreadyPrintedClasses.contains(className)){ + //outFile.println("<div class=\"rowdiv\">"); + outFile.println("<div class=\"rowdiv\">" + className + "</div>"); + //outFile.println("</div>"); + alreadyPrintedClasses.add(className); + } + } + } + } + outFile.println("</div>"); + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + } + + + public static void makeStringLiteralsClassesHtmls(TreeMap<String, LiteralsCollection> nameToLitColl) throws IOException{ + + + for (String literalType : nameToLitColl.get("string").stringTypeToSize.keySet()){ + + String outFileName = literalType + "Strings.html"; + + final PrintWriter outFile = new PrintWriter(outFileName); + + + outFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""); + outFile.println("\"http://www.w3.org/TR/html4/strict.dtd\">"); + outFile.println("<html>"); + outFile.println("<head>"); + outFile.println("<meta http-equiv=\"content-type\" content=\"text/html;charset=ISO-8859-1\">"); + outFile.println("<title>Literals of type \"" + literalType + "\"</title>"); + outFile.println("</head>"); + + outFile.println("<style type=\"text/css\">"); + outFile.println("body {background-color: #728FCE}"); + outFile.println("h2 {background-color: transparent}"); + outFile.println("p {background-color: fuchsia}"); + outFile.println(".tablediv {"); + outFile.println("display: table;"); + outFile.println("width:100%;"); + outFile.println("background-color:#eee;"); + outFile.println("border:1px solid #666666;"); + outFile.println("border-spacing:5px;/*cellspacing:poor IE support for this*/"); + outFile.println("border-collapse:separate;"); + outFile.println("}"); + outFile.println(".celldiv {"); + outFile.println("float:left;/*fix for buggy browsers*/"); + outFile.println("display: table-cell;"); + outFile.println("width:49.5%;"); + outFile.println("font-size: 14px;"); + outFile.println("background-color:white;"); + outFile.println("}"); + outFile.println(".rowdiv {"); + outFile.println("display: table-row;"); + outFile.println("width:100%;"); + outFile.println("}"); + outFile.println("</style>"); + + outFile.println("<body>"); + outFile.println("<center>"); + outFile.println("<h2>Literals of type \"" + literalType + "\"</h2>"); + outFile.println("</center>"); + outFile.println("<hr>"); + + outFile.println("<div style=\"width:90%; height:80%; overflow-y:auto; overflow-x:auto; top: 30px; left:60px; position:relative; background-color:white\""); + outFile.println("<div class=\"tablediv\">"); + + + for (String literal : nameToLitColl.get("string").stringLiteralToType.keySet()){ + + if (nameToLitColl.get("string").stringLiteralToType.get(literal).compareTo(literalType) == 0){ + + + if (literal.trim().compareTo("") == 0){ + literal = "[whitespace only string]"; + } + + String newLiteral = ""; + if(literal.length() > 100){ + int i; + for (i = 100; i < literal.length(); i=i+100){ + String part1 = literal.substring(i-100, i); + newLiteral = newLiteral + part1 + " "; + } + if (i-100 > 0){ + newLiteral = newLiteral + literal.substring(i-100); + } + } + else{ + newLiteral = literal; + } + + String escliteral = escapeXml(newLiteral); + outFile.println("<div class=\"rowdiv\">"); + outFile.println("<div class=\"celldiv\">" + escliteral + "</div>"); + + for (String location : nameToLitColl.get("string").literalToLocations.get(literal)){ + + String newLocation = ""; + if(location.length() > 100){ + int i; + for (i = 100; i < location.length(); i=i+100){ + String part1 = location.substring(i-100, i); + newLocation = newLocation + part1 + " "; + } + if (i-100 > 0){ + newLocation = newLocation + location.substring(i-100); + } + } + else{ + newLocation = location; + } + + outFile.println("<div class=\"celldiv\">" + newLocation + "</div>"); + } + outFile.println("</div>"); + } + } + outFile.println("</div>"); + outFile.println("</body>"); + outFile.println("</html>"); + outFile.close(); + } + + + + } + + + + public static String escapeXml(String unescaped) { + String escaped = unescaped.replaceAll("\\&", "&"); + escaped = escaped.replaceAll("\\<", "<"); + escaped = escaped.replaceAll("\\>", ">"); + escaped = escaped.replaceAll("\\\"", """); + escaped = escaped.replaceAll("\\'", "'"); + return escaped; + } + +}
diff --git a/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java new file mode 100644 index 0000000..3333352 --- /dev/null +++ b/tools/soyc-vis/src/com/google/gwt/soyc/SoycDashboard.java
@@ -0,0 +1,775 @@ +/* + * Copyright 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.gwt.soyc; + +import org.xml.sax.*; +import org.xml.sax.helpers.*; +import org.xml.sax.SAXException; + +import java.io.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.TreeSet; +import java.util.TreeMap; +import javax.xml.parsers.*; + +public class SoycDashboard { + + /** + * @param args Input: XML file containing soyc compile output + * @throws IOException + * @throws SAXException + */ + public static void main(String[] args) { + + if (args.length != 1){ + System.err.println("Usage: java com/google/gwt/soyc/SoycDashboard soyc-report0.xml"); + System.exit(1); + } + + String inFileName = args[0]; + + // to store literals data + final TreeMap<String, LiteralsCollection> nameToLitColl = new TreeMap<String, LiteralsCollection>(); + nameToLitColl.put("long",new LiteralsCollection("long")); + nameToLitColl.put("null",new LiteralsCollection("null")); + nameToLitColl.put("class",new LiteralsCollection("class")); + nameToLitColl.put("int",new LiteralsCollection("int")); + nameToLitColl.put("string",new LiteralsCollection("string")); + nameToLitColl.put("number",new LiteralsCollection("number")); + nameToLitColl.put("boolean",new LiteralsCollection("boolean")); + nameToLitColl.put("double",new LiteralsCollection("double")); + nameToLitColl.put("char",new LiteralsCollection("char")); + nameToLitColl.put("undefined",new LiteralsCollection("undefined")); + nameToLitColl.put("float",new LiteralsCollection("float")); + + // to store code data + final HashMap<String, CodeCollection> nameToCodeColl = new HashMap<String, CodeCollection>(); + nameToCodeColl.put("allOther", new CodeCollection("allOther")); + nameToCodeColl.put("widget", new CodeCollection("widget")); + nameToCodeColl.put("rpcUser", new CodeCollection("rpcUser")); + nameToCodeColl.put("rpcGen", new CodeCollection("rpcGen")); + nameToCodeColl.put("rpcGwt", new CodeCollection("rpcGwt")); + nameToCodeColl.put("gwtLang", new CodeCollection("long")); + nameToCodeColl.put("jre", new CodeCollection("jre")); + + // get the number of split points (so we know what code to ignore) + DefaultHandler fragmentCountHandler = scanXMLDocument(); + + // start parsing + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + try { + SAXParser saxParser = factory.newSAXParser(); + InputStream in = new BufferedInputStream(new FileInputStream(inFileName)); + saxParser.parse(in,fragmentCountHandler); + + + } catch (ParserConfigurationException e) { + throw new RuntimeException("Could not parse document. ", e); + } catch (SAXException e) { + throw new RuntimeException("Could not create SAX parser. ", e); + } catch (FileNotFoundException e) { + throw new RuntimeException("Could not open file. ", e); + } catch (IOException e) { + throw new RuntimeException("Could not open file. ", e); + } + GlobalInformation.numSplitPoints = (int)((float)(GlobalInformation.numFragments - 1) / 3f); + + // make the parser handler + DefaultHandler handler = parseXMLDocument(nameToLitColl, nameToCodeColl); + + + // start parsing + SAXParserFactory factoryMain = SAXParserFactory.newInstance(); + factoryMain.setNamespaceAware(true); + try { + SAXParser saxParser = factoryMain.newSAXParser(); + InputStream in = new BufferedInputStream(new FileInputStream(inFileName)); + saxParser.parse(in,handler); + + + } catch (ParserConfigurationException e) { + throw new RuntimeException("Could not parse document. ", e); + } catch (SAXException e) { + throw new RuntimeException("Could not create SAX parser. ", e); + } catch (FileNotFoundException e) { + throw new RuntimeException("Could not open file. ", e); + } catch (IOException e) { + throw new RuntimeException("Could not open file. ", e); + } + + // add to "All Other Code" if none of the special categories apply + updateAllOtherCodeType(nameToCodeColl); + + // now we need to aggregate numbers + GlobalInformation.computePackageSizes(); + GlobalInformation.computePartialPackageSizes(); + + // clean up the RPC categories + foldInRPCHeuristic(nameToCodeColl); + + // generate all the html files + makeHTMLFiles(nameToLitColl, nameToCodeColl); + + System.out.println("Finished creating reports. To see the dashboard, open SoycDashboard-index.html in your browser."); + } + + + private static DefaultHandler parseXMLDocument( + final TreeMap<String, LiteralsCollection> nameToLitColl, + final HashMap<String, CodeCollection> nameToCodeColl) { + + DefaultHandler handler = new DefaultHandler() { + + String curStoryId; + String curStoryLiteralType; + String curLineNumber; + String curLocation; + String curStoryRef; + HashSet<String> curRelevantLitTypes = new HashSet<String>(); + HashSet<String> curRelevantCodeTypes = new HashSet<String>(); + String curClassId; + String curPackage; + Integer curFragment; + boolean specialCodeType = false; + StringBuilder valueBuilder = new StringBuilder(); + int ct = 0; + + /** + * This method deals with the beginning of the XML element. + * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis. + * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + @Override + public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) { + + if ((ct % 10000) == 0){ + System.out.println("."); + } + ct++; + + valueBuilder.delete(0,valueBuilder.length()); + + if ((strippedName.compareTo("package") == 0)&&(attributes.getValue("id") != null)){ + curPackage = attributes.getValue("id"); + + if (curPackage.compareTo("") == 0){ + curPackage = "emptyPackageName"; + } + + if (! GlobalInformation.packageToClasses.containsKey(curPackage)){ + TreeSet<String> insertSet = new TreeSet<String>(); + GlobalInformation.packageToClasses.put(curPackage, insertSet); + } + } + + else if (strippedName.compareTo("class") == 0){ + + parseClass(nameToCodeColl, attributes); + } + + //TODO(kprobst): not currently used, but will be for dependencies +/* else if (strippedName.compareTo("on") == 0){ + parseDependsOn(nameToCodeColl, attributes); + }*/ + + else if (strippedName.compareTo("of") == 0){ + parseOverrides(nameToCodeColl, attributes); + } + + else if (strippedName.compareTo("by") == 0){ + parseCorrelations(nameToCodeColl, attributes); + } + + else if (strippedName.compareTo("story") == 0){ + parseStory(attributes); + } + + else if (strippedName.compareTo("origin") == 0){ + parseOrigins(nameToLitColl, attributes); + } + + else if (strippedName.compareTo("js") == 0){ + if (attributes.getValue("fragment") != null){ + // ignore all code that is not in the first load order + + curFragment = Integer.parseInt(attributes.getValue("fragment")); + if(!((curFragment == 0)||(curFragment == (GlobalInformation.numSplitPoints+1))||(curFragment == (GlobalInformation.numSplitPoints+2))|| + ((curFragment >= 2) && (curFragment <= GlobalInformation.numSplitPoints)))){ + curFragment = -1; + } + } + else{ + curFragment = -2; + } + } + + else if (strippedName.compareTo("storyref") == 0){ + parseJs(nameToLitColl, nameToCodeColl, attributes, curFragment); + } + } + + + /** + * This method collects a block of the value of the current XML node that the SAX parser parses. + * It simply adds to the the previous blocks, so that we can collect the entire value block. + */ + @Override + public void characters (char ch[], int start, int length){ + valueBuilder.append(ch, start, length); + } + + + /** + * This method marks the end of an XML element that the SAX parser parses. + * It has access to the full value of the node and uses it add information to the relevant literal or code collections. + * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void endElement (String nsUri, String strippedName, String qName){ + String value = valueBuilder.toString(); + + int numBytes = value.getBytes().length; + + if ((curStoryRef != null)&&(curFragment != -1)){ + + if ((!GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&(! GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef))){ + GlobalInformation.nonAttributedStories.add(curStoryRef); + GlobalInformation.nonAttributedBytes += numBytes; + } + + GlobalInformation.cumSizeAllCode += numBytes; + + if (curFragment == 0){ + GlobalInformation.cumSizeInitialFragment += numBytes; + } + + // go through all the classes for this story + if (GlobalInformation.storiesToCorrClasses.containsKey(curStoryRef)){ + + + if ((GlobalInformation.storiesToLitType.containsKey(curStoryRef))&&(GlobalInformation.storiesToCorrClasses.get(curStoryRef).size() > 0)){ + GlobalInformation.numBytesDoubleCounted += numBytes; + } + + float partialSize = (float)numBytes / (float)GlobalInformation.storiesToCorrClasses.get(curStoryRef).size(); + + //add this size to the current fragment + if (!GlobalInformation.fragmentToPartialSize.containsKey(curFragment)){ + GlobalInformation.fragmentToPartialSize.put(curFragment, partialSize); + } + else{ + float newSize = GlobalInformation.fragmentToPartialSize.get(curFragment) + partialSize; + GlobalInformation.fragmentToPartialSize.put(curFragment, newSize); + } + + for (String className : GlobalInformation.storiesToCorrClasses.get(curStoryRef)){ + // get the corresponding package + if (GlobalInformation.classToPackage.containsKey(className)){ + String packageName = GlobalInformation.classToPackage.get(className); + + if (!GlobalInformation.packageToClasses.containsKey(packageName)){ + TreeSet<String> insertSet = new TreeSet<String>(); + insertSet.add(className); + GlobalInformation.packageToClasses.put(packageName, insertSet); + } + else{ + GlobalInformation.packageToClasses.get(packageName).add(className); + } + + if (GlobalInformation.classToSize.containsKey(className)){ + int newSize = GlobalInformation.classToSize.get(className) + numBytes; + GlobalInformation.classToSize.put(className, newSize); + } + else{ + GlobalInformation.classToSize.put(className, numBytes); + } + + if (GlobalInformation.classToPartialSize.containsKey(className)){ + float newSize = GlobalInformation.classToPartialSize.get(className) + partialSize; + GlobalInformation.classToPartialSize.put(className, newSize); + } + else{ + GlobalInformation.classToPartialSize.put(className, partialSize); + } + } + } + } + + +/* else{ + System.err.println("----- NO CORR CLASSES FOUND FOR STORY " + curStoryRef + " ---------"); + }*/ + + updateLitTypes(nameToLitColl, value, numBytes); + } + } + + + /* + * This method assigns strings to the appropriate category + */ + private void updateLitTypes( + final TreeMap<String, LiteralsCollection> nameToLitColl, + String value, int numBytes) { + + int iNumCounted = 0; + + for (String relLitType : curRelevantLitTypes){ + + iNumCounted++; + + //then give string literals special treatment + if (relLitType.compareTo("string") == 0){ + + + + // note that this will double-count (i.e., it will count a string twice if it's in the output twice), as it should. + nameToLitColl.get("string").cumStringSize += numBytes; + nameToLitColl.get(relLitType).cumSize += numBytes; + + //get the origins + HashSet<String> originSet = nameToLitColl.get("string").storyToLocations.get(curStoryRef); + + // find the most appropriate string literal category + String mostAppropriateCategory = ""; + String mostAppropriateLocation = ""; + String backupLocation = ""; + for (String origin : originSet){ + + if ((origin.contains("ClassLiteralHolder")) && (mostAppropriateCategory.compareTo("") == 0)){ + mostAppropriateCategory = "compiler"; + mostAppropriateLocation = origin; + } + else if ((origin.startsWith("transient source for"))&&(origin.contains("_TypeSerializer")) && (mostAppropriateCategory.compareTo("") == 0)){ + mostAppropriateCategory = "transient"; + mostAppropriateLocation = origin; + } + else if ((origin.contains("InlineResourceBundleGenerator")) && (mostAppropriateCategory.compareTo("") == 0)){ + mostAppropriateCategory = "inlinedTextRes"; + mostAppropriateLocation = origin; + } + if (origin.compareTo("com.google.gwt.dev.js.ast.JsProgram: Line 0") != 0){ + backupLocation = origin; + } + } + + if (backupLocation.compareTo("") == 0){ + backupLocation = "com.google.gwt.dev.js.ast.JsProgram: Line 0"; + } + if ((((value.startsWith("'")) && (value.endsWith("'"))) || + ((value.startsWith("\""))&&(value.endsWith("\"")))) && + (mostAppropriateCategory.compareTo("") == 0)){ + mostAppropriateCategory = "user"; + mostAppropriateLocation = backupLocation; + } + else if (mostAppropriateCategory.compareTo("") == 0){ + mostAppropriateCategory = "otherStrings"; + mostAppropriateLocation = backupLocation; + } + + if (!nameToLitColl.get("string").stringLiteralToType.containsKey(value)){ + nameToLitColl.get("string").stringLiteralToType.put(value, mostAppropriateCategory); + if (!nameToLitColl.get("string").stringTypeToCount.containsKey(mostAppropriateCategory)){ + nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, 1); + } + else{ + int iNewCount = nameToLitColl.get("string").stringTypeToCount.get(mostAppropriateCategory) + 1; + nameToLitColl.get("string").stringTypeToCount.put(mostAppropriateCategory, iNewCount); + } + + + int iNewSize = numBytes; + if (nameToLitColl.get("string").stringTypeToSize.containsKey(mostAppropriateCategory)){ + iNewSize += nameToLitColl.get("string").stringTypeToSize.get(mostAppropriateCategory); + } + nameToLitColl.get("string").stringTypeToSize.put(mostAppropriateCategory, iNewSize); + + + if (nameToLitColl.get("string").storyToLocations.containsKey(curStoryRef)){ + HashSet<String> insertSet = new HashSet<String>(); + insertSet.add(mostAppropriateLocation); + nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet); + + } + } + } + + + + else{ + + // note that this will double-count (i.e., it will count a literal twice if it's in the output twice), as it should. + nameToLitColl.get(relLitType).cumSize += numBytes; + + if (nameToLitColl.get(relLitType).storyToLocations.containsKey(curStoryRef)){ + if (nameToLitColl.get(relLitType).literalToLocations.containsKey(value)){ + nameToLitColl.get(relLitType).literalToLocations.get(value).addAll(nameToLitColl.get(relLitType). + storyToLocations.get(curStoryRef)); + } + else{ + HashSet<String> insertSet = nameToLitColl.get(relLitType).storyToLocations.get(curStoryRef); + nameToLitColl.get(relLitType).literalToLocations.put(value,insertSet); + } + + } + } + } + + //System.out.println("value: |" + value + "| in story |" + curStoryRef + "| was counted " + iNumCounted + " times."); + + } + + /* + * parses the "JS" portion of the XML file + */ + private void parseJs( + final TreeMap<String, LiteralsCollection> nameToLitColl, + final HashMap<String, CodeCollection> nameToCodeColl, + Attributes attributes, Integer curFragment) { + curRelevantLitTypes.clear(); + curRelevantCodeTypes.clear(); + + if (attributes.getValue("idref") != null){ + + curStoryRef = attributes.getValue("idref"); + + if (curFragment != -1){ + //add this to the stories for this fragment + if (!GlobalInformation.fragmentToStories.containsKey(curFragment)){ + HashSet<String> insertSet = new HashSet<String>(); + insertSet.add(curStoryRef); + GlobalInformation.fragmentToStories.put(curFragment, insertSet); + } + else{ + GlobalInformation.fragmentToStories.get(curFragment).add(curStoryRef); + } + } + + for (String litType : nameToLitColl.keySet()){ + if (nameToLitColl.get(litType).storyToLocations.containsKey(curStoryRef)){ + curRelevantLitTypes.add(litType); + } + } + + specialCodeType = false; + for (String codeType : nameToCodeColl.keySet()){ + if (nameToCodeColl.get(codeType).stories.contains(curStoryRef)){ + curRelevantCodeTypes.add(codeType); + specialCodeType = true; + } + } + if (specialCodeType == false){ + + nameToCodeColl.get("allOther").stories.add(curStoryRef); + curRelevantCodeTypes.add("allOther"); + } + } + } + + /* + * parses the "origins" portion of the XML file + */ + private void parseOrigins( + final TreeMap<String, LiteralsCollection> nameToLitColl, + Attributes attributes) { + if ((curStoryLiteralType.compareTo("") != 0)&& + (attributes.getValue("lineNumber") != null)&& + (attributes.getValue("location") != null)){ + curLineNumber = attributes.getValue("lineNumber"); + curLocation = attributes.getValue("location"); + String curOrigin = curLocation + ": Line " + curLineNumber; + + if (!nameToLitColl.get(curStoryLiteralType).storyToLocations.containsKey(curStoryId)){ + HashSet<String> insertSet = new HashSet<String>(); + insertSet.add(curOrigin); + nameToLitColl.get(curStoryLiteralType).storyToLocations.put(curStoryId, insertSet); + } + else{ + nameToLitColl.get(curStoryLiteralType).storyToLocations.get(curStoryId).add(curOrigin); + } + } + } + + /* + * parses the "story" portion of the XML file + */ + private void parseStory(Attributes attributes) { + if (attributes.getValue("id") != null){ + curStoryId = attributes.getValue("id"); + if (attributes.getValue("literal") != null){ + curStoryLiteralType = attributes.getValue("literal"); + GlobalInformation.storiesToLitType.put(curStoryId, curStoryLiteralType); + } + else{ + curStoryLiteralType = ""; + } + } + } + + /* + * parses the "correlations" portion of the XML file + */ + private void parseCorrelations( + final HashMap<String, CodeCollection> nameToCodeColl, + Attributes attributes) { + + if (attributes.getValue("idref") != null){ + String corrClass = attributes.getValue("idref"); + + + if (corrClass.contains(":")){ + corrClass = corrClass.replaceAll(":.*", ""); + } + + if (GlobalInformation.classToPackage.containsKey(corrClass)){ //if we know about this class + + if (! GlobalInformation.storiesToCorrClasses.containsKey(curStoryId)){ + HashSet<String> insertSet = new HashSet<String>(); + insertSet.add(corrClass); + GlobalInformation.storiesToCorrClasses.put(curStoryId, insertSet); + } + else{ + GlobalInformation.storiesToCorrClasses.get(curStoryId).add(corrClass); + } + + for (String codeType : nameToCodeColl.keySet()){ + if (nameToCodeColl.get(codeType).classes.contains(corrClass)){ + nameToCodeColl.get(codeType).stories.add(curStoryId); + } + } + } + } + } + + /* + * parses the "overrides" portion of the XML file + */ + private void parseOverrides( + final HashMap<String, CodeCollection> nameToCodeColl, + Attributes attributes) { + if (attributes.getValue("idref") != null){ + String overriddenClass = attributes.getValue("idref"); + + + if (overriddenClass.contains(":")){ + overriddenClass = overriddenClass.replaceAll(":.*", ""); + } + if (overriddenClass.contains("$")){ + overriddenClass = overriddenClass.replaceAll("\\$.*", ""); + } + + if (overriddenClass.compareTo("com.google.gwt.user.client.ui.UIObject") == 0){ + nameToCodeColl.get("widget").classes.add(curClassId); + } + else if (overriddenClass.contains("java.io.Serializable") || + overriddenClass.contains("IsSerializable")){ + nameToCodeColl.get("rpcUser").classes.add(curClassId); + } + else if (overriddenClass.contains("com.google.gwt.user.client.rpc.core.java")){ + nameToCodeColl.get("rpcGwt").classes.add(curClassId); + } + } + } + + /* + * parses the "class" portion of the XML file + */ + private void parseClass( + final HashMap<String, CodeCollection> nameToCodeColl, + Attributes attributes) { + if (attributes.getValue("id") != null){ + curClassId = attributes.getValue("id"); + + GlobalInformation.classToPackage.put(curClassId, curPackage); + + if (curPackage.startsWith("java")){ + nameToCodeColl.get("jre").classes.add(curClassId); + } + else if (curPackage.startsWith("com.google.gwt.lang")){ + nameToCodeColl.get("gwtLang").classes.add(curClassId); + } + if (curClassId.contains("_CustomFieldSerializer")){ + nameToCodeColl.get("rpcUser").classes.add(curClassId); + } + else if (curClassId.endsWith("_FieldSerializer") || + curClassId.endsWith("_Proxy") || + curClassId.endsWith("_TypeSerializer")){ + nameToCodeColl.get("rpcGen").classes.add(curClassId); + } + } + } + + /* + * parses the "depends on" portion of the XML file + */ + //TODO(kprobst): not currently used, but will be for dependencies + /*private void parseDependsOn(final HashMap<String, CodeCollection> nameToCodeColl, Attributes attributes) { + if (attributes.getValue("idref") != null){ + String curDepClassId = attributes.getValue("idref"); + + if (curDepClassId.contains(":")){ + // strip everything after the :: (to get to class, even if it's a method) + curDepClassId = curDepClassId.replaceAll(":.*", ""); + } + if (curDepClassId.contains("$")){ + curDepClassId = curDepClassId.replaceAll("\\$.*", ""); + } + + if (! GlobalInformation.classToWhatItDependsOn.containsKey(curClassId)){ + HashSet<String> insertSet = new HashSet<String>(); + GlobalInformation.classToWhatItDependsOn.put(curClassId, insertSet); + } + else{ + GlobalInformation.classToWhatItDependsOn.get(curClassId).add(curDepClassId); + } + } + }*/ + }; + return handler; + } + + + + + private static DefaultHandler scanXMLDocument() { + + DefaultHandler handler = new DefaultHandler() { + + + /** + * This method deals with the beginning of the XML element. + * It analyzes the XML node and adds its information to the relevant literal or code collection for later analysis. + * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) + */ + @Override + public void startElement(String nsUri, String strippedName, String tagName, Attributes attributes) { + + if (strippedName.compareTo("js") == 0){ + if (attributes.getValue("fragment") != null){ + GlobalInformation.numFragments++; + } + } + } + }; + + return handler; + } + + + /* + * assigns code to "all other code" if none of the special categories apply + */ + private static void updateAllOtherCodeType(final HashMap<String, CodeCollection> nameToCodeColl){ + //all classes not in any of the other categories + for (String className : GlobalInformation.classToPackage.keySet()){ + if ( (!nameToCodeColl.get("widget").classes.contains(className))&& + (!nameToCodeColl.get("rpcUser").classes.contains(className))&& + (!nameToCodeColl.get("rpcGwt").classes.contains(className))&& + (!nameToCodeColl.get("rpcGen").classes.contains(className))&& + (!nameToCodeColl.get("jre").classes.contains(className))&& + (!nameToCodeColl.get("gwtLang").classes.contains(className))){ + nameToCodeColl.get("allOther").classes.add(className); + } + } + } + + /* + * generates all the HTML files + */ + private static void makeHTMLFiles( + final TreeMap<String, LiteralsCollection> nameToLitColl, + final HashMap<String, CodeCollection> nameToCodeColl) { + + try { + MakeTopLevelHtmlForPerm.makePackageClassesHtmls(); + MakeTopLevelHtmlForPerm.makeCodeTypeClassesHtmls(nameToCodeColl); + MakeTopLevelHtmlForPerm.makeLiteralsClassesHtmls(nameToLitColl); + MakeTopLevelHtmlForPerm.makeStringLiteralsClassesHtmls(nameToLitColl); + MakeTopLevelHtmlForPerm.makeFragmentClassesHtmls(); + + //make the shell last so we can display aggregate information here + MakeTopLevelHtmlForPerm.makeHTMLShell(nameToCodeColl, nameToLitColl); + + } catch (IOException e) { + throw new RuntimeException("Cannot open file. ", e); + } + } + + + /* + * cleans up the RPC code categories + */ + private static void foldInRPCHeuristic( + final HashMap<String, CodeCollection> nameToCodeColl) { + /** + * Heuristic: this moves all classes that override serializable from RPC to "Other Code" *if* there is no RPC generated code, i.e., if the + * application really is not using RPC + */ + + + if (nameToCodeColl.get("rpcGen").classes.size() == 0){ + + for (String className : nameToCodeColl.get("rpcUser").classes){ + + if ((! nameToCodeColl.get("widget").classes.contains(className))&& + (! nameToCodeColl.get("jre").classes.contains(className))&& + (! nameToCodeColl.get("gwtLang").classes.contains(className))){ + nameToCodeColl.get("allOther").classes.add(className); + } + } + nameToCodeColl.get("rpcUser").classes.clear(); + + for (String className : nameToCodeColl.get("rpcGwt").classes){ + if ((! nameToCodeColl.get("widget").classes.contains(className))&& + (! nameToCodeColl.get("jre").classes.contains(className))&& + (! nameToCodeColl.get("gwtLang").classes.contains(className))){ + nameToCodeColl.get("allOther").classes.add(className); + } + + } + nameToCodeColl.get("rpcGwt").classes.clear(); + } + + + } + + + /* + * unescape the JS snippets - in the XML file they are XML encoded for correct display, but this + * will mess up the byte counts + */ + public static String unEscapeXml(String escaped) { + String unescaped = escaped.replaceAll("&","\\&"); + unescaped = unescaped.replaceAll("<","\\<"); + unescaped = unescaped.replaceAll(">","\\>"); + unescaped = unescaped.replaceAll(""","\\\""); + //escaped = escaped.replaceAll("\\n", ""); + unescaped = unescaped.replaceAll("'","\\'"); + return unescaped; + } + + + + +} + + + + +