Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Side by Side Diff: pkg/analysis_server/lib/src/get_handler.dart

Issue 840953008: Alternate status page (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Sorted and formatted Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library get.handler; 5 library analysis_server.src.get_handler;
6 6
7 import 'dart:collection';
7 import 'dart:convert'; 8 import 'dart:convert';
8 import 'dart:io'; 9 import 'dart:io';
9 import 'dart:math'; 10 import 'dart:math';
10 11
11 import 'package:analysis_server/src/analysis_server.dart'; 12 import 'package:analysis_server/src/analysis_server.dart';
12 import 'package:analysis_server/src/domain_completion.dart'; 13 import 'package:analysis_server/src/domain_completion.dart';
14 import 'package:analysis_server/src/domain_execution.dart';
15 import 'package:analysis_server/src/operation/operation.dart';
16 import 'package:analysis_server/src/operation/operation_analysis.dart';
17 import 'package:analysis_server/src/operation/operation_queue.dart';
18 import 'package:analysis_server/src/protocol.dart' hide Element;
13 import 'package:analysis_server/src/socket_server.dart'; 19 import 'package:analysis_server/src/socket_server.dart';
20 import 'package:analysis_server/src/status/ast_writer.dart';
21 import 'package:analysis_server/src/status/element_writer.dart';
14 import 'package:analyzer/file_system/file_system.dart'; 22 import 'package:analyzer/file_system/file_system.dart';
15 import 'package:analyzer/instrumentation/instrumentation.dart'; 23 import 'package:analyzer/src/generated/ast.dart';
24 import 'package:analyzer/src/generated/element.dart';
16 import 'package:analyzer/src/generated/engine.dart'; 25 import 'package:analyzer/src/generated/engine.dart';
17 import 'package:analyzer/src/generated/java_engine.dart'; 26 import 'package:analyzer/src/generated/java_engine.dart';
18 import 'package:analyzer/src/generated/source.dart'; 27 import 'package:analyzer/src/generated/source.dart';
19 28
20 import 'analysis_server.dart'; 29 import 'analysis_server.dart';
21 30
22 /** 31 /**
32 * A function that can be used to generate HTML output into the given [buffer].
33 * The HTML that is generated must be valid (special characters must already be
34 * encoded).
35 */
36 typedef void HtmlGenerator(StringBuffer buffer);
37
38 /**
23 * Instances of the class [GetHandler] handle GET requests. 39 * Instances of the class [GetHandler] handle GET requests.
24 */ 40 */
25 class GetHandler { 41 class GetHandler {
26 /** 42 /**
27 * The path used to request the status of the analysis server as a whole. 43 * The path used to request the status of the analysis server as a whole.
28 */ 44 */
29 static const String STATUS_PATH = '/status'; 45 static const String STATUS_PATH = '/status';
30 46
31 /** 47 /**
48 * The path used to request information about a element model.
49 */
50 static const String AST_PATH = '/ast';
51
52 /**
32 * The path used to request information about the cache entry corresponding 53 * The path used to request information about the cache entry corresponding
33 * to a single file. 54 * to a single file.
34 */ 55 */
35 static const String CACHE_ENTRY_PATH = '/cache_entry'; 56 static const String CACHE_ENTRY_PATH = '/cache_entry';
36 57
37 /** 58 /**
59 * The path used to request information about the cache entry corresponding
60 * to a single file.
61 */
62 static const String CACHE_ENTRY2_PATH = '/cache_entry2';
63
64 /**
38 * The path used to request the list of source files in a certain cache 65 * The path used to request the list of source files in a certain cache
39 * state. 66 * state.
40 */ 67 */
41 static const String CACHE_STATE_PATH = '/cache_state'; 68 static const String CACHE_STATE_PATH = '/cache_state';
42 69
43 /** 70 /**
44 * The path used to request code completion information. 71 * The path used to request code completion information.
45 */ 72 */
46 static const String COMPLETION_PATH = '/completion'; 73 static const String COMPLETION_PATH = '/completion';
47 74
48 /** 75 /**
76 * The path used to request information about a specific context.
77 */
78 static const String CONTEXT_PATH = '/context';
79
80 /**
81 * The path used to request information about a element model.
82 */
83 static const String ELEMENT_PATH = '/element';
84
85 /**
49 * The path used to request an overlay contents. 86 * The path used to request an overlay contents.
50 */ 87 */
51 static const String OVERLAY_PATH = '/overlay'; 88 static const String OVERLAY_PATH = '/overlay';
52 89
53 /** 90 /**
54 * The path used to request overlays information. 91 * The path used to request overlays information.
55 */ 92 */
56 static const String OVERLAYS_PATH = '/overlays'; 93 static const String OVERLAYS_PATH = '/overlays';
57 94
58 /** 95 /**
59 * Query parameter used to represent the cache state to search for, when 96 * Query parameter used to represent the cache state to search for, when
60 * accessing [CACHE_STATE_PATH]. 97 * accessing [CACHE_STATE_PATH].
61 */ 98 */
62 static const String STATE_QUERY_PARAM = 'state'; 99 static const String STATE_QUERY_PARAM = 'state';
63 100
64 /** 101 /**
65 * Query parameter used to represent the context to search for, when 102 * Query parameter used to represent the context to search for, when
66 * accessing [CACHE_ENTRY_PATH] or [CACHE_STATE_PATH]. 103 * accessing [CACHE_ENTRY_PATH] or [CACHE_STATE_PATH].
67 */ 104 */
68 static const String CONTEXT_QUERY_PARAM = 'context'; 105 static const String CONTEXT_QUERY_PARAM = 'context';
69 106
70 /** 107 /**
71 * Query parameter used to represent the descriptor to search for, when 108 * Query parameter used to represent the descriptor to search for, when
72 * accessing [CACHE_STATE_PATH]. 109 * accessing [CACHE_STATE_PATH].
73 */ 110 */
74 static const String DESCRIPTOR_QUERY_PARAM = 'descriptor'; 111 static const String DESCRIPTOR_QUERY_PARAM = 'descriptor';
75 112
76 /** 113 /**
114 * Query parameter used to represent the index in the [_overlayContents].
115 */
116 static const String ID_PARAM = 'id';
117
118 /**
77 * Query parameter used to represent the source to search for, when accessing 119 * Query parameter used to represent the source to search for, when accessing
78 * [CACHE_ENTRY_PATH]. 120 * [CACHE_ENTRY_PATH].
79 */ 121 */
80 static const String SOURCE_QUERY_PARAM = 'entry'; 122 static const String SOURCE_QUERY_PARAM = 'entry';
81 123
82 /** 124 /**
83 * The socket server whose status is to be reported on. 125 * The socket server whose status is to be reported on.
84 */ 126 */
85 SocketServer _server; 127 SocketServer _server;
86 128
(...skipping 12 matching lines...) Expand all
99 */ 141 */
100 GetHandler(this._server, this._printBuffer); 142 GetHandler(this._server, this._printBuffer);
101 143
102 /** 144 /**
103 * Handle a GET request received by the HTTP server. 145 * Handle a GET request received by the HTTP server.
104 */ 146 */
105 void handleGetRequest(HttpRequest request) { 147 void handleGetRequest(HttpRequest request) {
106 String path = request.uri.path; 148 String path = request.uri.path;
107 if (path == STATUS_PATH) { 149 if (path == STATUS_PATH) {
108 _returnServerStatus(request); 150 _returnServerStatus(request);
151 } else if (path == '/status2') {
152 _returnServerStatus2(request);
153 } else if (path == AST_PATH) {
154 _returnAst(request);
109 } else if (path == CACHE_STATE_PATH) { 155 } else if (path == CACHE_STATE_PATH) {
110 _returnCacheState(request); 156 _returnCacheState(request);
111 } else if (path == CACHE_ENTRY_PATH) { 157 } else if (path == CACHE_ENTRY_PATH) {
112 _returnCacheEntry(request); 158 _returnCacheEntry(request);
159 } else if (path == CACHE_ENTRY2_PATH) {
160 _returnCacheEntry2(request);
113 } else if (path == COMPLETION_PATH) { 161 } else if (path == COMPLETION_PATH) {
114 _returnCompletionInfo(request); 162 _returnCompletionInfo(request);
163 } else if (path == CONTEXT_PATH) {
164 _returnContextInfo(request);
165 } else if (path == ELEMENT_PATH) {
166 _returnElement(request);
115 } else if (path == OVERLAY_PATH) { 167 } else if (path == OVERLAY_PATH) {
116 _returnOverlayContents(request); 168 _returnOverlayContents(request);
117 } else if (path == OVERLAYS_PATH) { 169 } else if (path == OVERLAYS_PATH) {
118 _returnOverlaysInfo(request); 170 _returnOverlaysInfo(request);
119 } else { 171 } else {
120 _returnUnknownRequest(request); 172 _returnUnknownRequest(request);
121 } 173 }
122 } 174 }
123 175
124 /** 176 /**
177 * Return the folder being managed by the given [analysisServer] that matches
178 * the given [contextFilter], or `null` if there is none.
179 */
180 Folder _findFolder(AnalysisServer analysisServer, String contextFilter) {
181 return analysisServer.folderMap.keys.firstWhere(
182 (Folder folder) => folder.path == contextFilter,
183 orElse: () => null);
184 }
185
186 /**
187 * Return `true` if the given analysis [context] has at least one entry with
188 * an exception.
189 */
190 bool _hasException(AnalysisContextImpl context) {
191 bool hasException = false;
192 context.visitCacheItems(
193 (Source source, SourceEntry sourceEntry, DataDescriptor rowDesc,
194 CacheState state) {
195 if (sourceEntry.exception != null) {
196 hasException = true;
197 }
198 });
199 return hasException;
200 }
201
202 Folder _keyForValue(Map<Folder, AnalysisContext> folderMap,
203 AnalysisContext context) {
204 for (Folder folder in folderMap.keys) {
205 if (folderMap[folder] == context) {
206 return folder;
207 }
208 }
209 return null;
210 }
211
212 /**
125 * Create a link to [path] with query parameters [params], with inner HTML 213 * Create a link to [path] with query parameters [params], with inner HTML
126 * [innerHtml]. 214 * [innerHtml]. If [hasError] is `true`, then the link will have the class
215 * 'error'.
127 */ 216 */
128 String _makeLink(String path, Map<String, String> params, String innerHtml) { 217 String _makeLink(String path, Map<String, String> params, String innerHtml,
218 [bool hasError = false]) {
129 Uri uri = new Uri(path: path, queryParameters: params); 219 Uri uri = new Uri(path: path, queryParameters: params);
130 return '<a href="${HTML_ESCAPE.convert(uri.toString())}">$innerHtml</a>'; 220 String href = HTML_ESCAPE.convert(uri.toString());
221 String classAttribute = hasError ? ' class="error"' : '';
222 return '<a href="$href"$classAttribute>$innerHtml</a>';
131 } 223 }
132 224
133 /** 225 /**
134 * Generate a table showing the cache values corresponding to the given 226 * Generate a table showing the cache values corresponding to the given
135 * [descriptors], using [getState] to get the cache state corresponding to 227 * [descriptors], using [getState] to get the cache state corresponding to
136 * each descriptor, and [getValue] to get the cached value corresponding to 228 * each descriptor, and [getValue] to get the cached value corresponding to
137 * each descriptor. Append the resulting HTML to [response]. 229 * each descriptor. Append the resulting HTML to [response].
138 */ 230 */
139 void _outputDescriptorTable(HttpResponse response, 231 void _outputDescriptorTable(HttpResponse response,
140 List<DataDescriptor> descriptors, CacheState getState(DataDescriptor), dyn amic 232 List<DataDescriptor> descriptors, CacheState getState(DataDescriptor), dyn amic
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 } 265 }
174 response.write('</ul>'); 266 response.write('</ul>');
175 } else { 267 } else {
176 response.write(HTML_ESCAPE.convert(value.toString())); 268 response.write(HTML_ESCAPE.convert(value.toString()));
177 response.write( 269 response.write(
178 ' <i>(${HTML_ESCAPE.convert(value.runtimeType.toString())})</i>'); 270 ' <i>(${HTML_ESCAPE.convert(value.runtimeType.toString())})</i>');
179 } 271 }
180 } 272 }
181 273
182 /** 274 /**
275 * Return a response containing information about an AST structure.
276 */
277 void _returnAst(HttpRequest request) {
278 AnalysisServer analysisServer = _server.analysisServer;
279 if (analysisServer == null) {
280 return _returnFailure(request, 'Analysis server not running');
281 }
282 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
283 if (contextFilter == null) {
284 return _returnFailure(
285 request,
286 'Query parameter $CONTEXT_QUERY_PARAM required');
287 }
288 Folder folder = _findFolder(analysisServer, contextFilter);
289 if (folder == null) {
290 return _returnFailure(request, 'Invalid context: $contextFilter');
291 }
292 String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
293 if (sourceUri == null) {
294 return _returnFailure(
295 request,
296 'Query parameter $SOURCE_QUERY_PARAM required');
297 }
298
299 AnalysisContextImpl context = analysisServer.folderMap[folder];
300
301 _writeResponse(request, (StringBuffer buffer) {
302 _writePage(
303 buffer,
304 'Analysis Server - AST Structure',
305 ['Context: $contextFilter', 'File: $sourceUri'],
306 (HttpResponse) {
307 Source source = context.sourceFactory.forUri(sourceUri);
308 if (source == null) {
309 buffer.write('<p>Not found.</p>');
310 return;
311 }
312 SourceEntry entry = context.getReadableSourceEntryOrNull(source);
313 if (entry == null) {
314 buffer.write('<p>Not found.</p>');
315 return;
316 }
317 CompilationUnit ast = (entry as DartEntry).anyParsedCompilationUnit;
318 if (ast == null) {
319 buffer.write('<p>null</p>');
320 return;
321 }
322 ast.accept(new AstWriter(buffer));
323 });
324 });
325 }
326
327 /**
183 * Return a response containing information about a single source file in the 328 * Return a response containing information about a single source file in the
184 * cache. 329 * cache.
185 */ 330 */
186 void _returnCacheEntry(HttpRequest request) { 331 void _returnCacheEntry(HttpRequest request) {
187 // Figure out which context is being searched for. 332 // Figure out which context is being searched for.
188 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM]; 333 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
189 if (contextFilter == null) { 334 if (contextFilter == null) {
190 return _returnFailure( 335 return _returnFailure(
191 request, 336 request,
192 'Query parameter $CONTEXT_QUERY_PARAM required'); 337 'Query parameter $CONTEXT_QUERY_PARAM required');
193 } 338 }
194 339
195 // Figure out which CacheEntry is being searched for. 340 // Figure out which CacheEntry is being searched for.
196 String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM]; 341 String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
197 if (sourceUri == null) { 342 if (sourceUri == null) {
198 return _returnFailure( 343 return _returnFailure(
199 request, 344 request,
200 'Query parameter $SOURCE_QUERY_PARAM required'); 345 'Query parameter $SOURCE_QUERY_PARAM required');
201 } 346 }
202 347
203 AnalysisServer analysisServer = _server.analysisServer; 348 AnalysisServer analysisServer = _server.analysisServer;
204 if (analysisServer == null) { 349 if (analysisServer == null) {
205 return _returnFailure(request, 'Analysis server not running'); 350 return _returnFailure(request, 'Analysis server not running');
206 } 351 }
352
207 HttpResponse response = request.response; 353 HttpResponse response = request.response;
208 response.statusCode = HttpStatus.OK; 354 response.statusCode = HttpStatus.OK;
209 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); 355 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html");
210 response.write('<html>'); 356 response.write('<html>');
211 response.write('<head>'); 357 response.write('<head>');
212 response.write('<title>Dart Analysis Server - Search result</title>'); 358 response.write('<title>Dart Analysis Server - Search result</title>');
213 response.write('</head>'); 359 response.write('</head>');
214 response.write('<body>'); 360 response.write('<body>');
215 response.write('<h1>'); 361 response.write('<h1>');
216 response.write('File ${HTML_ESCAPE.convert(sourceUri)}'); 362 response.write('File ${HTML_ESCAPE.convert(sourceUri)}');
(...skipping 29 matching lines...) Expand all
246 entry.libraryDescriptors, 392 entry.libraryDescriptors,
247 (DataDescriptor descriptor) => 393 (DataDescriptor descriptor) =>
248 entry.getStateInLibrary(descriptor, librarySource), 394 entry.getStateInLibrary(descriptor, librarySource),
249 (DataDescriptor descriptor) => 395 (DataDescriptor descriptor) =>
250 entry.getValueInLibrary(descriptor, librarySource)); 396 entry.getValueInLibrary(descriptor, librarySource));
251 } 397 }
252 } 398 }
253 }); 399 });
254 response.write('</body>'); 400 response.write('</body>');
255 response.write('</html>'); 401 response.write('</html>');
402
256 response.close(); 403 response.close();
257 } 404 }
258 405
259 /** 406 /**
407 * Return a response containing information about a single source file in the
408 * cache.
409 */
410 void _returnCacheEntry2(HttpRequest request) {
411 AnalysisServer analysisServer = _server.analysisServer;
412 if (analysisServer == null) {
413 return _returnFailure(request, 'Analysis server not running');
414 }
415 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
416 if (contextFilter == null) {
417 return _returnFailure(
418 request,
419 'Query parameter $CONTEXT_QUERY_PARAM required');
420 }
421 Folder folder = _findFolder(analysisServer, contextFilter);
422 if (folder == null) {
423 return _returnFailure(request, 'Invalid context: $contextFilter');
424 }
425 String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
426 if (sourceUri == null) {
427 return _returnFailure(
428 request,
429 'Query parameter $SOURCE_QUERY_PARAM required');
430 }
431
432 AnalysisContextImpl context = analysisServer.folderMap[folder];
433
434 _writeResponse(request, (StringBuffer buffer) {
435 _writePage(
436 buffer,
437 'Analysis Server - Cache Entry',
438 ['Context: $contextFilter', 'File: $sourceUri'],
439 (HttpResponse) {
440 Source source = context.sourceFactory.forUri(sourceUri);
441 if (source == null) {
442 buffer.write('<p>Not found.</p>');
443 return;
444 }
445 SourceEntry entry = context.getReadableSourceEntryOrNull(source);
446 if (entry == null) {
447 buffer.write('<p>Not found.</p>');
448 return;
449 }
450 Map<String, String> linkParameters = <String, String>{
451 CONTEXT_QUERY_PARAM: folder.path,
452 SOURCE_QUERY_PARAM: source.uri.toString()
453 };
454 buffer.write('<h3>Library Independent</h3>');
455 _writeDescriptorTable(
456 buffer,
457 entry.descriptors,
458 entry.getState,
459 entry.getValue,
460 linkParameters);
461 if (entry is DartEntry) {
462 for (Source librarySource in entry.containingLibraries) {
463 String libraryName = HTML_ESCAPE.convert(librarySource.fullName);
464 buffer.write('<h3>In library $libraryName:</h3>');
465 _writeDescriptorTable(
466 buffer,
467 entry.libraryDescriptors,
468 (DataDescriptor descriptor) =>
469 entry.getStateInLibrary(descriptor, librarySource),
470 (DataDescriptor descriptor) =>
471 entry.getValueInLibrary(descriptor, librarySource),
472 linkParameters);
473 }
474 }
475 if (entry.exception != null) {
476 buffer.write('<h3>Exception</h3>');
477 _writeException(buffer, entry.exception);
478 }
479 });
480 });
481 }
482
483 /**
260 * Return a response indicating the set of source files in a certain cache 484 * Return a response indicating the set of source files in a certain cache
261 * state. 485 * state.
262 */ 486 */
263 void _returnCacheState(HttpRequest request) { 487 void _returnCacheState(HttpRequest request) {
264 // Figure out what CacheState is being searched for. 488 // Figure out what CacheState is being searched for.
265 String stateQueryParam = request.uri.queryParameters[STATE_QUERY_PARAM]; 489 String stateQueryParam = request.uri.queryParameters[STATE_QUERY_PARAM];
266 if (stateQueryParam == null) { 490 if (stateQueryParam == null) {
267 return _returnFailure( 491 return _returnFailure(
268 request, 492 request,
269 'Query parameter $STATE_QUERY_PARAM required'); 493 'Query parameter $STATE_QUERY_PARAM required');
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 response.write('<a href="?refresh=5">?refresh=5</a>'); 593 response.write('<a href="?refresh=5">?refresh=5</a>');
370 response.write(' to refresh every 5 seconds</p>'); 594 response.write(' to refresh every 5 seconds</p>');
371 response.write('<p>and '); 595 response.write('<p>and ');
372 response.write('<a href="?maxCount=50">?maxCount=50</a>'); 596 response.write('<a href="?maxCount=50">?maxCount=50</a>');
373 response.write(' to keep the last 50 performance measurements</p>'); 597 response.write(' to keep the last 50 performance measurements</p>');
374 response.write('</body>'); 598 response.write('</body>');
375 response.write('</html>'); 599 response.write('</html>');
376 response.close(); 600 response.close();
377 } 601 }
378 602
603 /**
604 * Return a response containing information about a single source file in the
605 * cache.
606 */
607 void _returnContextInfo(HttpRequest request) {
608 AnalysisServer analysisServer = _server.analysisServer;
609 if (analysisServer == null) {
610 return _returnFailure(request, 'Analysis server not running');
611 }
612 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
613 if (contextFilter == null) {
614 return _returnFailure(
615 request,
616 'Query parameter $CONTEXT_QUERY_PARAM required');
617 }
618 Folder folder = _findFolder(analysisServer, contextFilter);
619 if (folder == null) {
620 return _returnFailure(request, 'Invalid context: $contextFilter');
621 }
622
623 List<String> priorityNames;
624 List<String> explicitNames = <String>[];
625 List<String> implicitNames = <String>[];
626 Map<String, String> links = new HashMap<String, String>();
627 List<CaughtException> exceptions = <CaughtException>[];
628 Map<String, int> overlayMap = new HashMap<String, int>();
629 AnalysisContextImpl context = analysisServer.folderMap[folder];
630 priorityNames =
631 context.prioritySources.map((Source source) => source.fullName).toList() ;
632 context.visitCacheItems(
633 (Source source, SourceEntry sourceEntry, DataDescriptor rowDesc,
634 CacheState state) {
635 String sourceName = source.fullName;
636 if (!links.containsKey(sourceName)) {
637 CaughtException exception = sourceEntry.exception;
638 if (exception != null) {
639 exceptions.add(exception);
640 }
641 String link = _makeLink(CACHE_ENTRY2_PATH, {
642 CONTEXT_QUERY_PARAM: folder.path,
643 SOURCE_QUERY_PARAM: source.uri.toString()
644 }, sourceName, exception != null);
645 if (sourceEntry.explicitlyAdded) {
646 explicitNames.add(sourceName);
647 } else {
648 implicitNames.add(sourceName);
649 }
650 links[sourceName] = link;
651 }
652 });
653 _overlayContents.clear();
654 int count = 0;
655 context.visitContentCache((Source source, int stamp, String contents) {
656 count++;
657 overlayMap[source.fullName] = count;
658 _overlayContents[count] = contents;
659 });
660 explicitNames.sort();
661 implicitNames.sort();
662
663 void _writeFiles(StringBuffer buffer, String title, List<String> fileNames)
664 {
665 buffer.write('<h3>$title</h3>');
666 if (fileNames == null || fileNames.isEmpty) {
667 buffer.write('<p>None</p>');
668 } else {
669 buffer.write('<table style="width: 100%">');
670 for (String fileName in fileNames) {
671 buffer.write('<tr><td>');
672 buffer.write(links[fileName]);
673 buffer.write('</td><td>');
674 if (overlayMap.containsKey(fileName)) {
675 buffer.write(_makeLink(OVERLAY_PATH, {
676 ID_PARAM: overlayMap[fileName].toString()
677 }, 'overlay'));
678 }
679 buffer.write('</td></tr>');
680 }
681 buffer.write('</table>');
682 }
683 }
684
685 _writeResponse(request, (StringBuffer buffer) {
686 _writePage(
687 buffer,
688 'Analysis Server - Context',
689 ['Context: $contextFilter'],
690 (StringBuffer buffer) {
691 List headerRowText = ['Context'];
692 headerRowText.addAll(CacheState.values);
693 buffer.write('<h3>Summary</h3>');
694 buffer.write('<table>');
695 _writeRow2(buffer, headerRowText, header: true);
696 AnalysisContextStatistics statistics = context.statistics;
697 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) {
698 List rowText = [row.name];
699 for (CacheState state in CacheState.values) {
700 String text = row.getCount(state).toString();
701 Map<String, String> params = <String, String>{
702 STATE_QUERY_PARAM: state.toString(),
703 CONTEXT_QUERY_PARAM: folder.path,
704 DESCRIPTOR_QUERY_PARAM: row.name
705 };
706 rowText.add(_makeLink(CACHE_STATE_PATH, params, text));
707 }
708 _writeRow2(buffer, rowText, classes: [null, "right"]);
709 });
710 buffer.write('</table>');
711
712 _writeFiles(buffer, 'Priority Files', priorityNames);
713 _writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
714 _writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
715
716 buffer.write('<h3>Exceptions</h3>');
717 if (exceptions.isEmpty) {
718 buffer.write('<p>None</p>');
719 } else {
720 exceptions.forEach((CaughtException exception) {
721 _writeException(buffer, exception);
722 });
723 }
724 });
725 });
726 }
727
728 /**
729 * Return a response containing information about an element structure.
730 */
731 void _returnElement(HttpRequest request) {
732 AnalysisServer analysisServer = _server.analysisServer;
733 if (analysisServer == null) {
734 return _returnFailure(request, 'Analysis server not running');
735 }
736 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
737 if (contextFilter == null) {
738 return _returnFailure(
739 request,
740 'Query parameter $CONTEXT_QUERY_PARAM required');
741 }
742 Folder folder = _findFolder(analysisServer, contextFilter);
743 if (folder == null) {
744 return _returnFailure(request, 'Invalid context: $contextFilter');
745 }
746 String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
747 if (sourceUri == null) {
748 return _returnFailure(
749 request,
750 'Query parameter $SOURCE_QUERY_PARAM required');
751 }
752
753 AnalysisContextImpl context = analysisServer.folderMap[folder];
754
755 _writeResponse(request, (StringBuffer buffer) {
756 _writePage(
757 buffer,
758 'Analysis Server - Element Model',
759 ['Context: $contextFilter', 'File: $sourceUri'],
760 (HttpResponse) {
761 Source source = context.sourceFactory.forUri(sourceUri);
762 if (source == null) {
763 buffer.write('<p>Not found.</p>');
764 return;
765 }
766 SourceEntry entry = context.getReadableSourceEntryOrNull(source);
767 if (entry == null) {
768 buffer.write('<p>Not found.</p>');
769 return;
770 }
771 LibraryElement element = entry.getValue(DartEntry.ELEMENT);
772 if (element == null) {
773 buffer.write('<p>null</p>');
774 return;
775 }
776 element.accept(new ElementWriter(buffer));
777 });
778 });
779 }
780
379 void _returnFailure(HttpRequest request, String message) { 781 void _returnFailure(HttpRequest request, String message) {
380 HttpResponse response = request.response; 782 HttpResponse response = request.response;
381 response.statusCode = HttpStatus.OK; 783 response.statusCode = HttpStatus.OK;
382 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); 784 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html");
383 response.write('<html>'); 785 response.write('<html>');
384 response.write('<head>'); 786 response.write('<head>');
385 response.write('<title>Dart Analysis Server - Failure</title>'); 787 response.write('<title>Dart Analysis Server - Failure</title>');
386 response.write('</head>'); 788 response.write('</head>');
387 response.write('<body>'); 789 response.write('<body>');
388 response.write(HTML_ESCAPE.convert(message)); 790 response.write(HTML_ESCAPE.convert(message));
389 response.write('</body>'); 791 response.write('</body>');
390 response.write('</html>'); 792 response.write('</html>');
391 response.close(); 793 response.close();
392 } 794 }
393 795
394 void _returnOverlayContents(HttpRequest request) { 796 void _returnOverlayContents(HttpRequest request) {
395 String idString = request.requestedUri.queryParameters['id']; 797 String idString = request.requestedUri.queryParameters[ID_PARAM];
396 int id = int.parse(idString); 798 int id = int.parse(idString);
397 String contents = _overlayContents[id]; 799 String contents = _overlayContents[id];
398 HttpResponse response = request.response; 800 HttpResponse response = request.response;
399 response.statusCode = HttpStatus.OK; 801 response.statusCode = HttpStatus.OK;
400 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); 802 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html");
401 response.write('<html>'); 803 response.write('<html>');
402 response.write('<head>'); 804 response.write('<head>');
403 response.write('<title>Dart Analysis Server - Overlay</title>'); 805 response.write('<title>Dart Analysis Server - Overlay</title>');
404 response.write('</head>'); 806 response.write('</head>');
405 response.write('<body>'); 807 response.write('<body>');
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 }; 933 };
532 rowText.add(_makeLink(CACHE_STATE_PATH, params, text)); 934 rowText.add(_makeLink(CACHE_STATE_PATH, params, text));
533 } 935 }
534 _writeRow(response, rowText, classes: [null, "right"]); 936 _writeRow(response, rowText, classes: [null, "right"]);
535 }); 937 });
536 response.write('</table>'); 938 response.write('</table>');
537 List<CaughtException> exceptions = statistics.exceptions; 939 List<CaughtException> exceptions = statistics.exceptions;
538 if (!exceptions.isEmpty) { 940 if (!exceptions.isEmpty) {
539 response.write('<h2>Exceptions</h2>'); 941 response.write('<h2>Exceptions</h2>');
540 exceptions.forEach((CaughtException exception) { 942 exceptions.forEach((CaughtException exception) {
541 response.write('<p>${exception.exception}</p>'); 943 StringBuffer buffer = new StringBuffer();
944 _writeException(buffer, exception);
945 response.write(buffer.toString());
542 }); 946 });
543 } 947 }
544 }); 948 });
545 } 949 }
546 response.write('<h1>Most recent strings printed by analysis server</h2>'); 950 response.write('<h1>Most recent strings printed by analysis server</h2>');
547 response.write('<pre>'); 951 response.write('<pre>');
548 response.write(HTML_ESCAPE.convert(_printBuffer.join('\n'))); 952 response.write(HTML_ESCAPE.convert(_printBuffer.join('\n')));
549 response.write('</pre>'); 953 response.write('</pre>');
550 response.write('</body>'); 954 response.write('</body>');
551 response.write('</html>'); 955 response.write('</html>');
552 response.close(); 956 response.close();
553 } 957 }
554 958
555 /** 959 /**
960 * Return a response indicating the status of the analysis server.
961 */
962 void _returnServerStatus2(HttpRequest request) {
963 _writeResponse(request, (StringBuffer buffer) {
964 _writePage(buffer, 'Analysis Server - Status', [], (StringBuffer buffer) {
965 if (_writeServerStatus(buffer)) {
966 _writeAnalysisStatus(buffer);
967 _writeEditStatus(buffer);
968 _writeExecutionStatus(buffer);
969 _writeRecentOutput(buffer);
970 }
971 });
972 });
973 }
974
975 /**
556 * Return an error in response to an unrecognized request received by the HTTP 976 * Return an error in response to an unrecognized request received by the HTTP
557 * server. 977 * server.
558 */ 978 */
559 void _returnUnknownRequest(HttpRequest request) { 979 void _returnUnknownRequest(HttpRequest request) {
560 HttpResponse response = request.response; 980 HttpResponse response = request.response;
561 response.statusCode = HttpStatus.NOT_FOUND; 981 response.statusCode = HttpStatus.NOT_FOUND;
562 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); 982 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html");
563 response.write('<html>'); 983 response.write('<html>');
564 response.write('<head>'); 984 response.write('<head>');
565 response.write('<title>Dart Analysis Server - Page Not Found</title>'); 985 response.write('<title>Dart Analysis Server - Page Not Found</title>');
566 response.write('</head>'); 986 response.write('</head>');
567 response.write('<body>'); 987 response.write('<body>');
568 response.write('<h1>Page Not Found</h1>'); 988 response.write('<h1>Page Not Found</h1>');
569 response.write('<p>Try one of these links instead:</p>'); 989 response.write('<p>Try one of these links instead:</p>');
570 response.write('<ul>'); 990 response.write('<ul>');
571 response.write('<li><a href="$STATUS_PATH">Server Status</a></li>'); 991 response.write('<li><a href="$STATUS_PATH">Server Status</a></li>');
572 response.write('<li><a href="$COMPLETION_PATH">Completion Stats</a></li>'); 992 response.write('<li><a href="$COMPLETION_PATH">Completion Stats</a></li>');
573 response.write('<ul>'); 993 response.write('<ul>');
574 response.write('</body>'); 994 response.write('</body>');
575 response.write('</html>'); 995 response.write('</html>');
576 response.close(); 996 response.close();
577 } 997 }
578 998
579 /** 999 /**
1000 * Return a two digit decimal representation of the given integer [value].
Paul Berry 2015/01/20 17:28:11 Nit: this function will produce nonsense if the in
Brian Wilkerson 2015/01/20 17:46:34 Done.
1001 */
1002 String _twoDigit(int value) {
1003 if (value < 10) {
1004 return '0$value';
1005 }
1006 return value.toString();
1007 }
1008
1009 /**
1010 * Write the status of the analysis domain (on the main status page) to the
1011 * given [buffer] object.
1012 */
1013 void _writeAnalysisStatus(StringBuffer buffer) {
1014 AnalysisServer analysisServer = _server.analysisServer;
1015 Map<Folder, AnalysisContext> folderMap = analysisServer.folderMap;
1016 List<Folder> folders = folderMap.keys.toList();
1017 folders.sort(
1018 (Folder first, Folder second) => first.shortName.compareTo(second.shortN ame));
1019 AnalysisOptionsImpl options =
1020 analysisServer.contextDirectoryManager.defaultOptions;
1021 ServerOperationQueue operationQueue = analysisServer.operationQueue;
1022
1023 buffer.write('<h3>Analysis Domain</h3>');
1024 _writeTwoColumns(buffer, (StringBuffer buffer) {
1025 if (operationQueue.isEmpty) {
1026 buffer.write('<p>Status: Done analyzing</p>');
1027 } else {
1028 ServerOperation operation = operationQueue.peek();
1029 if (operation is PerformAnalysisOperation) {
1030 Folder folder = _keyForValue(folderMap, operation.context);
1031 if (folder == null) {
1032 buffer.write('<p>Status: Analyzing in unmapped context</p>');
1033 } else {
1034 buffer.write('<p>Status: Analyzing in ${folder.path}</p>');
1035 }
1036 } else {
1037 buffer.write('<p>Status: Analyzing</p>');
1038 }
1039 }
1040
1041 buffer.write('<p><b>Analysis Contexts</b></p>');
1042 buffer.write('<p>');
1043 bool first = true;
1044 folders.forEach((Folder folder) {
1045 if (first) {
1046 first = false;
1047 } else {
1048 buffer.write('<br>');
1049 }
1050 String key = folder.shortName;
1051 buffer.write(_makeLink(CONTEXT_PATH, {
1052 CONTEXT_QUERY_PARAM: folder.path
1053 }, key, _hasException(folderMap[folder])));
1054 });
1055 buffer.write('</p>');
1056
1057 buffer.write('<p><b>Options</b></p>');
1058 buffer.write('<p>');
1059 _writeOption(
1060 buffer,
1061 'Analyze functon bodies',
1062 options.analyzeFunctionBodies);
1063 _writeOption(buffer, 'Cache size', options.cacheSize);
1064 _writeOption(buffer, 'Generate hints', options.hint);
1065 _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
1066 _writeOption(buffer, 'Generate SDK errors', options.generateSdkErrors);
1067 _writeOption(buffer, 'Incremental resolution', options.incremental);
1068 _writeOption(
1069 buffer,
1070 'Incremental resolution with API changes',
1071 options.incrementalApi);
1072 _writeOption(
1073 buffer,
1074 'Preserve comments',
1075 options.preserveComments,
1076 last: true);
1077 buffer.write('</p>');
1078 }, (StringBuffer buffer) {
1079 _writeSubscriptionMap(
1080 buffer,
1081 AnalysisService.VALUES,
1082 analysisServer.analysisServices);
1083 });
1084 }
1085
1086 /**
580 * Append code completion information. 1087 * Append code completion information.
581 */ 1088 */
582 void _writeCompletionInfo(HttpResponse response, maxCount) { 1089 void _writeCompletionInfo(HttpResponse response, maxCount) {
583 response.write('<h1>Code Completion</h1>'); 1090 response.write('<h1>Code Completion</h1>');
584 AnalysisServer analysisServer = _server.analysisServer; 1091 AnalysisServer analysisServer = _server.analysisServer;
585 if (analysisServer == null) { 1092 if (analysisServer == null) {
586 response.write('<p>Not running</p>'); 1093 response.write('<p>Not running</p>');
587 return; 1094 return;
588 } 1095 }
589 CompletionDomainHandler handler = analysisServer.handlers.firstWhere( 1096 CompletionDomainHandler handler = analysisServer.handlers.firstWhere(
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 '&nbsp;&nbsp;', 1162 '&nbsp;&nbsp;',
656 performance.suggestionCount, 1163 performance.suggestionCount,
657 '&nbsp;&nbsp;', 1164 '&nbsp;&nbsp;',
658 performance.snippet]); 1165 performance.snippet]);
659 }); 1166 });
660 response.write('</table>'); 1167 response.write('</table>');
661 } 1168 }
662 } 1169 }
663 1170
664 /** 1171 /**
1172 * Generate a table showing the cache values corresponding to the given
1173 * [descriptors], using [getState] to get the cache state corresponding to
1174 * each descriptor, and [getValue] to get the cached value corresponding to
1175 * each descriptor. Append the resulting HTML to the given [buffer]. The
1176 * [linkParameters] will be used if the value is too large to be displayed on
1177 * the current page and needs to be linked to a separate page.
1178 */
1179 void _writeDescriptorTable(StringBuffer buffer,
1180 List<DataDescriptor> descriptors, CacheState getState(DataDescriptor), dyn amic
1181 getValue(DataDescriptor), Map<String, String> linkParameters) {
1182 buffer.write('<dl>');
1183 for (DataDescriptor descriptor in descriptors) {
1184 String descriptorName = HTML_ESCAPE.convert(descriptor.toString());
1185 String descriptorState =
1186 HTML_ESCAPE.convert(getState(descriptor).toString());
1187 buffer.write('<dt>$descriptorName ($descriptorState)</dt><dd>');
1188 try {
1189 _writeValueAsHtml(buffer, getValue(descriptor), linkParameters);
1190 } catch (exception) {
1191 buffer.write('(${HTML_ESCAPE.convert(exception.toString())})');
1192 }
1193 buffer.write('</dd>');
1194 }
1195 buffer.write('</dl>');
1196 }
1197
1198 /**
1199 * Write the status of the edit domain (on the main status page) to the given
1200 * [buffer].
1201 */
1202 void _writeEditStatus(StringBuffer buffer) {
1203 buffer.write('<h3>Edit Domain</h3>');
1204 _writeTwoColumns(buffer, (StringBuffer buffer) {
1205 buffer.write('<p><b>Performance Data</b></p>');
1206 buffer.write('<p>');
1207 buffer.write(_makeLink(COMPLETION_PATH, {}, 'Completion data'));
1208 buffer.write('</p>');
1209 }, (StringBuffer buffer) {
1210 });
1211 }
1212
1213 /**
1214 * Write a representation of the given [caughtException] to the given
1215 * [buffer]. If [isCause] is `true`, then the exception was a cause for
1216 * another exception.
1217 */
1218 void _writeException(StringBuffer buffer, CaughtException caughtException,
1219 {bool isCause: false}) {
1220 Object exception = caughtException.exception;
1221
1222 if (exception is AnalysisException) {
1223 buffer.write('<p>');
1224 if (isCause) {
1225 buffer.write('Caused by ');
1226 }
1227 buffer.write(exception.message);
1228 buffer.write('</p>');
1229 _writeStackTrace(buffer, caughtException.stackTrace);
1230 CaughtException cause = exception.cause;
1231 if (cause != null) {
1232 buffer.write('<blockquote>');
1233 _writeException(buffer, cause, isCause: true);
1234 buffer.write('</blockquote>');
1235 }
1236 } else {
1237 buffer.write('<p>');
1238 if (isCause) {
1239 buffer.write('Caused by ');
1240 }
1241 buffer.write(exception.toString());
1242 buffer.write('<p>');
1243 _writeStackTrace(buffer, caughtException.stackTrace);
1244 }
1245 }
1246
1247 /**
1248 * Write the status of the execution domain (on the main status page) to the
1249 * given [buffer].
1250 */
1251 void _writeExecutionStatus(StringBuffer buffer) {
1252 AnalysisServer analysisServer = _server.analysisServer;
1253 ExecutionDomainHandler handler = analysisServer.handlers.firstWhere(
1254 (RequestHandler handler) => handler is ExecutionDomainHandler,
1255 orElse: () => null);
1256 Set<ExecutionService> services = new Set<ExecutionService>();
1257 if (handler.onFileAnalyzed != null) {
1258 services.add(ExecutionService.LAUNCH_DATA);
1259 }
1260
1261 if (handler != null) {
1262 buffer.write('<h3>Execution Domain</h3>');
1263 _writeTwoColumns(buffer, (StringBuffer buffer) {
1264 _writeSubscriptionList(buffer, ExecutionService.VALUES, services);
1265 }, (StringBuffer buffer) {
1266 });
1267 }
1268 }
1269
1270 /**
1271 * Write a representation of an analysis option with the given [name] and
1272 * [value] to the given [buffer]. The option should be separated from other
1273 * options unless the [last] flag is true, indicating that this is the last
1274 * option in the list of options.
1275 */
1276 void _writeOption(StringBuffer buffer, String name, Object value, {bool last:
1277 false}) {
1278 buffer.write(name);
1279 buffer.write(' = ');
1280 buffer.write(value.toString());
1281 if (!last) {
1282 buffer.write('<br>');
1283 }
1284 }
1285
1286 /**
1287 * Write a standard HTML page to the given [buffer]. The page will have the
1288 * given [title] and a body that is generated by the given [body] generator.
1289 */
1290 void _writePage(StringBuffer buffer, String title, List<String> subtitles,
1291 HtmlGenerator body) {
1292 DateTime now = new DateTime.now();
1293 String date = "${now.month}/${now.day}/${now.year}";
1294 String time =
1295 "${now.hour}:${_twoDigit(now.minute)}:${_twoDigit(now.second)}.${now.mil lisecond}";
1296
1297 buffer.write('<!DOCTYPE html>');
1298 buffer.write('<html>');
1299 buffer.write('<head>');
1300 buffer.write('<meta charset="utf-8">');
1301 buffer.write(
1302 '<meta name="viewport" content="width=device-width, initial-scale=1.0">' );
1303 buffer.write('<title>$title</title>');
1304 buffer.write('<style>');
1305 buffer.write('a {color: #0000DD; text-decoration: none;}');
1306 buffer.write('a:link.error {background-color: #FFEEEE;}');
1307 buffer.write('a:visited.error {background-color: #FFEEEE;}');
1308 buffer.write('a:hover.error {background-color: #FFEEEE;}');
1309 buffer.write('a:active.error {background-color: #FFEEEE;}');
1310 buffer.write(
1311 'h3 {background-color: #DDDDDD; margin-top: 0em; margin-bottom: 0em;}');
1312 buffer.write('p {margin-top: 0.5em; margin-bottom: 0.5em;}');
1313 // response.write('span.error {text-decoration-line: underline; text-decorati on-color: red; text-decoration-style: wavy;}');
1314 buffer.write(
1315 'table.column {border: 0px solid black; width: 100%; table-layout: fixed ;}');
1316 buffer.write('td.column {vertical-align: top; width: 50%;}');
1317 buffer.write('td.right {text-align: right;}');
1318 buffer.write('</style>');
1319 buffer.write('</head>');
1320
1321 buffer.write('<body>');
1322 buffer.write(
1323 '<h2>$title <small><small>(as of $time on $date)</small></small></h2>');
1324 if (subtitles != null && subtitles.isNotEmpty) {
1325 buffer.write('<blockquote>');
1326 bool first = true;
1327 for (String subtitle in subtitles) {
1328 if (first) {
1329 first = false;
1330 } else {
1331 buffer.write('<br>');
1332 }
1333 buffer.write('<b>');
1334 buffer.write(subtitle);
1335 buffer.write('</b>');
1336 }
1337 buffer.write('</blockquote>');
1338 }
1339 try {
1340 body(buffer);
1341 } catch (exception, stackTrace) {
1342 buffer.write('<h3>Exception while creating page</h3>');
1343 _writeException(buffer, new CaughtException(exception, stackTrace));
1344 }
1345 buffer.write('</body>');
1346 buffer.write('</html>');
1347 }
1348
1349 /**
1350 * Write the recent output section (on the main status page) to the given
1351 * [buffer] object.
1352 */
1353 void _writeRecentOutput(StringBuffer buffer) {
1354 buffer.write('<h3>Recent Output</h3>');
1355 String output = HTML_ESCAPE.convert(_printBuffer.join('\n'));
1356 if (output.isEmpty) {
1357 buffer.write('<i>none</i>');
1358 } else {
1359 buffer.write('<pre>');
1360 buffer.write(output);
1361 buffer.write('</pre>');
1362 }
1363 }
1364
1365 void _writeResponse(HttpRequest request, HtmlGenerator writePage) {
1366 HttpResponse response = request.response;
1367 response.statusCode = HttpStatus.OK;
1368 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html");
1369 try {
1370 StringBuffer buffer = new StringBuffer();
1371 try {
1372 writePage(buffer);
1373 } catch (exception, stackTrace) {
1374 buffer.clear();
1375 _writePage(buffer, 'Internal Exception', [], (StringBuffer buffer) {
1376 _writeException(buffer, new CaughtException(exception, stackTrace));
1377 });
1378 }
1379 response.write(buffer.toString());
1380 } finally {
1381 response.close();
1382 }
1383 }
1384
1385 /**
665 * Write a single row within a table to the given [response] object. The row 1386 * Write a single row within a table to the given [response] object. The row
666 * will have one cell for each of the [columns], and will be a header row if 1387 * will have one cell for each of the [columns], and will be a header row if
667 * [header] is `true`. 1388 * [header] is `true`.
668 */ 1389 */
669 void _writeRow(HttpResponse response, List<Object> columns, {bool header: 1390 void _writeRow(HttpResponse response, List<Object> columns, {bool header:
670 false, List<String> classes}) { 1391 false, List<String> classes}) {
671 response.write('<tr>'); 1392 response.write('<tr>');
672 int count = columns.length; 1393 int count = columns.length;
673 int maxClassIndex = classes == null ? 0 : classes.length - 1; 1394 int maxClassIndex = classes == null ? 0 : classes.length - 1;
674 for (int i = 0; i < count; i++) { 1395 for (int i = 0; i < count; i++) {
(...skipping 12 matching lines...) Expand all
687 response.write(columns[i]); 1408 response.write(columns[i]);
688 if (header) { 1409 if (header) {
689 response.write('</th>'); 1410 response.write('</th>');
690 } else { 1411 } else {
691 response.write('</td>'); 1412 response.write('</td>');
692 } 1413 }
693 } 1414 }
694 1415
695 response.write('</tr>'); 1416 response.write('</tr>');
696 } 1417 }
1418
1419 /**
1420 * Write a single row within a table to the given [buffer]. The row will have
1421 * one cell for each of the [columns], and will be a header row if [header] is
1422 * `true`.
1423 */
1424 void _writeRow2(StringBuffer buffer, List<Object> columns, {bool header:
1425 false, List<String> classes}) {
1426 buffer.write('<tr>');
1427 int count = columns.length;
1428 int maxClassIndex = classes == null ? 0 : classes.length - 1;
1429 for (int i = 0; i < count; i++) {
1430 String classAttribute = '';
1431 if (classes != null) {
1432 String className = classes[min(i, maxClassIndex)];
1433 if (className != null) {
1434 classAttribute = ' class="$className"';
1435 }
1436 }
1437 if (header) {
1438 buffer.write('<th$classAttribute>');
1439 } else {
1440 buffer.write('<td$classAttribute>');
1441 }
1442 buffer.write(columns[i]);
1443 if (header) {
1444 buffer.write('</th>');
1445 } else {
1446 buffer.write('</td>');
1447 }
1448 }
1449 buffer.write('</tr>');
1450 }
1451
1452 /**
1453 * Write the status of the service domain (on the main status page) to the
1454 * given [response] object.
1455 */
1456 bool _writeServerStatus(StringBuffer buffer) {
1457 AnalysisServer analysisServer = _server.analysisServer;
1458 Set<ServerService> services = analysisServer.serverServices;
1459
1460 buffer.write('<h3>Server Domain</h3>');
1461 _writeTwoColumns(buffer, (StringBuffer buffer) {
1462 if (analysisServer == null) {
1463 buffer.write('Status: <span style="color:red">Not running</span>');
1464 return false;
1465 }
1466 buffer.write('<p>');
1467 buffer.write('Status: Running<br>');
1468 buffer.write('Instrumentation: ');
1469 if (AnalysisEngine.instance.instrumentationService.isActive) {
1470 buffer.write('<span style="color:red">Active</span>');
1471 } else {
1472 buffer.write('Inactive');
1473 }
1474 buffer.write('<br>');
1475 buffer.write('Version: ');
1476 buffer.write(AnalysisServer.VERSION);
1477 buffer.write('</p>');
1478 }, (StringBuffer buffer) {
1479 _writeSubscriptionList(buffer, ServerService.VALUES, services);
1480 });
1481 return true;
1482 }
1483
1484 /**
1485 * Write a representation of the given [stackTrace] to the given [buffer].
1486 */
1487 void _writeStackTrace(StringBuffer buffer, StackTrace stackTrace) {
1488 if (stackTrace != null) {
1489 String trace = stackTrace.toString().replaceAll('#', '<br>#');
1490 if (trace.startsWith('<br>#')) {
1491 trace = trace.substring(4);
1492 }
1493 buffer.write('<p>');
1494 buffer.write(trace);
1495 buffer.write('</p>');
1496 }
1497 }
1498
1499 /**
1500 * Given a [service] that could be subscribed to and a set of the services
1501 * that are actually subscribed to ([subscribedServices]), write a
1502 * representation of the service to the given [buffer].
1503 */
1504 void _writeSubscriptionInList(StringBuffer buffer, Enum service,
1505 Set<Enum> subscribedServices) {
1506 if (subscribedServices.contains(service)) {
1507 buffer.write('<code>+ </code>');
1508 } else {
1509 buffer.write('<code>- </code>');
1510 }
1511 buffer.write(service.name);
1512 buffer.write('<br>');
1513 }
1514
1515 /**
1516 * Given a [service] that could be subscribed to and a set of paths that are
1517 * subscribed to the services ([subscribedPaths]), write a representation of
1518 * the service to the given [buffer].
1519 */
1520 void _writeSubscriptionInMap(StringBuffer buffer, Enum service,
1521 Set<String> subscribedPaths) {
1522 buffer.write('<p>');
1523 buffer.write(service.name);
1524 buffer.write('</p>');
1525 if (subscribedPaths == null || subscribedPaths.isEmpty) {
1526 buffer.write('none');
1527 } else {
1528 List<String> paths = subscribedPaths.toList();
1529 paths.sort();
1530 for (String path in paths) {
1531 buffer.write('<p>');
1532 buffer.write(path);
1533 buffer.write('</p>');
1534 }
1535 }
1536 }
1537
1538 /**
1539 * Given a list containing all of the services that can be subscribed to in a
1540 * single domain ([allServices]) and a set of the services that are actually
1541 * subscribed to ([subscribedServices]), write a representation of the
1542 * subscriptions to the given [buffer].
1543 */
1544 void _writeSubscriptionList(StringBuffer buffer, List<Enum> allServices,
1545 Set<Enum> subscribedServices) {
1546 buffer.write('<p><b>Subscriptions</b></p>');
1547 buffer.write('<p>');
1548 for (Enum service in allServices) {
1549 _writeSubscriptionInList(buffer, service, subscribedServices);
1550 }
1551 buffer.write('</p>');
1552 }
1553
1554 /**
1555 * Given a list containing all of the services that can be subscribed to in a
1556 * single domain ([allServices]) and a set of the services that are actually
1557 * subscribed to ([subscribedServices]), write a representation of the
1558 * subscriptions to the given [buffer].
1559 */
1560 void _writeSubscriptionMap(StringBuffer buffer, List<Enum> allServices,
1561 Map<Enum, Set<String>> subscribedServices) {
1562 buffer.write('<p><b>Subscriptions</b></p>');
1563 for (Enum service in allServices) {
1564 _writeSubscriptionInMap(buffer, service, subscribedServices[service]);
1565 }
1566 }
1567
1568 /**
1569 * Write two columns of information to the given [buffer], where the
1570 * [leftColumn] and [rightColumn] functions are used to generate the content
1571 * of those columns.
1572 */
1573 void _writeTwoColumns(StringBuffer buffer, HtmlGenerator leftColumn,
1574 HtmlGenerator rightColumn) {
1575 buffer.write(
1576 '<table class="column"><tr class="column"><td class="column">');
1577 leftColumn(buffer);
1578 buffer.write('</td><td class="column">');
1579 rightColumn(buffer);
1580 buffer.write('</td></tr></table>');
1581 }
1582
1583 /**
1584 * Render the given [value] as HTML and append it to the given [buffer]. The
1585 * [linkParameters] will be used if the value is too large to be displayed on
1586 * the current page and needs to be linked to a separate page.
1587 */
1588 void _writeValueAsHtml(StringBuffer buffer, Object value, Map<String,
1589 String> linkParameters) {
1590 if (value == null) {
1591 buffer.write('<i>null</i>');
1592 } else if (value is String) {
1593 buffer.write('<pre>${HTML_ESCAPE.convert(value)}</pre>');
1594 } else if (value is List) {
1595 buffer.write('List containing ${value.length} entries');
1596 buffer.write('<ul>');
1597 for (var entry in value) {
1598 buffer.write('<li>');
1599 _writeValueAsHtml(buffer, entry, linkParameters);
1600 buffer.write('</li>');
1601 }
1602 buffer.write('</ul>');
1603 } else if (value is AstNode) {
1604 String link =
1605 _makeLink(AST_PATH, linkParameters, value.runtimeType.toString());
1606 buffer.write('<i>$link</i>');
1607 } else if (value is Element) {
1608 String link =
1609 _makeLink(ELEMENT_PATH, linkParameters, value.runtimeType.toString());
1610 buffer.write('<i>$link</i>');
1611 } else {
1612 buffer.write(HTML_ESCAPE.convert(value.toString()));
1613 buffer.write(' <i>(${value.runtimeType.toString()})</i>');
1614 }
1615 }
697 } 1616 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698