1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.chukwa.datacollection.agent.rest;
19
20 import org.apache.hadoop.chukwa.datacollection.agent.ChukwaAgent;
21 import org.apache.hadoop.chukwa.datacollection.adaptor.AdaptorException;
22 import org.apache.hadoop.chukwa.datacollection.adaptor.Adaptor;
23 import org.apache.hadoop.chukwa.datacollection.OffsetStatsManager;
24 import org.apache.hadoop.chukwa.util.ExceptionUtil;
25 import org.apache.commons.lang.StringEscapeUtils;
26 import org.json.JSONObject;
27 import org.json.JSONException;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import javax.ws.rs.Path;
32 import javax.ws.rs.GET;
33 import javax.ws.rs.Produces;
34 import javax.ws.rs.PathParam;
35 import javax.ws.rs.QueryParam;
36 import javax.ws.rs.DELETE;
37 import javax.ws.rs.POST;
38 import javax.ws.rs.Consumes;
39 import javax.ws.rs.core.Context;
40 import javax.ws.rs.core.Response;
41 import javax.ws.rs.core.MediaType;
42 import javax.servlet.ServletContext;
43 import javax.servlet.http.HttpServletResponse;
44 import java.text.DecimalFormat;
45 import java.util.Map;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 @Path("/adaptor")
73 public class AdaptorController {
74
75 private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat();
76 private static final Log log = LogFactory.getLog(AdaptorController.class);
77
78 static {
79 DECIMAL_FORMAT.setMinimumFractionDigits(2);
80 DECIMAL_FORMAT.setMaximumFractionDigits(2);
81 DECIMAL_FORMAT.setGroupingUsed(false);
82 }
83
84
85
86
87
88
89
90
91 @POST
92 @Consumes("application/json")
93 @Produces({"text/xml","text/plain"})
94 public Response addAdaptor(@Context ServletContext context,
95 @QueryParam("viewType") String viewType,
96 String postBody) {
97 ChukwaAgent agent = (ChukwaAgent)context.getAttribute("ChukwaAgent");
98
99 if (postBody == null) return badRequestResponse("Empty POST body.");
100
101
102 StringBuilder addCommand = new StringBuilder("add ");
103 try {
104 JSONObject reqJson = new JSONObject(postBody);
105
106 String dataType = reqJson.getString("DataType");
107
108
109 String adaptorClass = reqJson.getString("AdaptorClass");
110
111 String adaptorParams = fetchOptionalString(reqJson, "AdaptorParams");
112 long offset = fetchOptionalLong(reqJson, "Offset", 0);
113
114 addCommand.append(adaptorClass).append(' ');
115 addCommand.append(dataType);
116 if (adaptorParams != null)
117 addCommand.append(' ').append(adaptorParams);
118 addCommand.append(' ').append(offset);
119
120 } catch (JSONException e) {
121 return badRequestResponse("Invalid JSON passed: '" + postBody + "', error: " + e.getMessage());
122 }
123
124
125 try {
126 String adaptorId = agent.processAddCommandE(addCommand.toString());
127
128 return doGetAdaptor(agent, adaptorId, viewType);
129 } catch (AdaptorException e) {
130 return badRequestResponse("Could not add adaptor for postBody: '" + postBody +
131 "', error: " + e.getMessage());
132 }
133 }
134
135
136
137
138
139
140
141 @DELETE
142 @Path("/{adaptorId}")
143 @Produces({"text/plain"})
144 public Response removeAdaptor(@Context ServletContext context,
145 @PathParam("adaptorId") String adaptorId) {
146 ChukwaAgent agent = (ChukwaAgent)context.getAttribute("ChukwaAgent");
147
148
149 if (adaptorId == null) {
150 return badRequestResponse("Missing adaptorId.");
151 }
152
153
154 if (agent.getAdaptor(adaptorId) == null) {
155 return badRequestResponse("Invalid adaptorId: " + adaptorId);
156 }
157
158
159 agent.stopAdaptor(adaptorId, true);
160 return Response.ok().build();
161 }
162
163
164
165
166
167
168
169 @GET
170 @Produces({"text/xml", "text/plain"})
171 public Response getAdaptors(@Context ServletContext context,
172 @QueryParam("viewType") String viewType) {
173 ChukwaAgent agent = (ChukwaAgent)context.getAttribute("ChukwaAgent");
174 return doGetAdaptor(agent, null, viewType);
175 }
176
177
178
179
180
181
182
183
184 @GET
185 @Path("/{adaptorId}")
186 @Produces({"text/xml","text/plain"})
187 public Response getAdaptor(@Context ServletContext context,
188 @QueryParam("viewType") String viewType,
189 @PathParam("adaptorId") String adaptorId) {
190 ChukwaAgent agent = (ChukwaAgent)context.getAttribute("ChukwaAgent");
191 return doGetAdaptor(agent, adaptorId, viewType);
192 }
193
194
195
196
197
198
199 private Response doGetAdaptor(ChukwaAgent agent, String adaptorId, String viewType) {
200 if ("text".equals(viewType)) {
201 return textResponse(buildAdaptorText(agent, adaptorId));
202 }
203 else if ("xml".equals(viewType) || viewType == null) {
204 return xmlResponse(buildAdaptorXML(agent, adaptorId));
205 }
206 else {
207 return badRequestResponse("Invalid viewType: " + viewType);
208 }
209 }
210
211
212
213
214 protected String buildAdaptorXML(ChukwaAgent agent, String adaptorId) {
215
216 StringBuilder out = new StringBuilder(
217 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
218
219 appendStartTag(out, "Response");
220
221 if (adaptorId == null) {
222 Map<String, String> adaptorMap = agent.getAdaptorList();
223 appendStartTag(out, "Adaptors", "total", adaptorMap.size());
224
225 for (String name : adaptorMap.keySet()) {
226 Adaptor adaptor = agent.getAdaptor(name);
227 appendAdaptorXML(out, agent, adaptor);
228 }
229
230 appendEndTag(out, "Adaptors");
231 }
232 else {
233 Adaptor adaptor = agent.getAdaptor(adaptorId);
234 if (adaptor != null) {
235 appendAdaptorXML(out, agent, adaptor);
236 }
237 else {
238 appendElement(out, "Error", "Invalid adaptor id: " + adaptorId);
239 }
240 }
241
242 appendEndTag(out, "Response");
243
244 return out.toString();
245 }
246
247
248
249
250 protected String buildAdaptorText(ChukwaAgent agent, String adaptorId) {
251 StringBuilder out = new StringBuilder();
252
253 Map<String, String> adaptorMap = agent.getAdaptorList();
254 int indent = 0;
255
256 if (adaptorId == null) {
257 appendNvp(out, indent, "adaptor_count", adaptorMap.size());
258 appendNvp(out, indent, "adaptors", "");
259
260 indent += 4;
261 for(String name : adaptorMap.keySet()) {
262 Adaptor adaptor = agent.getAdaptor(name);
263 appendAdaptorText(out, indent, agent, adaptor);
264 }
265 }
266 else {
267 Adaptor adaptor = agent.getAdaptor(adaptorId);
268 if (adaptor != null) {
269 appendNvp(out, indent, "adaptor", "");
270 indent += 4;
271 appendAdaptorText(out, indent, agent, adaptor);
272 }
273 else {
274 appendNvp(out, indent, "error_message", "Invalid adaptor id: " + adaptorId, true);
275 }
276 }
277
278 return out.toString();
279 }
280
281 private void appendAdaptorText(StringBuilder out, int indent,
282 ChukwaAgent agent, Adaptor adaptor) {
283 appendNvp(out, indent, "- adaptor_id", agent.offset(adaptor).adaptorID());
284 appendNvp(out, indent, "data_type", adaptor.getType());
285 appendNvp(out, indent, "offset", agent.offset(adaptor).offset());
286 appendNvp(out, indent, "adaptor_class", adaptor.getClass().getName());
287 appendNvp(out, indent, "adaptor_params", adaptor.getCurrentStatus(), true);
288
289 OffsetStatsManager adaptorStats = agent.getAdaptorStatsManager();
290
291 appendNvp(out, indent, "average_rates", "");
292 indent += 4;
293 appendNvp(out, indent, "- rate",
294 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 60)));
295 appendNvp(out, indent, "interval", "60");
296 appendNvp(out, indent, "- rate",
297 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 300)));
298 appendNvp(out, indent, "interval", "300");
299 appendNvp(out, indent, "- rate",
300 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 600)));
301 appendNvp(out, indent, "interval", "600");
302 indent -= 4;
303 }
304
305 private void appendAdaptorXML(StringBuilder out,
306 ChukwaAgent agent, Adaptor adaptor) {
307 appendStartTag(out, "Adaptor",
308 "id", agent.offset(adaptor).adaptorID(),
309 "dataType", adaptor.getType(),
310 "offset", agent.offset(adaptor).offset());
311
312 appendElement(out, "AdaptorClass", adaptor.getClass().getName());
313 appendElement(out, "AdaptorParams", adaptor.getCurrentStatus());
314
315 OffsetStatsManager adaptorStats = agent.getAdaptorStatsManager();
316
317 appendElement(out, "AverageRate",
318 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 60)),
319 "intervalSeconds", "60");
320 appendElement(out, "AverageRate",
321 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 300)),
322 "intervalSeconds", "300");
323 appendElement(out, "AverageRate",
324 DECIMAL_FORMAT.format(adaptorStats.calcAverageRate(adaptor, 600)),
325 "intervalSeconds", "600");
326
327 appendEndTag(out, "Adaptor");
328 }
329
330
331
332
333
334 private static Response textResponse(Object content) {
335 return Response.ok(content, MediaType.TEXT_PLAIN).build();
336 }
337
338 private static Response xmlResponse(String content) {
339 return Response.ok(content, MediaType.TEXT_XML).build();
340 }
341
342 private static Response badRequestResponse(String content) {
343 return Response.status(HttpServletResponse.SC_BAD_REQUEST)
344 .entity(content).build();
345 }
346
347
348
349 private static String fetchOptionalString(JSONObject json, String name) {
350 try {
351 return json.getString(name);
352 } catch (JSONException e) {
353 log.debug(ExceptionUtil.getStackTrace(e));
354 }
355 return null;
356 }
357
358 private static long fetchOptionalLong(JSONObject json, String name, long defaultLong) {
359 try {
360 return json.getLong(name);
361 } catch (JSONException e) {
362 return defaultLong;
363 }
364 }
365
366
367
368
369
370
371
372 protected static void appendNvp(StringBuilder out,
373 String name, Object value) {
374 appendNvp(out, 0, name, value, false);
375 }
376
377
378
379
380
381 protected static void appendNvp(StringBuilder out, int indent,
382 String name, Object value) {
383 appendNvp(out, indent, name, value, false);
384 }
385
386
387
388
389
390
391 protected static void appendNvp(StringBuilder out, int indent,
392 String name, Object value,
393 boolean stringLiteral) {
394
395 if (name.startsWith("- ") && indent > 1) indent -= 2;
396
397 indent(out, indent);
398 out.append(name);
399 out.append(": ");
400
401 if (stringLiteral) {
402 out.append('|').append('\n');
403 indent(out, indent + 2);
404 }
405
406 if (value != null)
407 out.append(value.toString()).append('\n');
408 }
409
410
411
412
413 protected static void indent(StringBuilder out, int indent) {
414 for (int i = 0; i < indent; i++) {
415 out.append(' ');
416 }
417 }
418
419
420
421
422
423
424
425
426 protected static void appendStartTag(StringBuilder out,
427 String name,
428 Object... attributeNvps) {
429 out.append("<");
430 out.append(name);
431 for(int i = 0; i < attributeNvps.length - 1; i = i + 2) {
432 out.append(" ");
433 out.append(attributeNvps[i].toString());
434 out.append("=\"");
435 if (attributeNvps[i + 1] != null)
436 out.append(StringEscapeUtils.escapeXml(attributeNvps[i + 1].toString()));
437 out.append("\"");
438 }
439 out.append(">");
440 }
441
442
443
444
445 protected static void appendEndTag(StringBuilder out,
446 String name) {
447 out.append("</");
448 out.append(name);
449 out.append(">");
450 }
451
452
453
454
455
456
457 protected static void appendElement(StringBuilder out,
458 String name, Object value,
459 Object... attributeNvps) {
460 appendStartTag(out, name, attributeNvps);
461 if (value != null)
462 out.append(StringEscapeUtils.escapeXml(value.toString()));
463 appendEndTag(out, name);
464 }
465
466 }