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 {
140 final int idx = pathinfo.indexOf('?');
142 qp=pathinfo.substring(idx+1);
143 pathinfo=pathinfo.substring(0,idx);
149 EClient<CT> client = client();
150 client.setMethod(POST);
151 client.addHeader(CONTENT_TYPE,contentType);
152 client.setPathInfo(pathinfo);
153 client.setQueryParams(qp);
154 client.setFragment(fragment);
155 client.setPayload(new EClient.Transfer() {
157 public void transfer(OutputStream os) throws IOException, APIException {
158 df.newData().out(type).direct(t,os);
162 queryParams = fragment = null;
163 return client.futureCreate(df.getTypeClass());
166 public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
171 final int idx = pathinfo.indexOf('?');
173 qp=pathinfo.substring(idx+1);
174 pathinfo=pathinfo.substring(0,idx);
180 EClient<CT> client = client();
181 client.setMethod(POST);
182 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
183 client.setPathInfo(pathinfo);
184 client.setQueryParams(qp);
185 client.setFragment(fragment);
186 client.setPayload(new EClient.Transfer() {
188 public void transfer(OutputStream os) throws IOException, APIException {
189 df.newData().out(type).direct(t,os);
193 queryParams = fragment = null;
194 return client.futureCreate(df.getTypeClass());
197 public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
202 final int idx = pathinfo.indexOf('?');
204 qp=pathinfo.substring(idx+1);
205 pathinfo=pathinfo.substring(0,idx);
211 EClient<CT> client = client();
212 client.setMethod(POST);
213 client.addHeader(CONTENT_TYPE,typeString(cls));
214 client.setPathInfo(pathinfo);
215 client.setQueryParams(qp);
216 client.setFragment(fragment);
217 client.setPayload(new EClient.Transfer() {
219 public void transfer(OutputStream os) throws IOException, APIException {
220 df.newData().out(type).direct(t,os);
224 queryParams = fragment = null;
225 return client.futureCreate(df.getTypeClass());
228 public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
233 final int idx = pathinfo.indexOf('?');
235 qp=pathinfo.substring(idx+1);
236 pathinfo=pathinfo.substring(0,idx);
243 EClient<CT> client = client();
244 client.setMethod(POST);
245 client.addHeader(CONTENT_TYPE,typeString(cls));
246 client.setPathInfo(pathinfo);
247 client.setQueryParams(qp);
248 client.setFragment(fragment);
249 client.setPayload(null);
251 queryParams = fragment = null;
252 return client.futureCreate(cls);
255 public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
260 final int idx = pathinfo.indexOf('?');
262 qp=pathinfo.substring(idx+1);
263 pathinfo=pathinfo.substring(0,idx);
270 EClient<CT> client = client();
271 client.setMethod(POST);
272 client.addHeader(CONTENT_TYPE,contentType);
273 client.setPathInfo(pathinfo);
274 client.setQueryParams(qp);
275 client.setFragment(fragment);
276 client.setPayload(null);
278 queryParams = fragment = null;
279 return client.futureCreate(Void.class);
284 * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
286 * Because typically, you will want to have a variable as value, you can type, as long as tag ends with "="
287 * postForm(..., "tag1=value1","tag2=",var2);
293 * @throws APIException
294 * @throws CadiException
296 public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
301 final int idx = pathinfo.indexOf('?');
303 qp=pathinfo.substring(idx+1);
304 pathinfo=pathinfo.substring(0,idx);
310 EClient<CT> client = client();
311 client.setMethod(POST);
312 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
315 client.addHeader(ACCEPT, APPL_JSON);
318 client.addHeader(ACCEPT, APPL_XML);
323 client.setPathInfo(pathinfo);
324 client.setQueryParams(qp);
325 client.setFragment(fragment);
326 client.setPayload(new Transfer() {
328 public void transfer(OutputStream os) throws IOException, APIException {
330 if(os instanceof PrintStream) {
331 ps = (PrintStream)os;
333 ps = new PrintStream(os);
335 boolean first = true;
336 for(String fp : formParam) {
343 if(fp.endsWith("=")) {
351 queryParams = fragment = null;
352 return client.futureRead(df,TYPE.JSON);
356 * Read String, using POST for keyInfo
363 * @throws APIException
364 * @throws CadiException
366 public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
371 final int idx = pathinfo.indexOf('?');
373 qp=pathinfo.substring(idx+1);
374 pathinfo=pathinfo.substring(0,idx);
380 EClient<CT> client = client();
381 client.setMethod(POST);
382 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
383 client.setPathInfo(pathinfo);
384 client.setQueryParams(qp);
385 client.setFragment(fragment);
386 client.setPayload(new EClient.Transfer() {
388 public void transfer(OutputStream os) throws IOException, APIException {
389 df.newData().out(type).direct(t,os);
393 queryParams = fragment = null;
394 return client.futureReadString();
398 * Read using POST for keyInfo, responding with marshaled Objects
405 * @throws APIException
406 * @throws CadiException
408 public<T,R> Future<R> readPost(String pathinfo, final RosettaDF<T> df, final T t, final RosettaDF<R> resp) throws APIException, CadiException {
413 final int idx = pathinfo.indexOf('?');
415 qp=pathinfo.substring(idx+1);
416 pathinfo=pathinfo.substring(0,idx);
422 EClient<CT> client = client();
423 client.setMethod(POST);
424 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
425 client.setPathInfo(pathinfo);
426 client.setQueryParams(qp);
427 client.setFragment(fragment);
428 client.setPayload(new EClient.Transfer() {
430 public void transfer(OutputStream os) throws IOException, APIException {
431 df.newData().out(type).direct(t,os);
435 queryParams = fragment = null;
436 return client.futureRead(resp,resp.getOutType());
439 public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
444 final int idx = pathinfo.indexOf('?');
446 qp=pathinfo.substring(idx+1);
447 pathinfo=pathinfo.substring(0,idx);
453 EClient<CT> client = client();
454 client.setMethod(POST);
455 client.addHeader(CONTENT_TYPE,contentType);
456 client.setPathInfo(pathinfo);
457 client.setQueryParams(qp);
458 client.setFragment(fragment);
459 client.setPayload(new EClient.Transfer() {
461 public void transfer(OutputStream os) throws IOException, APIException {
464 queryParams = fragment = null;
465 return client.futureReadString();
468 public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
473 final int idx = pathinfo.indexOf('?');
475 qp=pathinfo.substring(idx+1);
476 pathinfo=pathinfo.substring(0,idx);
482 EClient<CT> client = client();
483 client.setMethod(GET);
484 client.addHeader(ACCEPT, accept);
486 for(int i=1;i<headers.length;i=i+2) {
487 client.addHeader(headers[i-1],headers[i]);
489 client.setQueryParams(qp);
490 client.setFragment(fragment);
492 client.setPathInfo(pathinfo);
494 client.setPayload(null);
496 queryParams = fragment = null;
497 return client.futureReadString();
500 public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
505 final int idx = pathinfo.indexOf('?');
507 qp=pathinfo.substring(idx+1);
508 pathinfo=pathinfo.substring(0,idx);
515 EClient<CT> client = client();
516 client.setMethod(GET);
517 client.addHeader(ACCEPT, accept);
518 for(int i=1;i<headers.length;i=i+2) {
519 client.addHeader(headers[i-1],headers[i]);
521 client.setQueryParams(qp);
522 client.setFragment(fragment);
523 client.setPathInfo(pathinfo);
525 client.setPayload(null);
527 queryParams = fragment = null;
528 return client.futureRead(df,type);
531 public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
536 final int idx = pathinfo.indexOf('?');
538 qp=pathinfo.substring(idx+1);
539 pathinfo=pathinfo.substring(0,idx);
546 EClient<CT> client = client();
547 client.setMethod(GET);
548 client.addHeader(ACCEPT, typeString(df.getTypeClass()));
549 for(int i=1;i<headers.length;i=i+2) {
550 client.addHeader(headers[i-1],headers[i]);
552 client.setQueryParams(qp);
553 client.setFragment(fragment);
554 client.setPathInfo(pathinfo);
556 client.setPayload(null);
558 queryParams = fragment = null;
559 return client.futureRead(df,type);
562 public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
567 final int idx = pathinfo.indexOf('?');
569 qp=pathinfo.substring(idx+1);
570 pathinfo=pathinfo.substring(0,idx);
576 EClient<CT> client = client();
577 client.setMethod(GET);
578 client.addHeader(ACCEPT, typeString(cls));
579 client.setQueryParams(qp);
580 client.setFragment(fragment);
581 client.setPathInfo(pathinfo);
583 client.setPayload(null);
585 queryParams = fragment = null;
586 return client.futureRead(df,type);
589 public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
594 final int idx = pathinfo.indexOf('?');
596 qp=pathinfo.substring(idx+1);
597 pathinfo=pathinfo.substring(0,idx);
604 EClient<CT> client = client();
605 client.setMethod(PUT);
606 client.addHeader(CONTENT_TYPE,contentType);
607 client.setQueryParams(qp);
608 client.setFragment(fragment);
609 client.setPathInfo(pathinfo);
610 client.setPayload(new EClient.Transfer() {
612 public void transfer(OutputStream os) throws IOException, APIException {
613 df.newData().out(type).direct(t,os);
617 queryParams = fragment = null;
618 return client.future(t);
621 public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
626 final int idx = pathinfo.indexOf('?');
628 qp=pathinfo.substring(idx+1);
629 pathinfo=pathinfo.substring(0,idx);
636 EClient<CT> client = client();
637 client.setMethod(PUT);
638 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
639 client.setQueryParams(qp);
640 client.setFragment(fragment);
641 client.setPathInfo(pathinfo);
642 client.setPayload(new EClient.Transfer() {
644 public void transfer(OutputStream os) throws IOException, APIException {
645 df.newData().out(type).direct(t,os);
649 queryParams = fragment = null;
650 return client.futureReadString();
654 public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
659 final int idx = pathinfo.indexOf('?');
661 qp=pathinfo.substring(idx+1);
662 pathinfo=pathinfo.substring(0,idx);
668 EClient<CT> client = client();
669 client.setMethod(PUT);
670 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
671 client.setQueryParams(qp);
672 client.setFragment(fragment);
673 client.setPathInfo(pathinfo);
674 client.setPayload(new EClient.Transfer() {
676 public void transfer(OutputStream os) throws IOException, APIException {
677 df.newData().out(type).direct(t,os);
681 queryParams = fragment = null;
682 return client.future(t);
685 public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
690 final int idx = pathinfo.indexOf('?');
692 qp=pathinfo.substring(idx+1);
693 pathinfo=pathinfo.substring(0,idx);
700 EClient<CT> client = client();
701 client.setMethod(PUT);
702 client.addHeader(CONTENT_TYPE, typeString(cls));
703 client.setQueryParams(qp);
704 client.setFragment(fragment);
705 client.setPathInfo(pathinfo);
706 client.setPayload(new EClient.Transfer() {
708 public void transfer(OutputStream os) throws IOException, APIException {
709 df.newData().out(type).direct(t,os);
713 queryParams = fragment = null;
714 return client.future(t);
718 * A method to update with a VOID
723 * @throws APIException
724 * @throws CadiException
726 public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
731 final int idx = pathinfo.indexOf('?');
733 qp=pathinfo.substring(idx+1);
734 pathinfo=pathinfo.substring(0,idx);
741 EClient<CT> client = client();
742 client.setMethod(PUT);
743 client.addHeader(CONTENT_TYPE, typeString(Void.class));
744 client.setQueryParams(qp);
745 client.setFragment(fragment);
746 client.setPathInfo(pathinfo);
747 // client.setPayload(new EClient.Transfer() {
749 // public void transfer(OutputStream os) throws IOException, APIException {
753 queryParams = fragment = null;
754 return client.future(null);
757 public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
762 final int idx = pathinfo.indexOf('?');
764 qp=pathinfo.substring(idx+1);
765 pathinfo=pathinfo.substring(0,idx);
772 EClient<CT> client = client();
773 client.setMethod(DELETE);
774 client.addHeader(CONTENT_TYPE, contentType);
775 client.setQueryParams(qp);
776 client.setFragment(fragment);
777 client.setPathInfo(pathinfo);
778 client.setPayload(new EClient.Transfer() {
780 public void transfer(OutputStream os) throws IOException, APIException {
781 df.newData().out(type).direct(t,os);
785 queryParams = fragment = null;
786 return client.future(t);
789 public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
794 final int idx = pathinfo.indexOf('?');
796 qp=pathinfo.substring(idx+1);
797 pathinfo=pathinfo.substring(0,idx);
804 EClient<CT> client = client();
805 client.setMethod(DELETE);
806 client.addHeader(CONTENT_TYPE, typeString(cls));
807 client.setQueryParams(qp);
808 client.setFragment(fragment);
809 client.setPathInfo(pathinfo);
810 client.setPayload(new EClient.Transfer() {
812 public void transfer(OutputStream os) throws IOException, APIException {
813 df.newData().out(type).direct(t,os);
817 queryParams = fragment = null;
818 return client.future(t);
821 public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
826 final int idx = pathinfo.indexOf('?');
828 qp=pathinfo.substring(idx+1);
829 pathinfo=pathinfo.substring(0,idx);
835 EClient<CT> client = client();
836 client.setMethod(DELETE);
837 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
838 client.setQueryParams(qp);
839 client.setFragment(fragment);
840 client.setPathInfo(pathinfo);
841 client.setPayload(new EClient.Transfer() {
843 public void transfer(OutputStream os) throws IOException, APIException {
844 df.newData().out(type).direct(t,os);
849 queryParams = fragment = null;
850 return client.future(t);
854 public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
859 final int idx = pathinfo.indexOf('?');
861 qp=pathinfo.substring(idx+1);
862 pathinfo=pathinfo.substring(0,idx);
869 EClient<CT> client = client();
870 client.setMethod(DELETE);
871 client.addHeader(CONTENT_TYPE, typeString(cls));
872 client.setQueryParams(qp);
873 client.setFragment(fragment);
874 client.setPathInfo(pathinfo);
875 client.setPayload(null);
877 queryParams = fragment = null;
878 return client.future((T)null);
881 public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
886 final int idx = pathinfo.indexOf('?');
888 qp=pathinfo.substring(idx+1);
889 pathinfo=pathinfo.substring(0,idx);
895 EClient<CT> client = client();
896 client.setMethod(DELETE);
897 client.addHeader(CONTENT_TYPE, contentType);
898 client.setQueryParams(qp);
899 client.setFragment(fragment);
900 client.setPathInfo(pathinfo);
901 client.setPayload(null);
903 queryParams = fragment = null;
904 return client.future(null);
907 public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
908 EClient<CT> client = client();
911 uri = new URI(req.getRequestURI());
912 } catch (Exception e) {
913 throw new CadiException("Invalid incoming URI",e);
916 for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
917 name = en.nextElement();
918 client.addHeader(name,req.getHeader(name));
920 client.setQueryParams(req.getQueryString());
921 client.setFragment(uri.getFragment());
922 client.setPathInfo(pathParam);
923 String meth = req.getMethod();
924 client.setMethod(meth);
925 if(!"GET".equals(meth)) {
926 client.setPayload(new EClient.Transfer() {
928 public void transfer(OutputStream os) throws IOException, APIException {
929 final ServletInputStream is = req.getInputStream();
932 Pooled<byte[]> pbuff = buffPool.get();
934 while((read=is.read(pbuff.content))>=0) {
935 os.write(pbuff.content,0,read);
944 return client.future(resp, expected);
947 public String toString() {
948 return uri.toString();
952 * @param queryParams the queryParams to set
955 public Rcli<CT> setQueryParams(String queryParams) {
956 this.queryParams = queryParams;
962 * @param fragment the fragment to set
965 public Rcli<CT> setFragment(String fragment) {
966 this.fragment = fragment;
970 public URI getURI() {