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

Side by Side Diff: pkg/analysis_server/lib/plugin/protocol/protocol.dart

Issue 2844273003: Unify the server and plugin versions of the generators (Closed)
Patch Set: add missed files Created 3 years, 7 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
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Support for client code that needs to interact with the requests, responses
7 * and notifications that are part of the analysis server's wire protocol.
8 */
9 library analysis_server.plugin.protocol.protocol;
10
11 import 'dart:collection';
12 import 'dart:convert' hide JsonDecoder;
13
14 import 'package:analysis_server/src/protocol/protocol_internal.dart';
15
16 part 'generated_protocol.dart';
17
18 /**
19 * A [RequestHandler] that supports [startup] and [shutdown] methods.
20 *
21 * Clients may not extend, implement or mix-in this class.
22 */
23 abstract class DomainHandler implements RequestHandler {
24 /**
25 * Perform any operations associated with the shutdown of the domain. It is
26 * not guaranteed that this method will be called. If it is, it will be
27 * called after the last [Request] has been made.
28 */
29 void shutdown() {}
30
31 /**
32 * Perform any operations associated with the startup of the domain. This
33 * will be called before the first [Request].
34 */
35 void startup() {}
36 }
37
38 /**
39 * An interface for enumerated types in the protocol.
40 *
41 * Clients may not extend, implement or mix-in this class.
42 */
43 abstract class Enum {
44 /**
45 * The name of the enumerated value. This should match the name of the
46 * static getter which provides access to this enumerated value.
47 */
48 String get name;
49 }
50
51 /**
52 * A notification from the server about an event that occurred.
53 *
54 * Clients may not extend, implement or mix-in this class.
55 */
56 class Notification {
57 /**
58 * The name of the JSON attribute containing the name of the event that
59 * triggered the notification.
60 */
61 static const String EVENT = 'event';
62
63 /**
64 * The name of the JSON attribute containing the result values.
65 */
66 static const String PARAMS = 'params';
67
68 /**
69 * The name of the event that triggered the notification.
70 */
71 final String event;
72
73 /**
74 * A table mapping the names of notification parameters to their values, or
75 * `null` if there are no notification parameters.
76 */
77 Map<String, Object> _params;
78
79 /**
80 * Initialize a newly created [Notification] to have the given [event] name.
81 * If [_params] is provided, it will be used as the params; otherwise no
82 * params will be used.
83 */
84 Notification(this.event, [this._params]);
85
86 /**
87 * Initialize a newly created instance based on the given JSON data.
88 */
89 factory Notification.fromJson(Map json) {
90 return new Notification(json[Notification.EVENT],
91 json[Notification.PARAMS] as Map<String, Object>);
92 }
93
94 /**
95 * Return a table representing the structure of the Json object that will be
96 * sent to the client to represent this response.
97 */
98 Map<String, Object> toJson() {
99 Map<String, Object> jsonObject = {};
100 jsonObject[EVENT] = event;
101 if (_params != null) {
102 jsonObject[PARAMS] = _params;
103 }
104 return jsonObject;
105 }
106 }
107
108 /**
109 * A request that was received from the client.
110 *
111 * Clients may not extend, implement or mix-in this class.
112 */
113 class Request {
114 /**
115 * The name of the JSON attribute containing the id of the request.
116 */
117 static const String ID = 'id';
118
119 /**
120 * The name of the JSON attribute containing the name of the request.
121 */
122 static const String METHOD = 'method';
123
124 /**
125 * The name of the JSON attribute containing the request parameters.
126 */
127 static const String PARAMS = 'params';
128
129 /**
130 * The name of the optional JSON attribute indicating the time (milliseconds
131 * since epoch) at which the client made the request.
132 */
133 static const String CLIENT_REQUEST_TIME = 'clientRequestTime';
134
135 /**
136 * The unique identifier used to identify this request.
137 */
138 final String id;
139
140 /**
141 * The method being requested.
142 */
143 final String method;
144
145 /**
146 * A table mapping the names of request parameters to their values.
147 */
148 final Map<String, Object> _params;
149
150 /**
151 * The time (milliseconds since epoch) at which the client made the request
152 * or `null` if this information is not provided by the client.
153 */
154 final int clientRequestTime;
155
156 /**
157 * Initialize a newly created [Request] to have the given [id] and [method]
158 * name. If [params] is supplied, it is used as the "params" map for the
159 * request. Otherwise an empty "params" map is allocated.
160 */
161 Request(this.id, this.method,
162 [Map<String, Object> params, this.clientRequestTime])
163 : _params = params ?? new HashMap<String, Object>();
164
165 /**
166 * Return a request parsed from the given json, or `null` if the [data] is
167 * not a valid json representation of a request. The [data] is expected to
168 * have the following format:
169 *
170 * {
171 * 'clientRequestTime': millisecondsSinceEpoch
172 * 'id': String,
173 * 'method': methodName,
174 * 'params': {
175 * paramter_name: value
176 * }
177 * }
178 *
179 * where both the parameters and clientRequestTime are optional.
180 *
181 * The parameters can contain any number of name/value pairs. The
182 * clientRequestTime must be an int representing the time at which the client
183 * issued the request (milliseconds since epoch).
184 */
185 factory Request.fromJson(Map<String, dynamic> result) {
186 var id = result[Request.ID];
187 var method = result[Request.METHOD];
188 if (id is! String || method is! String) {
189 return null;
190 }
191 var time = result[Request.CLIENT_REQUEST_TIME];
192 if (time != null && time is! int) {
193 return null;
194 }
195 var params = result[Request.PARAMS];
196 if (params is Map || params == null) {
197 return new Request(id, method, params as Map<String, Object>, time);
198 } else {
199 return null;
200 }
201 }
202
203 /**
204 * Return a request parsed from the given [data], or `null` if the [data] is
205 * not a valid json representation of a request. The [data] is expected to
206 * have the following format:
207 *
208 * {
209 * 'clientRequestTime': millisecondsSinceEpoch
210 * 'id': String,
211 * 'method': methodName,
212 * 'params': {
213 * paramter_name: value
214 * }
215 * }
216 *
217 * where both the parameters and clientRequestTime are optional.
218 *
219 * The parameters can contain any number of name/value pairs. The
220 * clientRequestTime must be an int representing the time at which the client
221 * issued the request (milliseconds since epoch).
222 */
223 factory Request.fromString(String data) {
224 try {
225 var result = JSON.decode(data);
226 if (result is Map) {
227 return new Request.fromJson(result as Map<String, dynamic>);
228 }
229 return null;
230 } catch (exception) {
231 return null;
232 }
233 }
234
235 /**
236 * Return a table representing the structure of the Json object that will be
237 * sent to the client to represent this response.
238 */
239 Map<String, Object> toJson() {
240 Map<String, Object> jsonObject = new HashMap<String, Object>();
241 jsonObject[ID] = id;
242 jsonObject[METHOD] = method;
243 if (_params.isNotEmpty) {
244 jsonObject[PARAMS] = _params;
245 }
246 if (clientRequestTime != null) {
247 jsonObject[CLIENT_REQUEST_TIME] = clientRequestTime;
248 }
249 return jsonObject;
250 }
251 }
252
253 /**
254 * An exception that occurred during the handling of a request that requires
255 * that an error be returned to the client.
256 *
257 * Clients may not extend, implement or mix-in this class.
258 */
259 class RequestFailure implements Exception {
260 /**
261 * The response to be returned as a result of the failure.
262 */
263 final Response response;
264
265 /**
266 * Initialize a newly created exception to return the given reponse.
267 */
268 RequestFailure(this.response);
269 }
270
271 /**
272 * An object that can handle requests and produce responses for them.
273 *
274 * Clients may not extend, implement or mix-in this class.
275 */
276 abstract class RequestHandler {
277 /**
278 * Attempt to handle the given [request]. If the request is not recognized by
279 * this handler, return `null` so that other handlers will be given a chance
280 * to handle it. Otherwise, return the response that should be passed back to
281 * the client.
282 */
283 Response handleRequest(Request request);
284 }
285
286 /**
287 * A response to a request.
288 *
289 * Clients may not extend, implement or mix-in this class.
290 */
291 class Response {
292 /**
293 * The [Response] instance that is returned when a real [Response] cannot
294 * be provided at the moment.
295 */
296 static final Response DELAYED_RESPONSE = new Response('DELAYED_RESPONSE');
297
298 /**
299 * The name of the JSON attribute containing the id of the request for which
300 * this is a response.
301 */
302 static const String ID = 'id';
303
304 /**
305 * The name of the JSON attribute containing the error message.
306 */
307 static const String ERROR = 'error';
308
309 /**
310 * The name of the JSON attribute containing the result values.
311 */
312 static const String RESULT = 'result';
313
314 /**
315 * The unique identifier used to identify the request that this response is
316 * associated with.
317 */
318 final String id;
319
320 /**
321 * The error that was caused by attempting to handle the request, or `null` if
322 * there was no error.
323 */
324 final RequestError error;
325
326 /**
327 * A table mapping the names of result fields to their values. Should be
328 * `null` if there is no result to send.
329 */
330 Map<String, Object> _result;
331
332 /**
333 * Initialize a newly created instance to represent a response to a request
334 * with the given [id]. If [_result] is provided, it will be used as the
335 * result; otherwise an empty result will be used. If an [error] is provided
336 * then the response will represent an error condition.
337 */
338 Response(this.id, {Map<String, Object> result, this.error})
339 : _result = result;
340
341 /**
342 * Create and return the `DEBUG_PORT_COULD_NOT_BE_OPENED` error response.
343 */
344 Response.debugPortCouldNotBeOpened(Request request, dynamic error)
345 : this(request.id,
346 error: new RequestError(
347 RequestErrorCode.DEBUG_PORT_COULD_NOT_BE_OPENED, '$error'));
348
349 /**
350 * Initialize a newly created instance to represent the FILE_NOT_ANALYZED
351 * error condition.
352 */
353 Response.fileNotAnalyzed(Request request, String file)
354 : this(request.id,
355 error: new RequestError(RequestErrorCode.FILE_NOT_ANALYZED,
356 'File is not analyzed: $file.'));
357
358 /**
359 * Initialize a newly created instance to represent the FORMAT_INVALID_FILE
360 * error condition.
361 */
362 Response.formatInvalidFile(Request request)
363 : this(request.id,
364 error: new RequestError(RequestErrorCode.FORMAT_INVALID_FILE,
365 'Error during `edit.format`: invalid file.'));
366
367 /**
368 * Initialize a newly created instance to represent the FORMAT_WITH_ERROR
369 * error condition.
370 */
371 Response.formatWithErrors(Request request)
372 : this(request.id,
373 error: new RequestError(RequestErrorCode.FORMAT_WITH_ERRORS,
374 'Error during `edit.format`: source contains syntax errors.'));
375
376 /**
377 * Initialize a newly created instance based on the given JSON data.
378 */
379 factory Response.fromJson(Map json) {
380 try {
381 Object id = json[Response.ID];
382 if (id is! String) {
383 return null;
384 }
385 Object error = json[Response.ERROR];
386 RequestError decodedError;
387 if (error is Map) {
388 decodedError = new RequestError.fromJson(
389 new ResponseDecoder(null), '.error', error);
390 }
391 Object result = json[Response.RESULT];
392 Map<String, Object> decodedResult;
393 if (result is Map) {
394 decodedResult = result as Map<String, Object>;
395 }
396 return new Response(id, error: decodedError, result: decodedResult);
397 } catch (exception) {
398 return null;
399 }
400 }
401
402 /**
403 * Initialize a newly created instance to represent the
404 * GET_ERRORS_INVALID_FILE error condition.
405 */
406 Response.getErrorsInvalidFile(Request request)
407 : this(request.id,
408 error: new RequestError(RequestErrorCode.GET_ERRORS_INVALID_FILE,
409 'Error during `analysis.getErrors`: invalid file.'));
410
411 /**
412 * Initialize a newly created instance to represent the
413 * GET_NAVIGATION_INVALID_FILE error condition.
414 */
415 Response.getNavigationInvalidFile(Request request)
416 : this(request.id,
417 error: new RequestError(
418 RequestErrorCode.GET_NAVIGATION_INVALID_FILE,
419 'Error during `analysis.getNavigation`: invalid file.'));
420
421 /**
422 * Initialize a newly created instance to represent the
423 * GET_REACHABLE_SOURCES_INVALID_FILE error condition.
424 */
425 Response.getReachableSourcesInvalidFile(Request request)
426 : this(request.id,
427 error: new RequestError(
428 RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE,
429 'Error during `analysis.getReachableSources`: invalid file.'));
430
431 /**
432 * Initialize a newly created instance to represent an error condition caused
433 * by an analysis.reanalyze [request] that specifies an analysis root that is
434 * not in the current list of analysis roots.
435 */
436 Response.invalidAnalysisRoot(Request request, String rootPath)
437 : this(request.id,
438 error: new RequestError(RequestErrorCode.INVALID_ANALYSIS_ROOT,
439 "Invalid analysis root: $rootPath"));
440
441 /**
442 * Initialize a newly created instance to represent an error condition caused
443 * by a [request] that specifies an execution context whose context root does
444 * not exist.
445 */
446 Response.invalidExecutionContext(Request request, String contextId)
447 : this(request.id,
448 error: new RequestError(RequestErrorCode.INVALID_EXECUTION_CONTEXT,
449 "Invalid execution context: $contextId"));
450
451 /**
452 * Initialize a newly created instance to represent the
453 * INVALID_FILE_PATH_FORMAT error condition.
454 */
455 Response.invalidFilePathFormat(Request request, path)
456 : this(request.id,
457 error: new RequestError(RequestErrorCode.INVALID_FILE_PATH_FORMAT,
458 'Invalid file path format: $path'));
459
460 /**
461 * Initialize a newly created instance to represent an error condition caused
462 * by a [request] that had invalid parameter. [path] is the path to the
463 * invalid parameter, in Javascript notation (e.g. "foo.bar" means that the
464 * parameter "foo" contained a key "bar" whose value was the wrong type).
465 * [expectation] is a description of the type of data that was expected.
466 */
467 Response.invalidParameter(Request request, String path, String expectation)
468 : this(request.id,
469 error: new RequestError(RequestErrorCode.INVALID_PARAMETER,
470 "Invalid parameter '$path'. $expectation."));
471
472 /**
473 * Initialize a newly created instance to represent an error condition caused
474 * by a malformed request.
475 */
476 Response.invalidRequestFormat()
477 : this('',
478 error: new RequestError(
479 RequestErrorCode.INVALID_REQUEST, 'Invalid request'));
480
481 /**
482 * Initialize a newly created instance to represent an error condition caused
483 * by a request that requires an index, but indexing is disabled.
484 */
485 Response.noIndexGenerated(Request request)
486 : this(request.id,
487 error: new RequestError(
488 RequestErrorCode.NO_INDEX_GENERATED, 'Indexing is disabled'));
489
490 /**
491 * Initialize a newly created instance to represent the
492 * ORGANIZE_DIRECTIVES_ERROR error condition.
493 */
494 Response.organizeDirectivesError(Request request, String message)
495 : this(request.id,
496 error: new RequestError(
497 RequestErrorCode.ORGANIZE_DIRECTIVES_ERROR, message));
498
499 /**
500 * Initialize a newly created instance to represent the
501 * REFACTORING_REQUEST_CANCELLED error condition.
502 */
503 Response.refactoringRequestCancelled(Request request)
504 : this(request.id,
505 error: new RequestError(
506 RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
507 'The `edit.getRefactoring` request was cancelled.'));
508
509 /**
510 * Initialize a newly created instance to represent the SERVER_ERROR error
511 * condition.
512 */
513 factory Response.serverError(Request request, exception, stackTrace) {
514 RequestError error =
515 new RequestError(RequestErrorCode.SERVER_ERROR, exception.toString());
516 if (stackTrace != null) {
517 error.stackTrace = stackTrace.toString();
518 }
519 return new Response(request.id, error: error);
520 }
521
522 /**
523 * Initialize a newly created instance to represent the
524 * SORT_MEMBERS_INVALID_FILE error condition.
525 */
526 Response.sortMembersInvalidFile(Request request)
527 : this(request.id,
528 error: new RequestError(RequestErrorCode.SORT_MEMBERS_INVALID_FILE,
529 'Error during `edit.sortMembers`: invalid file.'));
530
531 /**
532 * Initialize a newly created instance to represent the
533 * SORT_MEMBERS_PARSE_ERRORS error condition.
534 */
535 Response.sortMembersParseErrors(Request request, int numErrors)
536 : this(request.id,
537 error: new RequestError(RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS,
538 'Error during `edit.sortMembers`: file has $numErrors scan/parse errors.'));
539
540 /**
541 * Initialize a newly created instance to represent an error condition caused
542 * by a `analysis.setPriorityFiles` [request] that includes one or more files
543 * that are not being analyzed.
544 */
545 Response.unanalyzedPriorityFiles(String requestId, String fileNames)
546 : this(requestId,
547 error: new RequestError(RequestErrorCode.UNANALYZED_PRIORITY_FILES,
548 "Unanalyzed files cannot be a priority: '$fileNames'"));
549
550 /**
551 * Initialize a newly created instance to represent an error condition caused
552 * by a [request] that cannot be handled by any known handlers.
553 */
554 Response.unknownRequest(Request request)
555 : this(request.id,
556 error: new RequestError(
557 RequestErrorCode.UNKNOWN_REQUEST, 'Unknown request'));
558
559 /**
560 * Initialize a newly created instance to represent an error condition caused
561 * by a [request] referencing a source that does not exist.
562 */
563 Response.unknownSource(Request request)
564 : this(request.id,
565 error: new RequestError(
566 RequestErrorCode.UNKNOWN_SOURCE, 'Unknown source'));
567
568 /**
569 * Initialize a newly created instance to represent an error condition caused
570 * by a [request] for a service that is not supported.
571 */
572 Response.unsupportedFeature(String requestId, String message)
573 : this(requestId,
574 error: new RequestError(
575 RequestErrorCode.UNSUPPORTED_FEATURE, message));
576
577 /**
578 * Return a table mapping the names of result fields to their values. Should
579 * be `null` if there is no result to send.
580 */
581 Map<String, Object> get result => _result;
582
583 /**
584 * Return a table representing the structure of the Json object that will be
585 * sent to the client to represent this response.
586 */
587 Map<String, Object> toJson() {
588 Map<String, Object> jsonObject = new HashMap<String, Object>();
589 jsonObject[ID] = id;
590 if (error != null) {
591 jsonObject[ERROR] = error.toJson();
592 }
593 if (_result != null) {
594 jsonObject[RESULT] = _result;
595 }
596 return jsonObject;
597 }
598 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698