|
59 | 59 | import java.util.Map.Entry; |
60 | 60 | import java.util.Set; |
61 | 61 | import java.util.SortedMap; |
| 62 | +import javax.annotation.concurrent.GuardedBy; |
62 | 63 |
|
63 | 64 | /*>>> |
64 | 65 | import org.checkerframework.checker.nullness.qual.Nullable; |
|
67 | 68 | /** HTML page formatter for all exported {@link View}s. */ |
68 | 69 | final class StatszZPageHandler extends ZPageHandler { |
69 | 70 |
|
| 71 | + private static final Object monitor = new Object(); |
| 72 | + |
70 | 73 | private final ViewManager viewManager; |
| 74 | + |
| 75 | + // measures, cachedViews and root are created when StatszZPageHandler is initialized, and will |
| 76 | + // be updated every time when there's a new View from viewManager.getAllExportedViews(). |
| 77 | + // viewManager.getAllExportedViews() will be called every time when the StatsZ page is |
| 78 | + // re-rendered, like refreshing or navigating to other paths. |
| 79 | + |
| 80 | + @GuardedBy("monitor") |
71 | 81 | private final Map<String, Measure> measures = Maps.newTreeMap(); |
| 82 | + |
| 83 | + @GuardedBy("monitor") |
72 | 84 | private final Set<View> cachedViews = Sets.newHashSet(); |
| 85 | + |
| 86 | + @GuardedBy("monitor") |
73 | 87 | private final TreeNode root = new TreeNode(); |
74 | 88 |
|
75 | 89 | @VisibleForTesting static final String QUERY_PATH = "path"; |
@@ -139,18 +153,20 @@ private static void emitStyles(PrintWriter out, Formatter formatter) { |
139 | 153 | } |
140 | 154 |
|
141 | 155 | private void emitHtmlBody(Map<String, String> queryMap, PrintWriter out, Formatter formatter) { |
142 | | - groupViewsByDirectoriesAndGetMeasures( |
143 | | - viewManager.getAllExportedViews(), root, measures, cachedViews); |
144 | | - out.write("<h1><a href='?'>StatsZ</a></h1>"); |
145 | | - out.write("<p></p>"); |
146 | | - String path = queryMap.get(QUERY_PATH); |
147 | | - TreeNode current = findNode(path); |
148 | | - emitDirectoryTable(current, path, out, formatter); |
149 | | - if (current != null && current.view != null) { |
150 | | - ViewData viewData = viewManager.getView(current.view.getName()); |
151 | | - emitViewData(viewData, current.view.getName(), out, formatter); |
| 156 | + synchronized (monitor) { |
| 157 | + groupViewsByDirectoriesAndGetMeasures( |
| 158 | + viewManager.getAllExportedViews(), root, measures, cachedViews); |
| 159 | + out.write("<h1><a href='?'>StatsZ</a></h1>"); |
| 160 | + out.write("<p></p>"); |
| 161 | + String path = queryMap.get(QUERY_PATH); |
| 162 | + TreeNode current = findNode(path); |
| 163 | + emitDirectoryTable(current, path, out, formatter); |
| 164 | + if (current != null && current.view != null) { |
| 165 | + ViewData viewData = viewManager.getView(current.view.getName()); |
| 166 | + emitViewData(viewData, current.view.getName(), out, formatter); |
| 167 | + } |
| 168 | + emitMeasureTable(measures, out, formatter); |
152 | 169 | } |
153 | | - emitMeasureTable(measures, out, formatter); |
154 | 170 | } |
155 | 171 |
|
156 | 172 | // Parses view names, creates a tree that represents the directory structure and put each view |
@@ -188,6 +204,7 @@ private static void groupViewsByDirectoriesAndGetMeasures( |
188 | 204 | } |
189 | 205 | } |
190 | 206 |
|
| 207 | + @GuardedBy("monitor") |
191 | 208 | private void emitDirectoryTable( |
192 | 209 | /*@Nullable*/ TreeNode currentNode, |
193 | 210 | /*@Nullable*/ String path, |
@@ -223,13 +240,13 @@ private void emitDirectoryTable( |
223 | 240 | CLASS_LARGER_TR, QUERY_PATH, path + '/' + relativePath, viewName); |
224 | 241 | } |
225 | 242 | } |
226 | | - |
227 | 243 | out.write("</table>"); |
228 | 244 | out.write("<p></p>"); |
229 | 245 | } |
230 | 246 |
|
231 | 247 | // Searches the TreeNode whose absolute path matches the given path, started from root. |
232 | 248 | // Returns null if such a TreeNode doesn't exist. |
| 249 | + @GuardedBy("monitor") |
233 | 250 | private /*@Nullable*/ TreeNode findNode(/*@Nullable*/ String path) { |
234 | 251 | if (Strings.isNullOrEmpty(path) || "/".equals(path)) { // Go back to the root directory. |
235 | 252 | return root; |
@@ -485,7 +502,8 @@ private static void emitHistogramBuckets( |
485 | 502 |
|
486 | 503 | private static void emitMeasureTable( |
487 | 504 | Map<String, Measure> measures, PrintWriter out, Formatter formatter) { |
488 | | - out.write("<h2>Measures</h2>"); |
| 505 | + out.write("<h2>Measures with Views</h2>"); |
| 506 | + out.write("<p>Below are the measures used in registered views.</p>"); |
489 | 507 | out.write("<p></p>"); |
490 | 508 | formatter.format("<table %s frame=box cellspacing=0 cellpadding=2>", TABLE_BORDER); |
491 | 509 | emitMeasureTableHeader(out, formatter); |
|
0 commit comments