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

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

Issue 137853026: Basic communication protocol for server (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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
(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 library protocol;
6
7 import 'dart:convert';
devoncarew 2014/01/20 22:35:01 Perhaps, import 'dart:convert' show JSON;
Brian Wilkerson 2014/01/21 03:21:20 Added 'show JsonDecoder' pending resolution of the
8
9 /**
10 * Instances of the class [Request] represent a request that was received.
11 */
12 class Request {
13 /**
14 * The name of the JSON attribute containing the id of the request.
15 */
16 static const String ID = 'id';
17
18 /**
19 * The name of the JSON attribute containing the name of the request.
20 */
21 static const String METHOD = 'method';
22
23 /**
24 * The name of the JSON attribute containing the request parameters.
25 */
26 static const String PARAMS = 'params';
27
28 /**
29 * The unique identifier used to identify this request.
30 */
31 final String id;
32
33 /**
34 * The method being requested.
35 */
36 final String method;
37
38 /**
39 * A table mapping the names of request parameters to their values.
40 */
41 final Map<String, Object> params = new Map<String, Object>();
42
43 /**
44 * A decoder that can be used to decode strings into JSON objects.
45 */
46 static const JsonDecoder DECODER = const JsonDecoder(null);
devoncarew 2014/01/20 22:35:01 You can delete this line.
Brian Wilkerson 2014/01/21 03:21:20 Only if I make the next change.
47
48 /**
49 * Initialize a newly created [Request] to have the given [id] and [method]
50 * name.
51 */
52 Request(this.id, this.method);
53
54 /**
55 * Return a request parsed from the given [data], or `null` if the [data] is
56 * not a valid json representation of a request. The [data] is expected to
57 * have the following format:
58 *
59 * {
60 * 'id': String,
61 * 'method': methodName,
62 * 'params': {
63 * paramter_name: value
64 * }
65 * }
66 *
67 * where the parameters are optional and can contain any number of name/value
68 * pairs.
69 */
70 factory Request.fromString(String data) {
71 try {
72 var result = DECODER.convert(data);
devoncarew 2014/01/20 22:35:01 ==> var result = JSON.decode(data);
Brian Wilkerson 2014/01/21 03:21:20 I considered this, but this method creates a new d
devoncarew 2014/01/21 04:16:08 Hmm, I was not aware that a new decoder is created
73 if (result is! Map) {
74 return null;
75 }
76 String id = result[Request.ID];
77 String method = result[Request.METHOD];
78 Map<String, Object> params = result[Request.PARAMS];
79 Request request = new Request(id, method);
80 params.forEach((String key, Object value) {
81 request.setParameter(key, value);
82 });
83 return request;
84 } catch (exception) {
85 return null;
86 }
87 }
88
89 /**
90 * Return the value of the parameter with the given [name], or `null` if there
91 * is no such parameter associated with this request.
92 */
93 Object getParameter(String name) => params[name];
94
95 /**
96 * Return the value of the parameter with the given [name], or throw a
97 * [RequestFailure] exception with an appropriate error message if there is no
98 * such parameter associated with this request.
99 */
100 Object getRequiredParameter(String name) {
101 Object value = params[name];
102 if (value == null) {
103 throw new RequestFailure(new Response.missingRequiredParameter(this, name) );
104 }
105 return value;
106 }
107
108 /**
109 * Set the value of the parameter with the given [name] to the given [value].
110 */
111 void setParameter(String name, Object value) {
112 params[name] = value;
113 }
114
115 /**
116 * Convert the given [value] to a boolean, or throw a [RequestFailure]
117 * exception if the [value] could not be converted.
118 *
119 * The value is typically the result of invoking either [getParameter] or
120 * [getRequiredParameter].
121 */
122 bool toBool(Object value) {
123 if (value is bool) {
124 return value;
125 } else if (value is String) {
126 return value == 'true';
127 }
128 throw new RequestFailure(new Response.expectedBoolean(this, value));
129 }
130
131 /**
132 * Convert the given [value] to an integer, or throw a [RequestFailure]
133 * exception if the [value] could not be converted.
134 *
135 * The value is typically the result of invoking either [getParameter] or
136 * [getRequiredParameter].
137 */
138 int toInt(Object value) {
139 if (value is int) {
140 return value;
141 } else if (value is String) {
142 return int.parse(value, onError: (String value) {
143 throw new RequestFailure(new Response.expectedInteger(this, value));
144 });
145 }
146 throw new RequestFailure(new Response.expectedInteger(this, value));
147 }
148 }
149
150 /**
151 * Instances of the class [Response] represent a response to a request.
152 */
153 class Response {
154 /**
155 * The name of the JSON attribute containing the id of the request for which
156 * this is a response.
157 */
158 static const String ID = 'id';
159
160 /**
161 * The name of the JSON attribute containing the error message.
162 */
163 static const String ERROR = 'error';
164
165 /**
166 * The name of the JSON attribute containing the result values.
167 */
168 static const String RESULT = 'result';
169
170 /**
171 * The unique identifier used to identify the request that this response is
172 * associated with.
173 */
174 final String id;
175
176 /**
177 * The error that was caused by attempting to handle the request, or `null` if
178 * there was no error.
179 */
180 final Object error;
181
182 /**
183 * A table mapping the names of result fields to their values. The table
184 * should be empty if there was an error.
185 */
186 final Map<String, Object> result = new Map<String, Object>();
187
188 /**
189 * Initialize a newly created instance to represent a response to a request
190 * with the given [id]. If an [error] is provided then the response will
191 * represent an error condition.
192 */
193 Response(this.id, [this.error]);
194
195 /**
196 * Initialize a newly created instance to represent an error condition caused
197 * by a [request] referencing a context that does not exist.
198 */
199 Response.contextDoesNotExist(Request request)
200 : this(request.id, 'Context does not exist');
201
202 /**
203 * Initialize a newly created instance to represent an error condition caused
204 * by a [request] that was expected to have a boolean-valued parameter but was
205 * passed a non-boolean value.
206 */
207 Response.expectedBoolean(Request request, String value)
208 : this(request.id, 'Expected a boolean value, but found "$value"');
209
210 /**
211 * Initialize a newly created instance to represent an error condition caused
212 * by a [request] that was expected to have a integer-valued parameter but was
213 * passed a non-integer value.
214 */
215 Response.expectedInteger(Request request, String value)
216 : this(request.id, 'Expected an integer value, but found "$value"');
217
218 /**
219 * Initialize a newly created instance to represent an error condition caused
220 * by a malformed request.
221 */
222 Response.invalidRequestFormat()
223 : this('', 'Invalid request');
224
225 /**
226 * Initialize a newly created instance to represent an error condition caused
227 * by a [request] that does not have a required parameter.
228 */
229 Response.missingRequiredParameter(Request request, String parameterName)
230 : this(request.id, 'Missing required parameter: $parameterName');
231
232 /**
233 * Initialize a newly created instance to represent an error condition caused
234 * by a [request] that takes a set of analysis options but for which an
235 * unknown analysis option was provided.
236 */
237 Response.unknownAnalysisOption(Request request, String optionName)
238 : this(request.id, 'Unknown analysis option: "$optionName"');
239
240 /**
241 * Initialize a newly created instance to represent an error condition caused
242 * by a [request] that cannot be handled by any known handlers.
243 */
244 Response.unknownRequest(Request request)
245 : this(request.id, 'Unknown request');
246
247 /**
248 * Return the value of the result field with the given [name].
249 */
250 Object getResult(String name) {
251 return result[name];
252 }
253
254 /**
255 * Set the value of the result field with the given [name] to the given [value ].
256 */
257 void setResult(String name, Object value) {
258 result[name] = value;
259 }
260
261 /**
262 * Return a table representing the structure of the Json object that will be
263 * sent to the client to represent this response.
264 */
265 Map<String, Object> toJson() {
devoncarew 2014/01/20 22:35:01 I have generally seen this as: Map<String, dynami
Brian Wilkerson 2014/01/21 03:21:20 The difference primarily has to do with warnings.
266 Map jsonObject = new Map();
267 jsonObject[ID] = id;
268 jsonObject[ERROR] = error;
269 if (!result.isEmpty) {
270 jsonObject[RESULT] = result;
271 }
272 return jsonObject;
273 }
274 }
275
276 /**
277 * Instances of the class [Notification] represent a notification from the
278 * server about an event that occurred.
279 */
280 class Notification {
281 /**
282 * The name of the JSON attribute containing the name of the event that
283 * triggered the notification.
284 */
285 static const String EVENT = 'event';
286
287 /**
288 * The name of the JSON attribute containing the result values.
289 */
290 static const String PARAMS = 'params';
291
292 /**
293 * The name of the event that triggered the notification.
294 */
295 final String event;
296
297 /**
298 * A table mapping the names of notification parameters to their values.
299 */
300 final Map<String, Object> params = new Map<String, Object>();
301
302 /**
303 * Initialize a newly created [Notification] to have the given [event] name.
304 */
305 Notification(this.event);
306
307 /**
308 * Return the value of the parameter with the given [name], or `null` if there
309 * is no such parameter associated with this notification.
310 */
311 Object getParameter(String name) => params[name];
312
313 /**
314 * Set the value of the parameter with the given [name] to the given [value].
315 */
316 void setParameter(String name, Object value) {
317 params[name] = value;
318 }
319
320 /**
321 * Return a table representing the structure of the Json object that will be
322 * sent to the client to represent this response.
323 */
324 Map<String, Object> toJson() {
325 Map jsonObject = new Map();
326 jsonObject[EVENT] = event;
327 if (!params.isEmpty) {
328 jsonObject[PARAMS] = params;
329 }
330 return jsonObject;
331 }
332 }
333
334 /**
335 * Instances of the class [RequestHandler] implement a handler that can handle
336 * requests and produce responses for them.
337 */
338 abstract class RequestHandler {
339 /**
340 * Attempt to handle the given [request]. If the request is not recognized by
341 * this handler, return `null` so that other handlers will be given a chance
342 * to handle it. Otherwise, return the response that should be passed back to
343 * the client.
344 */
345 Response handleRequest(Request request);
346 }
347
348 /**
349 * Instances of the class [RequestFailure] represent an exception that occurred
350 * during the handling of a request that requires that an error be returned to
351 * the client.
352 */
353 class RequestFailure implements Exception {
354 /**
355 * The response to be returned as a result of the failure.
356 */
357 final Response response;
358
359 /**
360 * Initialize a newly created exception to return the given reponse.
361 */
362 RequestFailure(this.response);
363 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698