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 oneCallQueryParams;
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(final String pathinfo, final String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
136 final ParsePath pp = new ParsePath(pathinfo);
138 EClient<CT> client = client();
139 client.setMethod(POST);
140 client.addHeader(CONTENT_TYPE,contentType);
141 client.setPathInfo(pp.path());
142 client.setQueryParams(pp.query());
143 client.setFragment(pp.frag());
144 client.setPayload(new EClient.Transfer() {
146 public void transfer(OutputStream os) throws IOException, APIException {
147 df.newData().out(type).direct(t,os);
151 return client.futureCreate(df.getTypeClass());
154 public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
155 final ParsePath pp = new ParsePath(pathinfo);
157 EClient<CT> client = client();
158 client.setMethod(POST);
159 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
160 client.setPathInfo(pp.path());
161 client.setQueryParams(pp.query());
162 client.setFragment(pp.frag());
163 client.setPayload(new EClient.Transfer() {
165 public void transfer(OutputStream os) throws IOException, APIException {
166 df.newData().out(type).direct(t,os);
170 return client.futureCreate(df.getTypeClass());
173 public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
174 final ParsePath pp = new ParsePath(pathinfo);
176 EClient<CT> client = client();
177 client.setMethod(POST);
178 client.addHeader(CONTENT_TYPE,typeString(cls));
179 client.setPathInfo(pp.path());
180 client.setQueryParams(pp.query());
181 client.setFragment(pp.frag());
182 client.setPayload(new EClient.Transfer() {
184 public void transfer(OutputStream os) throws IOException, APIException {
185 df.newData().out(type).direct(t,os);
189 return client.futureCreate(df.getTypeClass());
192 public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
193 final ParsePath pp = new ParsePath(pathinfo);
195 EClient<CT> client = client();
196 client.setMethod(POST);
197 client.addHeader(CONTENT_TYPE,typeString(cls));
198 client.setPathInfo(pp.path());
199 client.setQueryParams(pp.query());
200 client.setFragment(pp.frag());
201 client.setPayload(null);
203 return client.futureCreate(cls);
206 public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
207 final ParsePath pp = new ParsePath(pathinfo);
209 EClient<CT> client = client();
210 client.setMethod(POST);
211 client.addHeader(CONTENT_TYPE,contentType);
212 client.setPathInfo(pp.path());
213 client.setQueryParams(pp.query());
214 client.setFragment(pp.frag());
215 client.setPayload(null);
217 return client.futureCreate(Void.class);
220 public Future<Void> create(String pathinfo, String contentType, EClient.Transfer content) throws APIException, CadiException {
221 final ParsePath pp = new ParsePath(pathinfo);
223 EClient<CT> client = client();
224 client.setMethod(POST);
225 client.addHeader(CONTENT_TYPE,contentType);
226 client.setPathInfo(pp.path());
227 client.setQueryParams(pp.query());
228 client.setFragment(pp.frag());
229 client.setPayload(content);
231 return client.futureCreate(Void.class);
236 * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
238 * Because typically, you will want to have a variable as value, you can type, as long as tag ends with "="
239 * postForm(..., "tag1=value1","tag2=",var2);
245 * @throws APIException
246 * @throws CadiException
248 public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
249 final ParsePath pp = new ParsePath(pathinfo);
251 EClient<CT> client = client();
252 client.setMethod(POST);
253 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
256 client.addHeader(ACCEPT, APPL_JSON);
259 client.addHeader(ACCEPT, APPL_XML);
264 client.setPathInfo(pp.path());
265 client.setQueryParams(pp.query());
266 client.setFragment(pp.frag());
267 client.setPayload(new Transfer() {
269 public void transfer(OutputStream os) throws IOException, APIException {
271 if (os instanceof PrintStream) {
272 ps = (PrintStream)os;
274 ps = new PrintStream(os);
276 boolean first = true;
277 for (String fp : formParam) {
284 if (fp.endsWith("=")) {
292 return client.futureRead(df,TYPE.JSON);
296 * Read String, using POST for keyInfo
303 * @throws APIException
304 * @throws CadiException
306 public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
307 final ParsePath pp = new ParsePath(pathinfo);
309 EClient<CT> client = client();
310 client.setMethod(POST);
311 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
312 client.setPathInfo(pp.path());
313 client.setQueryParams(pp.query());
314 client.setFragment(pp.frag());
315 client.setPayload(new EClient.Transfer() {
317 public void transfer(OutputStream os) throws IOException, APIException {
318 df.newData().out(type).direct(t,os);
322 return client.futureReadString();
326 * Read using POST for keyInfo, responding with marshaled Objects
333 * @throws APIException
334 * @throws CadiException
336 public<T,R> Future<R> readPost(String pathinfo, final RosettaDF<T> df, final T t, final RosettaDF<R> resp) throws APIException, CadiException {
337 final ParsePath pp = new ParsePath(pathinfo);
339 EClient<CT> client = client();
340 client.setMethod(POST);
341 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
342 client.setPathInfo(pp.path());
343 client.setQueryParams(pp.query());
344 client.setFragment(pp.frag());
345 client.setPayload(new EClient.Transfer() {
347 public void transfer(OutputStream os) throws IOException, APIException {
348 df.newData().out(type).direct(t,os);
352 return client.futureRead(resp,resp.getOutType());
355 public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
356 final ParsePath pp = new ParsePath(pathinfo);
358 EClient<CT> client = client();
359 client.setMethod(POST);
360 client.addHeader(CONTENT_TYPE,contentType);
361 client.setPathInfo(pp.path());
362 client.setQueryParams(pp.query());
363 client.setFragment(pp.frag());
364 client.setPayload(new EClient.Transfer() {
366 public void transfer(OutputStream os) throws IOException, APIException {
369 return client.futureReadString();
372 public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
373 final ParsePath pp = new ParsePath(pathinfo);
375 EClient<CT> client = client();
376 client.setMethod(GET);
377 client.addHeader(ACCEPT, accept);
379 for (int i=1;i<headers.length;i=i+2) {
380 client.addHeader(headers[i-1],headers[i]);
382 client.setPathInfo(pp.path());
383 client.setQueryParams(pp.query());
384 client.setFragment(pp.frag());
385 client.setPayload(null);
387 return client.futureReadString();
390 public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
391 final ParsePath pp = new ParsePath(pathinfo);
393 EClient<CT> client = client();
394 client.setMethod(GET);
395 client.addHeader(ACCEPT, accept);
396 for (int i=1;i<headers.length;i=i+2) {
397 client.addHeader(headers[i-1],headers[i]);
399 client.setPathInfo(pp.path());
400 client.setQueryParams(pp.query());
401 client.setFragment(pp.frag());
402 client.setPayload(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 ParsePath pp = new ParsePath(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.setPathInfo(pp.path());
417 client.setQueryParams(pp.query());
418 client.setFragment(pp.frag());
420 client.setPayload(null);
422 return client.futureRead(df,type);
425 public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
426 final ParsePath pp = new ParsePath(pathinfo);
428 EClient<CT> client = client();
429 client.setMethod(GET);
430 client.addHeader(ACCEPT, typeString(cls));
431 client.setPathInfo(pp.path());
432 client.setQueryParams(pp.query());
433 client.setFragment(pp.frag());
435 client.setPayload(null);
437 return client.futureRead(df,type);
440 public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
441 final ParsePath pp = new ParsePath(pathinfo);
443 EClient<CT> client = client();
444 client.setMethod(PUT);
445 client.addHeader(CONTENT_TYPE,contentType);
446 client.setPathInfo(pp.path());
447 client.setQueryParams(pp.query());
448 client.setFragment(pp.frag());
449 client.setPayload(new EClient.Transfer() {
451 public void transfer(OutputStream os) throws IOException, APIException {
452 df.newData().out(type).direct(t,os);
456 return client.future(t);
459 public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
460 final ParsePath pp = new ParsePath(pathinfo);
462 EClient<CT> client = client();
463 client.setMethod(PUT);
464 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
465 client.setPathInfo(pp.path());
466 client.setQueryParams(pp.query());
467 client.setFragment(pp.frag());
469 client.setPayload(new EClient.Transfer() {
471 public void transfer(OutputStream os) throws IOException, APIException {
472 //String s = df.newData().out(type).load(t).asString();
473 df.newData().out(type).direct(t,os);
477 return client.futureReadString();
480 public Future<String> update(String pathinfo, String contentType, EClient.Transfer content) throws APIException, CadiException {
481 final ParsePath pp = new ParsePath(pathinfo);
483 EClient<CT> client = client();
484 client.setMethod(PUT);
485 client.addHeader(CONTENT_TYPE,contentType);
486 client.setPathInfo(pp.path());
487 client.setQueryParams(pp.query());
488 client.setFragment(pp.frag());
489 client.setPayload(content);
491 return client.futureReadString();
497 public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
498 final ParsePath pp = new ParsePath(pathinfo);
500 EClient<CT> client = client();
501 client.setMethod(PUT);
502 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
503 client.setPathInfo(pp.path());
504 client.setQueryParams(pp.query());
505 client.setFragment(pp.frag());
507 client.setPayload(new EClient.Transfer() {
509 public void transfer(OutputStream os) throws IOException, APIException {
510 df.newData().out(type).direct(t,os);
514 return client.future(t);
517 public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
518 final ParsePath pp = new ParsePath(pathinfo);
520 EClient<CT> client = client();
521 client.setMethod(PUT);
522 client.addHeader(CONTENT_TYPE, typeString(cls));
523 client.setPathInfo(pp.path());
524 client.setQueryParams(pp.query());
525 client.setFragment(pp.frag());
527 client.setPayload(new EClient.Transfer() {
529 public void transfer(OutputStream os) throws IOException, APIException {
530 df.newData().out(type).direct(t,os);
534 return client.future(t);
540 * A method to update with a VOID
545 * @throws APIException
546 * @throws CadiException
548 public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
549 final ParsePath pp = new ParsePath(pathinfo);
551 EClient<CT> client = client();
552 client.setMethod(PUT);
553 client.addHeader(CONTENT_TYPE, typeString(Void.class));
554 client.setPathInfo(pp.path());
555 client.setQueryParams(pp.query());
556 client.setFragment(pp.frag());
558 // client.setPayload(new EClient.Transfer() {
560 // public void transfer(OutputStream os) throws IOException, APIException {
564 return client.future(null);
568 public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
569 final ParsePath pp = new ParsePath(pathinfo);
571 EClient<CT> client = client();
572 client.setMethod(DELETE);
573 client.addHeader(CONTENT_TYPE, contentType);
574 client.setPathInfo(pp.path());
575 client.setQueryParams(pp.query());
576 client.setFragment(pp.frag());
578 client.setPayload(new EClient.Transfer() {
580 public void transfer(OutputStream os) throws IOException, APIException {
581 df.newData().out(type).direct(t,os);
585 return client.future(t);
588 public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
589 final ParsePath pp = new ParsePath(pathinfo);
591 EClient<CT> client = client();
592 client.setMethod(DELETE);
593 client.addHeader(CONTENT_TYPE, typeString(cls));
594 client.setPathInfo(pp.path());
595 client.setQueryParams(pp.query());
596 client.setFragment(pp.frag());
597 client.setPayload(new EClient.Transfer() {
599 public void transfer(OutputStream os) throws IOException, APIException {
600 df.newData().out(type).direct(t,os);
604 return client.future(t);
607 public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
608 final ParsePath pp = new ParsePath(pathinfo);
610 EClient<CT> client = client();
611 client.setMethod(DELETE);
612 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
613 client.setPathInfo(pp.path());
614 client.setQueryParams(pp.query());
615 client.setFragment(pp.frag());
616 client.setPayload(new EClient.Transfer() {
618 public void transfer(OutputStream os) throws IOException, APIException {
619 df.newData().out(type).direct(t,os);
624 return client.future(t);
628 public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
629 final ParsePath pp = new ParsePath(pathinfo);
631 EClient<CT> client = client();
632 client.setMethod(DELETE);
633 client.addHeader(CONTENT_TYPE, typeString(cls));
634 client.setPathInfo(pp.path());
635 client.setQueryParams(pp.query());
636 client.setFragment(pp.frag());
638 client.setPayload(null);
640 return client.future((T)null);
643 public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
644 final ParsePath pp = new ParsePath(pathinfo);
646 EClient<CT> client = client();
647 client.setMethod(DELETE);
648 client.addHeader(CONTENT_TYPE, contentType);
649 client.setPathInfo(pp.path());
650 client.setQueryParams(pp.query());
651 client.setFragment(pp.frag());
653 client.setPayload(null);
655 return client.future(null);
658 public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
659 EClient<CT> client = client();
662 uri = new URI(req.getRequestURI());
663 } catch (Exception e) {
664 throw new CadiException("Invalid incoming URI",e);
667 for (Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
668 name = en.nextElement();
669 client.addHeader(name,req.getHeader(name));
671 client.setQueryParams(req.getQueryString());
672 client.setFragment(uri.getFragment());
673 client.setPathInfo(pathParam);
674 String meth = req.getMethod();
675 client.setMethod(meth);
676 if (!"GET".equals(meth)) {
677 client.setPayload(new EClient.Transfer() {
679 public void transfer(OutputStream os) throws IOException, APIException {
680 final ServletInputStream is = req.getInputStream();
683 Pooled<byte[]> pbuff = buffPool.get();
685 while ((read=is.read(pbuff.content))>=0) {
686 os.write(pbuff.content,0,read);
695 return client.future(resp, expected);
698 private class ParsePath {
699 private final String path;
700 private final int query;
701 private final int queryEnd;
702 private final int pound;
703 private final String queryParams;
705 public ParsePath(final String origPath) {
707 if (origPath==null) {
708 query=queryEnd=pound=-1;
711 query = origPath.indexOf('?');
712 pound = origPath.indexOf('#');
713 queryEnd = pound>=0?pound:path.length();
714 if (oneCallQueryParams==null) {
716 queryParams = path.substring(query+1,queryEnd);
722 queryParams = oneCallQueryParams + '&' + path.substring(query+1,queryEnd);
724 queryParams = oneCallQueryParams;
726 oneCallQueryParams = null;
731 public String path() {
734 return path.substring(pound+1);
736 return path.substring(0,query);
737 } else if (pound>=0) {
738 return path.substring(0,pound);
744 public String query() {
748 public String frag() {
750 return path.substring(pound+1);
757 public String toString() {
758 return uri.toString();
761 public URI getURI() {
765 public void setQueryParams(final String queryParams) {
766 oneCallQueryParams=queryParams;