2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6 * ===========================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END====================================================
22 package org.onap.aaf.cadi.client;
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.io.PrintStream;
28 import java.util.Enumeration;
30 import javax.servlet.ServletInputStream;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
34 import org.onap.aaf.cadi.CadiException;
35 import org.onap.aaf.cadi.SecuritySetter;
36 import org.onap.aaf.cadi.client.EClient.Transfer;
37 import org.onap.aaf.misc.env.APIException;
38 import org.onap.aaf.misc.env.Data.TYPE;
39 import org.onap.aaf.misc.env.util.Pool;
40 import org.onap.aaf.misc.env.util.Pool.Pooled;
41 import org.onap.aaf.misc.rosetta.env.RosettaDF;
43 public abstract class Rcli<CT> {
44 public static final String FORM_ENCODED = "application/x-www-form-urlencoded";
45 public static final String APPL_JSON = "application/json";
46 public static final String APPL_XML = "application/xml";
47 public static final String BLANK = "";
48 public static final String CONTENT_TYPE = "Content-Type";
49 public static final String ACCEPT = "Accept";
51 protected static final String POST = "POST";
52 protected static final String GET = "GET";
53 protected static final String PUT = "PUT";
54 protected static final String DELETE = "DELETE";
56 protected String apiVersion;
57 protected int readTimeout = 5000;
58 protected int connectionTimeout = 3000;
60 private String queryParams, fragment;
61 public static Pool<byte[]> buffPool = new Pool<byte[]>(new Pool.Creator<byte[]>() {
63 public byte[] create() throws APIException {
64 return new byte[1024];
68 public void destroy(byte[] t) {
72 public boolean isValid(byte[] t) {
77 public void reuse(byte[] t) {
86 public abstract void setSecuritySetter(SecuritySetter<CT> ss);
87 public abstract SecuritySetter<CT> getSecuritySetter();
90 public Rcli<CT> forUser(SecuritySetter<CT> ss) {
91 Rcli<CT> rv = clone(uri==null?this.uri:uri,ss);
92 setSecuritySetter(ss);
94 rv.apiVersion = apiVersion;
98 protected abstract Rcli<CT> clone(URI uri, SecuritySetter<CT> ss);
100 public abstract void invalidate() throws CadiException;
102 public Rcli<CT> readTimeout(int millis) {
103 readTimeout = millis;
107 public Rcli<CT> connectionTimeout(int millis) {
108 connectionTimeout = millis;
112 public Rcli<CT> type(TYPE type) {
117 public Rcli<CT> apiVersion(String apiVersion) {
118 this.apiVersion = apiVersion;
122 public boolean isApiVersion(String prospective) {
123 return apiVersion.equals(prospective);
127 public String typeString(Class<?> cls) {
128 return "application/"+cls.getSimpleName()+"+"+type.name().toLowerCase()+
129 (apiVersion==null?BLANK:";version="+apiVersion);
132 protected abstract EClient<CT> client() throws CadiException;
135 public<T> Future<T> create(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
136 final String qp = setupParams(pathinfo);
138 EClient<CT> client = client();
139 client.setMethod(POST);
140 client.addHeader(CONTENT_TYPE,contentType);
141 client.setPathInfo(pathinfo);
142 client.setQueryParams(qp);
143 client.setFragment(fragment);
144 client.setPayload(new EClient.Transfer() {
146 public void transfer(OutputStream os) throws IOException, APIException {
147 df.newData().out(type).direct(t,os);
151 queryParams = fragment = null;
152 return client.futureCreate(df.getTypeClass());
155 public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
156 final String qp = setupParams(pathinfo);
158 EClient<CT> client = client();
159 client.setMethod(POST);
160 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
161 client.setPathInfo(pathinfo);
162 client.setQueryParams(qp);
163 client.setFragment(fragment);
164 client.setPayload(new EClient.Transfer() {
166 public void transfer(OutputStream os) throws IOException, APIException {
167 df.newData().out(type).direct(t,os);
171 queryParams = fragment = null;
172 return client.futureCreate(df.getTypeClass());
175 public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
176 final String qp = setupParams(pathinfo);
178 EClient<CT> client = client();
179 client.setMethod(POST);
180 client.addHeader(CONTENT_TYPE,typeString(cls));
181 client.setPathInfo(pathinfo);
182 client.setQueryParams(qp);
183 client.setFragment(fragment);
184 client.setPayload(new EClient.Transfer() {
186 public void transfer(OutputStream os) throws IOException, APIException {
187 df.newData().out(type).direct(t,os);
191 queryParams = fragment = null;
192 return client.futureCreate(df.getTypeClass());
195 public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
196 final String qp = setupParams(pathinfo);
198 EClient<CT> client = client();
199 client.setMethod(POST);
200 client.addHeader(CONTENT_TYPE,typeString(cls));
201 client.setPathInfo(pathinfo);
202 client.setQueryParams(qp);
203 client.setFragment(fragment);
204 client.setPayload(null);
206 queryParams = fragment = null;
207 return client.futureCreate(cls);
210 public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
211 final String qp = setupParams(pathinfo);
213 EClient<CT> client = client();
214 client.setMethod(POST);
215 client.addHeader(CONTENT_TYPE,contentType);
216 client.setPathInfo(pathinfo);
217 client.setQueryParams(qp);
218 client.setFragment(fragment);
219 client.setPayload(null);
221 queryParams = fragment = null;
222 return client.futureCreate(Void.class);
227 * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
229 * Because typically, you will want to have a variable as value, you can type, as long as tag ends with "="
230 * postForm(..., "tag1=value1","tag2=",var2);
236 * @throws APIException
237 * @throws CadiException
239 public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
240 final String qp = setupParams(pathinfo);
242 EClient<CT> client = client();
243 client.setMethod(POST);
244 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
247 client.addHeader(ACCEPT, APPL_JSON);
250 client.addHeader(ACCEPT, APPL_XML);
255 client.setPathInfo(pathinfo);
256 client.setQueryParams(qp);
257 client.setFragment(fragment);
258 client.setPayload(new Transfer() {
260 public void transfer(OutputStream os) throws IOException, APIException {
262 if(os instanceof PrintStream) {
263 ps = (PrintStream)os;
265 ps = new PrintStream(os);
267 boolean first = true;
268 for(String fp : formParam) {
275 if(fp.endsWith("=")) {
283 queryParams = fragment = null;
284 return client.futureRead(df,TYPE.JSON);
288 * Read String, using POST for keyInfo
295 * @throws APIException
296 * @throws CadiException
298 public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
299 final String qp = setupParams(pathinfo);
301 EClient<CT> client = client();
302 client.setMethod(POST);
303 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
304 client.setPathInfo(pathinfo);
305 client.setQueryParams(qp);
306 client.setFragment(fragment);
307 client.setPayload(new EClient.Transfer() {
309 public void transfer(OutputStream os) throws IOException, APIException {
310 df.newData().out(type).direct(t,os);
314 queryParams = fragment = null;
315 return client.futureReadString();
319 * Read using POST for keyInfo, responding with marshaled Objects
326 * @throws APIException
327 * @throws CadiException
329 public<T,R> Future<R> readPost(String pathinfo, final RosettaDF<T> df, final T t, final RosettaDF<R> resp) throws APIException, CadiException {
330 final String qp = setupParams(pathinfo);
332 EClient<CT> client = client();
333 client.setMethod(POST);
334 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
335 client.setPathInfo(pathinfo);
336 client.setQueryParams(qp);
337 client.setFragment(fragment);
338 client.setPayload(new EClient.Transfer() {
340 public void transfer(OutputStream os) throws IOException, APIException {
341 df.newData().out(type).direct(t,os);
345 queryParams = fragment = null;
346 return client.futureRead(resp,resp.getOutType());
349 public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
350 final String qp = setupParams(pathinfo);
352 EClient<CT> client = client();
353 client.setMethod(POST);
354 client.addHeader(CONTENT_TYPE,contentType);
355 client.setPathInfo(pathinfo);
356 client.setQueryParams(qp);
357 client.setFragment(fragment);
358 client.setPayload(new EClient.Transfer() {
360 public void transfer(OutputStream os) throws IOException, APIException {
363 queryParams = fragment = null;
364 return client.futureReadString();
367 public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
368 final String qp = setupParams(pathinfo);
370 EClient<CT> client = client();
371 client.setMethod(GET);
372 client.addHeader(ACCEPT, accept);
374 for(int i=1;i<headers.length;i=i+2) {
375 client.addHeader(headers[i-1],headers[i]);
377 client.setQueryParams(qp);
378 client.setFragment(fragment);
380 client.setPathInfo(pathinfo);
382 client.setPayload(null);
384 queryParams = fragment = null;
385 return client.futureReadString();
388 public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
389 final String qp = setupParams(pathinfo);
391 EClient<CT> client = client();
392 client.setMethod(GET);
393 client.addHeader(ACCEPT, accept);
394 for(int i=1;i<headers.length;i=i+2) {
395 client.addHeader(headers[i-1],headers[i]);
397 client.setQueryParams(qp);
398 client.setFragment(fragment);
399 client.setPathInfo(pathinfo);
401 client.setPayload(null);
403 queryParams = fragment = null;
404 return client.futureRead(df,type);
407 public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
408 final String qp = setupParams(pathinfo);
410 EClient<CT> client = client();
411 client.setMethod(GET);
412 client.addHeader(ACCEPT, typeString(df.getTypeClass()));
413 for(int i=1;i<headers.length;i=i+2) {
414 client.addHeader(headers[i-1],headers[i]);
416 client.setQueryParams(qp);
417 client.setFragment(fragment);
418 client.setPathInfo(pathinfo);
420 client.setPayload(null);
422 queryParams = fragment = null;
423 return client.futureRead(df,type);
426 public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
427 final String qp = setupParams(pathinfo);
429 EClient<CT> client = client();
430 client.setMethod(GET);
431 client.addHeader(ACCEPT, typeString(cls));
432 client.setQueryParams(qp);
433 client.setFragment(fragment);
434 client.setPathInfo(pathinfo);
436 client.setPayload(null);
438 queryParams = fragment = null;
439 return client.futureRead(df,type);
442 public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
443 final String qp = setupParams(pathinfo);
445 EClient<CT> client = client();
446 client.setMethod(PUT);
447 client.addHeader(CONTENT_TYPE,contentType);
448 client.setQueryParams(qp);
449 client.setFragment(fragment);
450 client.setPathInfo(pathinfo);
451 client.setPayload(new EClient.Transfer() {
453 public void transfer(OutputStream os) throws IOException, APIException {
454 df.newData().out(type).direct(t,os);
458 queryParams = fragment = null;
459 return client.future(t);
462 public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
463 final String qp = setupParams(pathinfo);
465 EClient<CT> client = client();
466 client.setMethod(PUT);
467 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
468 client.setQueryParams(qp);
469 client.setFragment(fragment);
470 client.setPathInfo(pathinfo);
471 client.setPayload(new EClient.Transfer() {
473 public void transfer(OutputStream os) throws IOException, APIException {
474 df.newData().out(type).direct(t,os);
478 queryParams = fragment = null;
479 return client.futureReadString();
483 public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
484 final String qp = setupParams(pathinfo);
486 EClient<CT> client = client();
487 client.setMethod(PUT);
488 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
489 client.setQueryParams(qp);
490 client.setFragment(fragment);
491 client.setPathInfo(pathinfo);
492 client.setPayload(new EClient.Transfer() {
494 public void transfer(OutputStream os) throws IOException, APIException {
495 df.newData().out(type).direct(t,os);
499 queryParams = fragment = null;
500 return client.future(t);
503 public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
504 final String qp = setupParams(pathinfo);
506 EClient<CT> client = client();
507 client.setMethod(PUT);
508 client.addHeader(CONTENT_TYPE, typeString(cls));
509 client.setQueryParams(qp);
510 client.setFragment(fragment);
511 client.setPathInfo(pathinfo);
512 client.setPayload(new EClient.Transfer() {
514 public void transfer(OutputStream os) throws IOException, APIException {
515 df.newData().out(type).direct(t,os);
519 queryParams = fragment = null;
520 return client.future(t);
524 * A method to update with a VOID
529 * @throws APIException
530 * @throws CadiException
532 public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
533 final String qp = setupParams(pathinfo);
535 EClient<CT> client = client();
536 client.setMethod(PUT);
537 client.addHeader(CONTENT_TYPE, typeString(Void.class));
538 client.setQueryParams(qp);
539 client.setFragment(fragment);
540 client.setPathInfo(pathinfo);
541 // client.setPayload(new EClient.Transfer() {
543 // public void transfer(OutputStream os) throws IOException, APIException {
547 queryParams = fragment = null;
548 return client.future(null);
551 public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
552 final String qp = setupParams(pathinfo);
554 EClient<CT> client = client();
555 client.setMethod(DELETE);
556 client.addHeader(CONTENT_TYPE, contentType);
557 client.setQueryParams(qp);
558 client.setFragment(fragment);
559 client.setPathInfo(pathinfo);
560 client.setPayload(new EClient.Transfer() {
562 public void transfer(OutputStream os) throws IOException, APIException {
563 df.newData().out(type).direct(t,os);
567 queryParams = fragment = null;
568 return client.future(t);
571 public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
572 final String qp = setupParams(pathinfo);
574 EClient<CT> client = client();
575 client.setMethod(DELETE);
576 client.addHeader(CONTENT_TYPE, typeString(cls));
577 client.setQueryParams(qp);
578 client.setFragment(fragment);
579 client.setPathInfo(pathinfo);
580 client.setPayload(new EClient.Transfer() {
582 public void transfer(OutputStream os) throws IOException, APIException {
583 df.newData().out(type).direct(t,os);
587 queryParams = fragment = null;
588 return client.future(t);
591 public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
592 final String qp = setupParams(pathinfo);
594 EClient<CT> client = client();
595 client.setMethod(DELETE);
596 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
597 client.setQueryParams(qp);
598 client.setFragment(fragment);
599 client.setPathInfo(pathinfo);
600 client.setPayload(new EClient.Transfer() {
602 public void transfer(OutputStream os) throws IOException, APIException {
603 df.newData().out(type).direct(t,os);
608 queryParams = fragment = null;
609 return client.future(t);
613 public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
614 final String qp = setupParams(pathinfo);
616 EClient<CT> client = client();
617 client.setMethod(DELETE);
618 client.addHeader(CONTENT_TYPE, typeString(cls));
619 client.setQueryParams(qp);
620 client.setFragment(fragment);
621 client.setPathInfo(pathinfo);
622 client.setPayload(null);
624 queryParams = fragment = null;
625 return client.future((T)null);
628 public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
629 final String qp = setupParams(pathinfo);
631 EClient<CT> client = client();
632 client.setMethod(DELETE);
633 client.addHeader(CONTENT_TYPE, contentType);
634 client.setQueryParams(qp);
635 client.setFragment(fragment);
636 client.setPathInfo(pathinfo);
637 client.setPayload(null);
639 queryParams = fragment = null;
640 return client.future(null);
643 public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
644 EClient<CT> client = client();
647 uri = new URI(req.getRequestURI());
648 } catch (Exception e) {
649 throw new CadiException("Invalid incoming URI",e);
652 for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
653 name = en.nextElement();
654 client.addHeader(name,req.getHeader(name));
656 client.setQueryParams(req.getQueryString());
657 client.setFragment(uri.getFragment());
658 client.setPathInfo(pathParam);
659 String meth = req.getMethod();
660 client.setMethod(meth);
661 if(!"GET".equals(meth)) {
662 client.setPayload(new EClient.Transfer() {
664 public void transfer(OutputStream os) throws IOException, APIException {
665 final ServletInputStream is = req.getInputStream();
668 Pooled<byte[]> pbuff = buffPool.get();
670 while((read=is.read(pbuff.content))>=0) {
671 os.write(pbuff.content,0,read);
680 return client.future(resp, expected);
683 private String setupParams(String pathinfo) {
688 final int idx = pathinfo.indexOf('?');
690 qp=pathinfo.substring(idx+1);
691 pathinfo=pathinfo.substring(0,idx);
699 public String toString() {
700 return uri.toString();
704 * @param queryParams the queryParams to set
707 public Rcli<CT> setQueryParams(String queryParams) {
708 this.queryParams = queryParams;
714 * @param fragment the fragment to set
717 public Rcli<CT> setFragment(String fragment) {
718 this.fragment = fragment;
722 public URI getURI() {