1 package com.guinetik.rr;
2
3 import com.guinetik.rr.api.AsyncApiClient;
4 import com.guinetik.rr.api.DefaultApiClient;
5 import com.guinetik.rr.api.FluentApiClient;
6 import com.guinetik.rr.auth.AbstractOAuth2Strategy;
7 import com.guinetik.rr.request.RequestBuilder;
8 import com.guinetik.rr.request.RequestSpec;
9 import com.guinetik.rr.result.ApiError;
10 import com.guinetik.rr.result.Result;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13
14 import java.util.Date;
15 import java.util.Map;
16 import java.util.concurrent.CompletableFuture;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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
73
74
75
76
77 public class RocketRest {
78
79 protected final Logger logger = LoggerFactory.getLogger(this.getClass());
80
81 private final RocketRestOptions options;
82 private final DefaultApiClient syncClient;
83 private final AsyncApiClient asyncClient;
84 private final FluentApiClient fluentClient;
85
86
87
88
89 public interface SyncApi {
90 <T> T get(String endpoint, Class<T> responseType);
91 <T> T get(String endpoint, Class<T> responseType, Map<String, String> queryParams);
92 <Res> Res post(String endpoint, Class<Res> responseType);
93 <Req, Res> Res post(String endpoint, Req body, Class<Res> responseType);
94 <Res> Res put(String endpoint, Class<Res> responseType);
95 <Req, Res> Res put(String endpoint, Req body, Class<Res> responseType);
96 <T> T delete(String endpoint, Class<T> responseType);
97 <Req, Res> Res execute(RequestSpec<Req, Res> requestSpec);
98 }
99
100
101
102
103 public interface AsyncApi {
104 <T> CompletableFuture<T> get(String endpoint, Class<T> responseType);
105 <T> CompletableFuture<T> get(String endpoint, Class<T> responseType, Map<String, String> queryParams);
106 <Res> CompletableFuture<Res> post(String endpoint, Class<Res> responseType);
107 <Req, Res> CompletableFuture<Res> post(String endpoint, Req body, Class<Res> responseType);
108 <Res> CompletableFuture<Res> put(String endpoint, Class<Res> responseType);
109 <Req, Res> CompletableFuture<Res> put(String endpoint, Req body, Class<Res> responseType);
110 <T> CompletableFuture<T> delete(String endpoint, Class<T> responseType);
111 <Req, Res> CompletableFuture<Res> execute(RequestSpec<Req, Res> requestSpec);
112 void shutdown();
113 }
114
115
116
117
118 public interface FluentApi {
119 <T> Result<T, ApiError> get(String endpoint, Class<T> responseType);
120 <T> Result<T, ApiError> get(String endpoint, Class<T> responseType, Map<String, String> queryParams);
121 <Res> Result<Res, ApiError> post(String endpoint, Class<Res> responseType);
122 <Req, Res> Result<Res, ApiError> post(String endpoint, Req body, Class<Res> responseType);
123 <Res> Result<Res, ApiError> put(String endpoint, Class<Res> responseType);
124 <Req, Res> Result<Res, ApiError> put(String endpoint, Req body, Class<Res> responseType);
125 <T> Result<T, ApiError> delete(String endpoint, Class<T> responseType);
126 <Req, Res> Result<Res, ApiError> execute(RequestSpec<Req, Res> requestSpec);
127 }
128
129 private RocketRestConfig config;
130
131
132
133
134
135
136 public RocketRest(RocketRestConfig config) {
137 this(config.getServiceUrl(), config);
138 }
139
140
141
142
143
144
145
146 public RocketRest(String baseUrl, RocketRestConfig config) {
147
148 this.config = config;
149 if (this.config != null && this.config.getDefaultOptions() != null) {
150 this.options = new RocketRestOptions();
151 RocketRestOptions defaultOptions = this.config.getDefaultOptions();
152
153
154 for (String key : defaultOptions.getKeys()) {
155 Object value = defaultOptions.getRaw(key);
156 if (value != null) {
157 this.options.set(key, value);
158 }
159 }
160 } else {
161 this.options = new RocketRestOptions();
162 }
163
164
165 this.syncClient = new DefaultApiClient(baseUrl, this.config);
166
167
168 int poolSize = options.getInt(RocketRestOptions.ASYNC_POOL_SIZE, 4);
169 ExecutorService asyncExecutor = Executors.newFixedThreadPool(poolSize);
170 this.asyncClient = new AsyncApiClient(baseUrl, this.config, asyncExecutor);
171
172
173 this.fluentClient = new FluentApiClient(baseUrl, this.config);
174
175 logger.info("Initialized RocketRest with base URL: {} and async pool size: {}", baseUrl, poolSize);
176 }
177
178
179
180
181
182
183
184
185
186 public <T> T get(String endpoint, Class<T> responseType) {
187 return sync().get(endpoint, responseType);
188 }
189
190
191
192
193
194
195
196
197
198
199 public <T> T get(String endpoint, Class<T> responseType, Map<String, String> queryParams) {
200 return sync().get(endpoint, responseType, queryParams);
201 }
202
203
204
205
206
207
208
209
210
211 public <Res> Res post(String endpoint, Class<Res> responseType) {
212 return sync().post(endpoint, responseType);
213 }
214
215
216
217
218
219
220
221
222
223
224
225 public <Req, Res> Res post(String endpoint, Req body, Class<Res> responseType) {
226 return sync().post(endpoint, body, responseType);
227 }
228
229
230
231
232
233
234
235
236
237 public <Res> Res put(String endpoint, Class<Res> responseType) {
238 return sync().put(endpoint, responseType);
239 }
240
241
242
243
244
245
246
247
248
249
250
251 public <Req, Res> Res put(String endpoint, Req body, Class<Res> responseType) {
252 return sync().put(endpoint, body, responseType);
253 }
254
255
256
257
258
259
260
261
262
263 public <T> T delete(String endpoint, Class<T> responseType) {
264 return sync().delete(endpoint, responseType);
265 }
266
267
268
269
270
271
272
273
274
275 public <Req, Res> Res execute(RequestSpec<Req, Res> requestSpec) {
276 return sync().execute(requestSpec);
277 }
278
279
280
281
282
283
284 public SyncApi sync() {
285 return new SyncApiImpl();
286 }
287
288
289
290
291
292
293 public AsyncApi async() {
294 return new AsyncApiImpl();
295 }
296
297
298
299
300
301
302 public FluentApi fluent() {
303 return new FluentApiImpl();
304 }
305
306
307
308
309
310
311
312
313 public RocketRest configure(String key, Object value) {
314 options.set(key, value);
315
316
317 syncClient.configure(key, value);
318 asyncClient.configure(key, value);
319 fluentClient.configure(key, value);
320
321
322 if (RocketRestOptions.ASYNC_POOL_SIZE.equals(key) && value instanceof Integer) {
323 logger.info("Note: Changing ASYNC_POOL_SIZE after initialization is not supported");
324 }
325
326 return this;
327 }
328
329
330
331
332 public void shutdown() {
333 asyncClient.shutdown();
334 logger.info("RocketRest shutdown completed.");
335 }
336
337
338
339
340
341
342
343
344
345
346
347 private <T> RequestSpec<Void, T> createGetRequest(String endpoint, Class<T> responseType) {
348 logger.debug("Creating GET request to endpoint: {}", endpoint);
349 return new RequestBuilder<Void, T>()
350 .endpoint(endpoint)
351 .method("GET")
352 .responseType(responseType)
353 .build();
354 }
355
356
357
358
359
360
361
362
363
364
365 private <T> RequestSpec<Void, T> createGetRequest(String endpoint, Class<T> responseType, Map<String, String> queryParams) {
366 logger.debug("Creating GET request to endpoint: {} with params: {}", endpoint, queryParams);
367 return new RequestBuilder<Void, T>()
368 .endpoint(endpoint)
369 .method("GET")
370 .queryParams(queryParams)
371 .responseType(responseType)
372 .build();
373 }
374
375
376
377
378
379
380
381
382
383 private <Res> RequestSpec<Void, Res> createPostRequest(String endpoint, Class<Res> responseType) {
384 logger.debug("Creating POST request to endpoint: {}", endpoint);
385 return new RequestBuilder<Void, Res>()
386 .endpoint(endpoint)
387 .method("POST")
388 .responseType(responseType)
389 .build();
390 }
391
392
393
394
395
396
397
398
399
400
401
402 private <Req, Res> RequestSpec<Req, Res> createPostRequest(String endpoint, Req body, Class<Res> responseType) {
403 logger.debug("Creating POST request to endpoint: {} with body", endpoint);
404 return new RequestBuilder<Req, Res>()
405 .endpoint(endpoint)
406 .method("POST")
407 .body(body)
408 .responseType(responseType)
409 .build();
410 }
411
412
413
414
415
416
417
418
419
420 private <Res> RequestSpec<Void, Res> createPutRequest(String endpoint, Class<Res> responseType) {
421 logger.debug("Creating PUT request to endpoint: {}", endpoint);
422 return new RequestBuilder<Void, Res>()
423 .endpoint(endpoint)
424 .method("PUT")
425 .responseType(responseType)
426 .build();
427 }
428
429
430
431
432
433
434
435
436
437
438
439 private <Req, Res> RequestSpec<Req, Res> createPutRequest(String endpoint, Req body, Class<Res> responseType) {
440 logger.debug("Creating PUT request to endpoint: {} with body", endpoint);
441 return new RequestBuilder<Req, Res>()
442 .endpoint(endpoint)
443 .method("PUT")
444 .body(body)
445 .responseType(responseType)
446 .build();
447 }
448
449
450
451
452
453
454
455
456
457 private <T> RequestSpec<Void, T> createDeleteRequest(String endpoint, Class<T> responseType) {
458 logger.debug("Creating DELETE request to endpoint: {}", endpoint);
459 return new RequestBuilder<Void, T>()
460 .endpoint(endpoint)
461 .method("DELETE")
462 .responseType(responseType)
463 .build();
464 }
465
466
467
468
469
470
471 private class SyncApiImpl implements SyncApi {
472 @Override
473 public <T> T get(String endpoint, Class<T> responseType) {
474 return syncClient.execute(createGetRequest(endpoint, responseType));
475 }
476
477 @Override
478 public <T> T get(String endpoint, Class<T> responseType, Map<String, String> queryParams) {
479 return syncClient.execute(createGetRequest(endpoint, responseType, queryParams));
480 }
481
482 @Override
483 public <Res> Res post(String endpoint, Class<Res> responseType) {
484 return syncClient.execute(createPostRequest(endpoint, responseType));
485 }
486
487 @Override
488 public <Req, Res> Res post(String endpoint, Req body, Class<Res> responseType) {
489 return syncClient.execute(createPostRequest(endpoint, body, responseType));
490 }
491
492 @Override
493 public <Res> Res put(String endpoint, Class<Res> responseType) {
494 return syncClient.execute(createPutRequest(endpoint, responseType));
495 }
496
497 @Override
498 public <Req, Res> Res put(String endpoint, Req body, Class<Res> responseType) {
499 return syncClient.execute(createPutRequest(endpoint, body, responseType));
500 }
501
502 @Override
503 public <T> T delete(String endpoint, Class<T> responseType) {
504 return syncClient.execute(createDeleteRequest(endpoint, responseType));
505 }
506
507 @Override
508 public <Req, Res> Res execute(RequestSpec<Req, Res> requestSpec) {
509 return syncClient.execute(requestSpec);
510 }
511 }
512
513
514
515
516 private class AsyncApiImpl implements AsyncApi {
517 @Override
518 public <T> CompletableFuture<T> get(String endpoint, Class<T> responseType) {
519 return asyncClient.executeAsync(createGetRequest(endpoint, responseType));
520 }
521
522 @Override
523 public <T> CompletableFuture<T> get(String endpoint, Class<T> responseType, Map<String, String> queryParams) {
524 return asyncClient.executeAsync(createGetRequest(endpoint, responseType, queryParams));
525 }
526
527 @Override
528 public <Res> CompletableFuture<Res> post(String endpoint, Class<Res> responseType) {
529 return asyncClient.executeAsync(createPostRequest(endpoint, responseType));
530 }
531
532 @Override
533 public <Req, Res> CompletableFuture<Res> post(String endpoint, Req body, Class<Res> responseType) {
534 return asyncClient.executeAsync(createPostRequest(endpoint, body, responseType));
535 }
536
537 @Override
538 public <Res> CompletableFuture<Res> put(String endpoint, Class<Res> responseType) {
539 return asyncClient.executeAsync(createPutRequest(endpoint, responseType));
540 }
541
542 @Override
543 public <Req, Res> CompletableFuture<Res> put(String endpoint, Req body, Class<Res> responseType) {
544 return asyncClient.executeAsync(createPutRequest(endpoint, body, responseType));
545 }
546
547 @Override
548 public <T> CompletableFuture<T> delete(String endpoint, Class<T> responseType) {
549 return asyncClient.executeAsync(createDeleteRequest(endpoint, responseType));
550 }
551
552 @Override
553 public <Req, Res> CompletableFuture<Res> execute(RequestSpec<Req, Res> requestSpec) {
554 return asyncClient.executeAsync(requestSpec);
555 }
556
557 @Override
558 public void shutdown() {
559 asyncClient.shutdown();
560 }
561 }
562
563
564
565
566 private class FluentApiImpl implements FluentApi {
567 @Override
568 public <T> Result<T, ApiError> get(String endpoint, Class<T> responseType) {
569 return fluentClient.executeWithResult(createGetRequest(endpoint, responseType));
570 }
571
572 @Override
573 public <T> Result<T, ApiError> get(String endpoint, Class<T> responseType, Map<String, String> queryParams) {
574 return fluentClient.executeWithResult(createGetRequest(endpoint, responseType, queryParams));
575 }
576
577 @Override
578 public <Res> Result<Res, ApiError> post(String endpoint, Class<Res> responseType) {
579 return fluentClient.executeWithResult(createPostRequest(endpoint, responseType));
580 }
581
582 @Override
583 public <Req, Res> Result<Res, ApiError> post(String endpoint, Req body, Class<Res> responseType) {
584 return fluentClient.executeWithResult(createPostRequest(endpoint, body, responseType));
585 }
586
587 @Override
588 public <Res> Result<Res, ApiError> put(String endpoint, Class<Res> responseType) {
589 return fluentClient.executeWithResult(createPutRequest(endpoint, responseType));
590 }
591
592 @Override
593 public <Req, Res> Result<Res, ApiError> put(String endpoint, Req body, Class<Res> responseType) {
594 return fluentClient.executeWithResult(createPutRequest(endpoint, body, responseType));
595 }
596
597 @Override
598 public <T> Result<T, ApiError> delete(String endpoint, Class<T> responseType) {
599 return fluentClient.executeWithResult(createDeleteRequest(endpoint, responseType));
600 }
601
602 @Override
603 public <Req, Res> Result<Res, ApiError> execute(RequestSpec<Req, Res> requestSpec) {
604 return fluentClient.<Req, Res>executeWithResult(requestSpec);
605 }
606 }
607
608 public void setBaseUrl(String baseUrl) {
609 this.syncClient.setBaseUrl(baseUrl);
610 this.asyncClient.setBaseUrl(baseUrl);
611 this.fluentClient.setBaseUrl(baseUrl);
612 }
613
614 public String getAccessToken() {
615 if(this.config.getAuthStrategy() instanceof AbstractOAuth2Strategy) {
616 AbstractOAuth2Strategy strat = (AbstractOAuth2Strategy) this.config.getAuthStrategy();
617 return strat.getAccessToken();
618 }
619 return null;
620 }
621
622 public Date getTokenExpiryTime() {
623 if(this.config.getAuthStrategy() instanceof AbstractOAuth2Strategy) {
624 AbstractOAuth2Strategy strat = (AbstractOAuth2Strategy) this.config.getAuthStrategy();
625 return strat.getTokenExpiryTime();
626 }
627 return null;
628 }
629 }