1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.rest.client;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.net.URI;
27 import java.net.URISyntaxException;
28 import java.util.Collections;
29 import java.util.Map;
30 import java.util.concurrent.ConcurrentHashMap;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.hbase.classification.InterfaceStability;
36 import org.apache.http.Header;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.client.HttpClient;
39 import org.apache.http.client.methods.HttpDelete;
40 import org.apache.http.client.methods.HttpGet;
41 import org.apache.http.client.methods.HttpHead;
42 import org.apache.http.client.methods.HttpPost;
43 import org.apache.http.client.methods.HttpPut;
44 import org.apache.http.client.methods.HttpUriRequest;
45 import org.apache.http.entity.InputStreamEntity;
46 import org.apache.http.impl.client.DefaultHttpClient;
47 import org.apache.http.message.BasicHeader;
48 import org.apache.http.params.CoreConnectionPNames;
49 import org.apache.http.util.EntityUtils;
50
51
52
53
54
55 @InterfaceAudience.Public
56 @InterfaceStability.Stable
57 public class Client {
58 public static final Header[] EMPTY_HEADER_ARRAY = new Header[0];
59
60 private static final Log LOG = LogFactory.getLog(Client.class);
61
62 private HttpClient httpClient;
63 private Cluster cluster;
64 private boolean sslEnabled;
65 private HttpResponse resp;
66 private HttpGet httpGet = null;
67
68 private Map<String, String> extraHeaders;
69
70
71
72
73 public Client() {
74 this(null);
75 }
76
77 private void initialize(Cluster cluster, boolean sslEnabled) {
78 this.cluster = cluster;
79 this.sslEnabled = sslEnabled;
80 extraHeaders = new ConcurrentHashMap<String, String>();
81 String clspath = System.getProperty("java.class.path");
82 LOG.debug("classpath " + clspath);
83 this.httpClient = new DefaultHttpClient();
84 this.httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);
85 }
86
87
88
89
90 public Client(Cluster cluster) {
91 initialize(cluster, false);
92 }
93
94
95
96
97
98
99 public Client(Cluster cluster, boolean sslEnabled) {
100 initialize(cluster, sslEnabled);
101 }
102
103
104
105
106 public void shutdown() {
107 }
108
109
110
111
112 public HttpClient getHttpClient() {
113 return httpClient;
114 }
115
116
117
118
119
120
121 public void addExtraHeader(final String name, final String value) {
122 extraHeaders.put(name, value);
123 }
124
125
126
127
128 public String getExtraHeader(final String name) {
129 return extraHeaders.get(name);
130 }
131
132
133
134
135 public Map<String, String> getExtraHeaders() {
136 return Collections.unmodifiableMap(extraHeaders);
137 }
138
139
140
141
142 public void removeExtraHeader(final String name) {
143 extraHeaders.remove(name);
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public HttpResponse executePathOnly(Cluster cluster, HttpUriRequest method,
160 Header[] headers, String path) throws IOException {
161 IOException lastException;
162 if (cluster.nodes.size() < 1) {
163 throw new IOException("Cluster is empty");
164 }
165 int start = (int)Math.round((cluster.nodes.size() - 1) * Math.random());
166 int i = start;
167 do {
168 cluster.lastHost = cluster.nodes.get(i);
169 try {
170 StringBuilder sb = new StringBuilder();
171 if (sslEnabled) {
172 sb.append("https://");
173 } else {
174 sb.append("http://");
175 }
176 sb.append(cluster.lastHost);
177 sb.append(path);
178 URI uri = new URI(sb.toString());
179 if (method instanceof HttpPut) {
180 HttpPut put = new HttpPut(uri);
181 put.setEntity(((HttpPut) method).getEntity());
182 put.setHeaders(method.getAllHeaders());
183 method = put;
184 } else if (method instanceof HttpGet) {
185 method = new HttpGet(uri);
186 } else if (method instanceof HttpHead) {
187 method = new HttpHead(uri);
188 } else if (method instanceof HttpDelete) {
189 method = new HttpDelete(uri);
190 } else if (method instanceof HttpPost) {
191 HttpPost post = new HttpPost(uri);
192 post.setEntity(((HttpPost) method).getEntity());
193 post.setHeaders(method.getAllHeaders());
194 method = post;
195 }
196 return executeURI(method, headers, uri.toString());
197 } catch (IOException e) {
198 lastException = e;
199 } catch (URISyntaxException use) {
200 lastException = new IOException(use);
201 }
202 } while (++i != start && i < cluster.nodes.size());
203 throw lastException;
204 }
205
206
207
208
209
210
211
212
213
214 public HttpResponse executeURI(HttpUriRequest method, Header[] headers, String uri)
215 throws IOException {
216 for (Map.Entry<String, String> e: extraHeaders.entrySet()) {
217 method.addHeader(e.getKey(), e.getValue());
218 }
219 if (headers != null) {
220 for (Header header: headers) {
221 method.addHeader(header);
222 }
223 }
224 long startTime = System.currentTimeMillis();
225 if (resp != null) EntityUtils.consumeQuietly(resp.getEntity());
226 resp = httpClient.execute(method);
227 long endTime = System.currentTimeMillis();
228 if (LOG.isDebugEnabled()) {
229 LOG.debug(method.getMethod() + " " + uri + " " + resp.getStatusLine().getStatusCode() + " " +
230 resp.getStatusLine().getReasonPhrase() + " in " + (endTime - startTime) + " ms");
231 }
232 return resp;
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246 public HttpResponse execute(Cluster cluster, HttpUriRequest method, Header[] headers,
247 String path) throws IOException {
248 if (path.startsWith("/")) {
249 return executePathOnly(cluster, method, headers, path);
250 }
251 return executeURI(method, headers, path);
252 }
253
254
255
256
257 public Cluster getCluster() {
258 return cluster;
259 }
260
261
262
263
264 public void setCluster(Cluster cluster) {
265 this.cluster = cluster;
266 }
267
268
269
270
271
272
273
274 public Response head(String path) throws IOException {
275 return head(cluster, path, null);
276 }
277
278
279
280
281
282
283
284
285
286 public Response head(Cluster cluster, String path, Header[] headers)
287 throws IOException {
288 HttpHead method = new HttpHead(path);
289 try {
290 HttpResponse resp = execute(cluster, method, null, path);
291
292 return new Response(resp.getStatusLine().getStatusCode(), resp.getAllHeaders(), null);
293 } finally {
294 method.releaseConnection();
295 }
296 }
297
298
299
300
301
302
303
304 public Response get(String path) throws IOException {
305 return get(cluster, path);
306 }
307
308
309
310
311
312
313
314
315 public Response get(Cluster cluster, String path) throws IOException {
316 return get(cluster, path, EMPTY_HEADER_ARRAY);
317 }
318
319
320
321
322
323
324
325
326 public Response get(String path, String accept) throws IOException {
327 return get(cluster, path, accept);
328 }
329
330
331
332
333
334
335
336
337
338 public Response get(Cluster cluster, String path, String accept)
339 throws IOException {
340 Header[] headers = new Header[1];
341 headers[0] = new BasicHeader("Accept", accept);
342 return get(cluster, path, headers);
343 }
344
345
346
347
348
349
350
351
352
353 public Response get(String path, Header[] headers) throws IOException {
354 return get(cluster, path, headers);
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value =
372 "NP_LOAD_OF_KNOWN_NULL_VALUE", justification = "null is possible return value")
373 public static byte[] getResponseBody(HttpResponse resp) throws IOException {
374 if (resp.getEntity() == null) return null;
375 try (InputStream instream = resp.getEntity().getContent()) {
376 if (instream != null) {
377 long contentLength = resp.getEntity().getContentLength();
378 if (contentLength > Integer.MAX_VALUE) {
379
380 throw new IOException("Content too large to be buffered: " + contentLength +" bytes");
381 }
382 ByteArrayOutputStream outstream = new ByteArrayOutputStream(
383 contentLength > 0 ? (int) contentLength : 4*1024);
384 byte[] buffer = new byte[4096];
385 int len;
386 while ((len = instream.read(buffer)) > 0) {
387 outstream.write(buffer, 0, len);
388 }
389 outstream.close();
390 return outstream.toByteArray();
391 }
392 return null;
393 }
394 }
395
396
397
398
399
400
401
402
403
404 public Response get(Cluster c, String path, Header[] headers)
405 throws IOException {
406 if (httpGet != null) {
407 httpGet.releaseConnection();
408 }
409 httpGet = new HttpGet(path);
410 HttpResponse resp = execute(c, httpGet, headers, path);
411 return new Response(resp.getStatusLine().getStatusCode(), resp.getAllHeaders(),
412 resp, resp.getEntity() == null ? null : resp.getEntity().getContent());
413 }
414
415
416
417
418
419
420
421
422
423 public Response put(String path, String contentType, byte[] content)
424 throws IOException {
425 return put(cluster, path, contentType, content);
426 }
427
428
429
430
431
432
433
434
435
436
437 public Response put(String path, String contentType, byte[] content, Header extraHdr)
438 throws IOException {
439 return put(cluster, path, contentType, content, extraHdr);
440 }
441
442
443
444
445
446
447
448
449
450
451 public Response put(Cluster cluster, String path, String contentType,
452 byte[] content) throws IOException {
453 Header[] headers = new Header[1];
454 headers[0] = new BasicHeader("Content-Type", contentType);
455 return put(cluster, path, headers, content);
456 }
457
458
459
460
461
462
463
464
465
466
467
468 public Response put(Cluster cluster, String path, String contentType,
469 byte[] content, Header extraHdr) throws IOException {
470 int cnt = extraHdr == null ? 1 : 2;
471 Header[] headers = new Header[cnt];
472 headers[0] = new BasicHeader("Content-Type", contentType);
473 if (extraHdr != null) {
474 headers[1] = extraHdr;
475 }
476 return put(cluster, path, headers, content);
477 }
478
479
480
481
482
483
484
485
486
487
488 public Response put(String path, Header[] headers, byte[] content)
489 throws IOException {
490 return put(cluster, path, headers, content);
491 }
492
493
494
495
496
497
498
499
500
501
502
503 public Response put(Cluster cluster, String path, Header[] headers,
504 byte[] content) throws IOException {
505 HttpPut method = new HttpPut(path);
506 try {
507 method.setEntity(new InputStreamEntity(new ByteArrayInputStream(content), content.length));
508 HttpResponse resp = execute(cluster, method, headers, path);
509 headers = resp.getAllHeaders();
510 content = getResponseBody(resp);
511 return new Response(resp.getStatusLine().getStatusCode(), headers, content);
512 } finally {
513 method.releaseConnection();
514 }
515 }
516
517
518
519
520
521
522
523
524
525 public Response post(String path, String contentType, byte[] content)
526 throws IOException {
527 return post(cluster, path, contentType, content);
528 }
529
530
531
532
533
534
535
536
537
538
539 public Response post(String path, String contentType, byte[] content, Header extraHdr)
540 throws IOException {
541 return post(cluster, path, contentType, content, extraHdr);
542 }
543
544
545
546
547
548
549
550
551
552
553 public Response post(Cluster cluster, String path, String contentType,
554 byte[] content) throws IOException {
555 Header[] headers = new Header[1];
556 headers[0] = new BasicHeader("Content-Type", contentType);
557 return post(cluster, path, headers, content);
558 }
559
560
561
562
563
564
565
566
567
568
569
570 public Response post(Cluster cluster, String path, String contentType,
571 byte[] content, Header extraHdr) throws IOException {
572 int cnt = extraHdr == null ? 1 : 2;
573 Header[] headers = new Header[cnt];
574 headers[0] = new BasicHeader("Content-Type", contentType);
575 if (extraHdr != null) {
576 headers[1] = extraHdr;
577 }
578 return post(cluster, path, headers, content);
579 }
580
581
582
583
584
585
586
587
588
589
590 public Response post(String path, Header[] headers, byte[] content)
591 throws IOException {
592 return post(cluster, path, headers, content);
593 }
594
595
596
597
598
599
600
601
602
603
604
605 public Response post(Cluster cluster, String path, Header[] headers,
606 byte[] content) throws IOException {
607 HttpPost method = new HttpPost(path);
608 try {
609 method.setEntity(new InputStreamEntity(new ByteArrayInputStream(content), content.length));
610 HttpResponse resp = execute(cluster, method, headers, path);
611 headers = resp.getAllHeaders();
612 content = getResponseBody(resp);
613 return new Response(resp.getStatusLine().getStatusCode(), headers, content);
614 } finally {
615 method.releaseConnection();
616 }
617 }
618
619
620
621
622
623
624
625 public Response delete(String path) throws IOException {
626 return delete(cluster, path);
627 }
628
629
630
631
632
633
634
635
636 public Response delete(String path, Header extraHdr) throws IOException {
637 return delete(cluster, path, extraHdr);
638 }
639
640
641
642
643
644
645
646
647 public Response delete(Cluster cluster, String path) throws IOException {
648 HttpDelete method = new HttpDelete(path);
649 try {
650 HttpResponse resp = execute(cluster, method, null, path);
651 Header[] headers = resp.getAllHeaders();
652 byte[] content = getResponseBody(resp);
653 return new Response(resp.getStatusLine().getStatusCode(), headers, content);
654 } finally {
655 method.releaseConnection();
656 }
657 }
658
659
660
661
662
663
664
665
666 public Response delete(Cluster cluster, String path, Header extraHdr) throws IOException {
667 HttpDelete method = new HttpDelete(path);
668 try {
669 Header[] headers = { extraHdr };
670 HttpResponse resp = execute(cluster, method, headers, path);
671 headers = resp.getAllHeaders();
672 byte[] content = getResponseBody(resp);
673 return new Response(resp.getStatusLine().getStatusCode(), headers, content);
674 } finally {
675 method.releaseConnection();
676 }
677 }
678 }