AT&T 2.0.19 Code drop, stage 2
[aaf/authz.git] / cadi / client / src / main / java / org / onap / aaf / cadi / client / Rcli.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi.client;
23
24 import java.io.IOException;
25 import java.io.OutputStream;
26 import java.io.PrintStream;
27 import java.net.URI;
28 import java.util.Enumeration;
29
30 import javax.servlet.ServletInputStream;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
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;
42
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";
50
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";
55         protected TYPE type;
56         protected String apiVersion;
57         protected int readTimeout = 5000;
58         protected int connectionTimeout = 3000;
59         protected URI uri;
60         private String queryParams, fragment;
61         public static Pool<byte[]> buffPool = new Pool<byte[]>(new Pool.Creator<byte[]>() {
62                 @Override
63                 public byte[] create() throws APIException {
64                         return new byte[1024];
65                 }
66
67                 @Override
68                 public void destroy(byte[] t) {
69                 }
70
71                 @Override
72                 public boolean isValid(byte[] t) {
73                         return true;
74                 }
75
76                 @Override
77                 public void reuse(byte[] t) {
78                 }
79         });
80
81
82         public Rcli() {
83                 super();
84         }
85
86         public abstract void setSecuritySetter(SecuritySetter<CT> ss);
87         public abstract SecuritySetter<CT> getSecuritySetter();
88
89
90         public Rcli<CT> forUser(SecuritySetter<CT> ss) {
91                 Rcli<CT> rv = clone(uri==null?this.uri:uri,ss);
92                 setSecuritySetter(ss);
93                 rv.type = type;
94                 rv.apiVersion = apiVersion;
95                 return rv;
96         }
97         
98         protected abstract Rcli<CT> clone(URI uri, SecuritySetter<CT> ss);
99         
100         public abstract void invalidate() throws CadiException;
101
102         public Rcli<CT> readTimeout(int millis) {
103                 readTimeout = millis;
104                 return this;
105         }
106
107         public Rcli<CT> connectionTimeout(int millis) {
108                 connectionTimeout = millis;
109                 return this;
110         }
111
112         public Rcli<CT> type(TYPE type) {
113                 this.type=type;
114                 return this;
115         }
116
117         public Rcli<CT> apiVersion(String apiVersion) {
118                 this.apiVersion = apiVersion;
119                 return this;
120         }
121         
122         public boolean isApiVersion(String prospective) {
123                 return apiVersion.equals(prospective);
124         }
125
126
127         public String typeString(Class<?> cls) {
128                 return "application/"+cls.getSimpleName()+"+"+type.name().toLowerCase()+
129                                 (apiVersion==null?BLANK:";version="+apiVersion);
130         }
131
132         protected abstract EClient<CT> client() throws CadiException;
133
134
135         public<T> Future<T> create(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
136                 final String qp; 
137                 if(pathinfo==null) {
138                         qp=queryParams;
139                 } else {
140                         final int idx = pathinfo.indexOf('?');
141                         if(idx>=0) {
142                                 qp=pathinfo.substring(idx+1);
143                                 pathinfo=pathinfo.substring(0,idx);
144                         } else {
145                                 qp=queryParams;
146                         }
147                 }
148
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() {
156                         @Override
157                         public void transfer(OutputStream os) throws IOException, APIException {
158                                 df.newData().out(type).direct(t,os);
159                         }
160                 });
161                 client.send();
162                 queryParams = fragment = null;
163                 return client.futureCreate(df.getTypeClass());
164         }
165
166         public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
167                 final String qp; 
168                 if(pathinfo==null) {
169                         qp=queryParams;
170                 } else {
171                         final int idx = pathinfo.indexOf('?');
172                         if(idx>=0) {
173                                 qp=pathinfo.substring(idx+1);
174                                 pathinfo=pathinfo.substring(0,idx);
175                         } else {
176                                 qp=queryParams;
177                         }
178                 }
179
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() {
187                         @Override
188                         public void transfer(OutputStream os) throws IOException, APIException {
189                                 df.newData().out(type).direct(t,os);
190                         }
191                 });
192                 client.send();
193                 queryParams = fragment = null;
194                 return client.futureCreate(df.getTypeClass());
195         }
196
197         public<T> Future<T> create(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
198                 final String qp; 
199                 if(pathinfo==null) {
200                         qp=queryParams;
201                 } else {
202                         final int idx = pathinfo.indexOf('?');
203                         if(idx>=0) {
204                                 qp=pathinfo.substring(idx+1);
205                                 pathinfo=pathinfo.substring(0,idx);
206                         } else {
207                                 qp=queryParams;
208                         }
209                 }
210
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() {
218                         @Override
219                         public void transfer(OutputStream os) throws IOException, APIException {
220                                 df.newData().out(type).direct(t,os);
221                         }
222                 });
223                 client.send();
224                 queryParams = fragment = null;
225                 return client.futureCreate(df.getTypeClass());
226         }
227
228         public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
229                 final String qp; 
230                 if(pathinfo==null) {
231                         qp=queryParams;
232                 } else {
233                         final int idx = pathinfo.indexOf('?');
234                         if(idx>=0) {
235                                 qp=pathinfo.substring(idx+1);
236                                 pathinfo=pathinfo.substring(0,idx);
237                         } else {
238                                 qp=queryParams;
239                         }
240                 }
241
242
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);
250                 client.send();
251                 queryParams = fragment = null;
252                 return client.futureCreate(cls);
253         }
254
255         public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
256                 final String qp; 
257                 if(pathinfo==null) {
258                         qp=queryParams;
259                 } else {
260                         final int idx = pathinfo.indexOf('?');
261                         if(idx>=0) {
262                                 qp=pathinfo.substring(idx+1);
263                                 pathinfo=pathinfo.substring(0,idx);
264                         } else {
265                                 qp=queryParams;
266                         }
267                 }
268
269
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);
277                 client.send();
278                 queryParams = fragment = null;
279                 return client.futureCreate(Void.class);
280         }
281
282
283         /**
284          * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
285          * Note Shortcut:
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);
288          * @param pathinfo
289          * @param df
290          * @param cls
291          * @param formParam
292          * @return
293          * @throws APIException
294          * @throws CadiException
295          */
296         public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
297                 final String qp; 
298                 if(pathinfo==null) {
299                         qp=queryParams;
300                 } else {
301                         final int idx = pathinfo.indexOf('?');
302                         if(idx>=0) {
303                                 qp=pathinfo.substring(idx+1);
304                                 pathinfo=pathinfo.substring(0,idx);
305                         } else {
306                                 qp=queryParams;
307                         }
308                 }
309
310                 EClient<CT> client = client();
311                 client.setMethod(POST);
312                 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
313                 switch(type) {
314                         case JSON:
315                                 client.addHeader(ACCEPT, APPL_JSON);
316                                 break;
317                         case XML:
318                                 client.addHeader(ACCEPT, APPL_XML);
319                                 break;
320                         default:
321                                 break;
322                 }
323                 client.setPathInfo(pathinfo);
324                 client.setQueryParams(qp);
325                 client.setFragment(fragment);
326                 client.setPayload(new Transfer() {
327                         @Override
328                         public void transfer(OutputStream os) throws IOException, APIException {
329                                 PrintStream ps;
330                                 if(os instanceof PrintStream) {
331                                         ps = (PrintStream)os;
332                                 } else {
333                                         ps = new PrintStream(os);
334                                 }
335                                 boolean first = true;
336                                 for(String fp : formParam) {
337                                         if(fp!=null) {
338                                                 if(first) {
339                                                         first = false;
340                                                 } else {
341                                                         ps.print('&');
342                                                 }
343                                                 if(fp.endsWith("=")) {
344                                                         first = true;
345                                                 }
346                                                 ps.print(fp);
347                                         }
348                                 }
349                         }});
350                 client.send();
351                 queryParams = fragment = null;
352                 return client.futureRead(df,TYPE.JSON);
353         }
354
355         /**
356          * Read String, using POST for keyInfo
357          * 
358          * @param pathinfo
359          * @param df
360          * @param t
361          * @param resp
362          * @return
363          * @throws APIException
364          * @throws CadiException
365          */
366         public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
367                 final String qp; 
368                 if(pathinfo==null) {
369                         qp=queryParams;
370                 } else {
371                         final int idx = pathinfo.indexOf('?');
372                         if(idx>=0) {
373                                 qp=pathinfo.substring(idx+1);
374                                 pathinfo=pathinfo.substring(0,idx);
375                         } else {
376                                 qp=queryParams;
377                         }
378                 }
379
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() {
387                         @Override
388                         public void transfer(OutputStream os) throws IOException, APIException {
389                                 df.newData().out(type).direct(t,os);
390                         }
391                 });
392                 client.send();
393                 queryParams = fragment = null;
394                 return client.futureReadString();
395         }
396
397         /**
398          * Read using POST for keyInfo, responding with marshaled Objects
399          *
400          * @param pathinfo
401          * @param df
402          * @param t
403          * @param resp
404          * @return
405          * @throws APIException
406          * @throws CadiException
407          */
408         public<T,R> Future<R> readPost(String pathinfo, final RosettaDF<T> df, final T t, final RosettaDF<R> resp) throws APIException, CadiException {
409                 final String qp; 
410                 if(pathinfo==null) {
411                         qp=queryParams;
412                 } else {
413                         final int idx = pathinfo.indexOf('?');
414                         if(idx>=0) {
415                                 qp=pathinfo.substring(idx+1);
416                                 pathinfo=pathinfo.substring(0,idx);
417                         } else {
418                                 qp=queryParams;
419                         }
420                 }
421
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() {
429                         @Override
430                         public void transfer(OutputStream os) throws IOException, APIException {
431                                 df.newData().out(type).direct(t,os);
432                         }
433                 });
434                 client.send();
435                 queryParams = fragment = null;
436                 return client.futureRead(resp,resp.getOutType());
437         }
438
439         public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
440                 final String qp; 
441                 if(pathinfo==null) {
442                         qp=queryParams;
443                 } else {
444                         final int idx = pathinfo.indexOf('?');
445                         if(idx>=0) {
446                                 qp=pathinfo.substring(idx+1);
447                                 pathinfo=pathinfo.substring(0,idx);
448                         } else {
449                                 qp=queryParams;
450                         }
451                 }
452
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() {
460                         @Override
461                         public void transfer(OutputStream os) throws IOException, APIException {
462                         }});
463                 client.send();
464                 queryParams = fragment = null;
465                 return client.futureReadString();
466         }
467
468         public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
469                 final String qp;
470                 if(pathinfo==null) {
471                         qp=queryParams;
472                 } else {
473                         final int idx = pathinfo.indexOf('?');
474                         if(idx>=0) {
475                                 qp=pathinfo.substring(idx+1);
476                                 pathinfo=pathinfo.substring(0,idx);
477                         } else {
478                                 qp=queryParams;
479                         }
480                 }
481         
482                 EClient<CT> client = client();
483                 client.setMethod(GET);
484                 client.addHeader(ACCEPT, accept);
485                 
486                 for(int i=1;i<headers.length;i=i+2) {
487                         client.addHeader(headers[i-1],headers[i]);
488                 }
489                 client.setQueryParams(qp);
490                 client.setFragment(fragment);
491         
492                 client.setPathInfo(pathinfo);
493                 
494                 client.setPayload(null);
495                 client.send();
496                 queryParams = fragment = null;
497                 return client.futureReadString();
498         }
499
500         public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
501                 final String qp; 
502                 if(pathinfo==null) {
503                         qp=queryParams;
504                 } else {
505                         final int idx = pathinfo.indexOf('?');
506                         if(idx>=0) {
507                                 qp=pathinfo.substring(idx+1);
508                                 pathinfo=pathinfo.substring(0,idx);
509                         } else {
510                                 qp=queryParams;
511                         }
512                 }
513
514
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]);
520                 }
521                 client.setQueryParams(qp);
522                 client.setFragment(fragment);
523                 client.setPathInfo(pathinfo);
524                 
525                 client.setPayload(null);
526                 client.send();
527                 queryParams = fragment = null;
528                 return client.futureRead(df,type);
529         }
530
531         public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
532                 final String qp; 
533                 if(pathinfo==null) {
534                         qp=queryParams;
535                 } else {
536                         final int idx = pathinfo.indexOf('?');
537                         if(idx>=0) {
538                                 qp=pathinfo.substring(idx+1);
539                                 pathinfo=pathinfo.substring(0,idx);
540                         } else {
541                                 qp=queryParams;
542                         }
543                 }
544
545
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]);
551                 }
552                 client.setQueryParams(qp);
553                 client.setFragment(fragment);
554                 client.setPathInfo(pathinfo);
555                 
556                 client.setPayload(null);
557                 client.send();
558                 queryParams = fragment = null;
559                 return client.futureRead(df,type);
560         }
561
562         public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
563                 final String qp; 
564                 if(pathinfo==null) {
565                         qp=queryParams;
566                 } else {
567                         final int idx = pathinfo.indexOf('?');
568                         if(idx>=0) {
569                                 qp=pathinfo.substring(idx+1);
570                                 pathinfo=pathinfo.substring(0,idx);
571                         } else {
572                                 qp=queryParams;
573                         }
574                 }
575
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);
582                 
583                 client.setPayload(null);
584                 client.send();
585                 queryParams = fragment = null;
586                 return client.futureRead(df,type);
587         }
588
589         public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
590                 final String qp; 
591                 if(pathinfo==null) {
592                         qp=queryParams;
593                 } else {
594                         final int idx = pathinfo.indexOf('?');
595                         if(idx>=0) {
596                                 qp=pathinfo.substring(idx+1);
597                                 pathinfo=pathinfo.substring(0,idx);
598                         } else {
599                                 qp=queryParams;
600                         }
601                 }
602
603
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() {
611                         @Override
612                         public void transfer(OutputStream os) throws IOException, APIException {
613                                 df.newData().out(type).direct(t,os);
614                         }
615                 });
616                 client.send();
617                 queryParams = fragment = null;
618                 return client.future(t);
619         }
620         
621         public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
622                 final String qp; 
623                 if(pathinfo==null) {
624                         qp=queryParams;
625                 } else {
626                         final int idx = pathinfo.indexOf('?');
627                         if(idx>=0) {
628                                 qp=pathinfo.substring(idx+1);
629                                 pathinfo=pathinfo.substring(0,idx);
630                         } else {
631                                 qp=queryParams;
632                         }
633                 }
634
635
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() {
643                         @Override
644                         public void transfer(OutputStream os) throws IOException, APIException {
645                                 df.newData().out(type).direct(t,os);
646                         }
647                 });
648                 client.send();
649                 queryParams = fragment = null;
650                 return client.futureReadString();
651         }
652
653
654         public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
655                 final String qp; 
656                 if(pathinfo==null) {
657                         qp=queryParams;
658                 } else {
659                         final int idx = pathinfo.indexOf('?');
660                         if(idx>=0) {
661                                 qp=pathinfo.substring(idx+1);
662                                 pathinfo=pathinfo.substring(0,idx);
663                         } else {
664                                 qp=queryParams;
665                         }
666                 }
667
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() {
675                         @Override
676                         public void transfer(OutputStream os) throws IOException, APIException {
677                                 df.newData().out(type).direct(t,os);
678                         }
679                 });
680                 client.send();
681                 queryParams = fragment = null;
682                 return client.future(t);
683         }
684         
685         public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
686                 final String qp; 
687                 if(pathinfo==null) {
688                         qp=queryParams;
689                 } else {
690                         final int idx = pathinfo.indexOf('?');
691                         if(idx>=0) {
692                                 qp=pathinfo.substring(idx+1);
693                                 pathinfo=pathinfo.substring(0,idx);
694                         } else {
695                                 qp=queryParams;
696                         }
697                 }
698
699
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() {
707                         @Override
708                         public void transfer(OutputStream os) throws IOException, APIException {
709                                 df.newData().out(type).direct(t,os);
710                         }
711                 });
712                 client.send();
713                 queryParams = fragment = null;
714                 return client.future(t);
715         }
716
717         /**
718          * A method to update with a VOID
719          * @param pathinfo
720          * @param resp
721          * @param expected
722          * @return
723          * @throws APIException
724          * @throws CadiException
725          */
726         public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
727                 final String qp; 
728                 if(pathinfo==null) {
729                         qp=queryParams;
730                 } else {
731                         final int idx = pathinfo.indexOf('?');
732                         if(idx>=0) {
733                                 qp=pathinfo.substring(idx+1);
734                                 pathinfo=pathinfo.substring(0,idx);
735                         } else {
736                                 qp=queryParams;
737                         }
738                 }
739
740
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() {
748 //                      @Override
749 //                      public void transfer(OutputStream os) throws IOException, APIException {
750 //                      }
751 //              });
752                 client.send();
753                 queryParams = fragment = null;
754                 return client.future(null);
755         }
756
757         public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
758                 final String qp; 
759                 if(pathinfo==null) {
760                         qp=queryParams;
761                 } else {
762                         final int idx = pathinfo.indexOf('?');
763                         if(idx>=0) {
764                                 qp=pathinfo.substring(idx+1);
765                                 pathinfo=pathinfo.substring(0,idx);
766                         } else {
767                                 qp=queryParams;
768                         }
769                 }
770
771
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() {
779                         @Override
780                         public void transfer(OutputStream os) throws IOException, APIException {
781                                 df.newData().out(type).direct(t,os);
782                         }
783                 });
784                 client.send();
785                 queryParams = fragment = null;
786                 return client.future(t);
787         }
788
789         public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
790                 final String qp; 
791                 if(pathinfo==null) {
792                         qp=queryParams;
793                 } else {
794                         final int idx = pathinfo.indexOf('?');
795                         if(idx>=0) {
796                                 qp=pathinfo.substring(idx+1);
797                                 pathinfo=pathinfo.substring(0,idx);
798                         } else {
799                                 qp=queryParams;
800                         }
801                 }
802
803
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() {
811                         @Override
812                         public void transfer(OutputStream os) throws IOException, APIException {
813                                 df.newData().out(type).direct(t,os);
814                         }
815                 });
816                 client.send();
817                 queryParams = fragment = null;
818                 return client.future(t);
819         }
820
821         public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
822                 final String qp; 
823                 if(pathinfo==null) {
824                         qp=queryParams;
825                 } else {
826                         final int idx = pathinfo.indexOf('?');
827                         if(idx>=0) {
828                                 qp=pathinfo.substring(idx+1);
829                                 pathinfo=pathinfo.substring(0,idx);
830                         } else {
831                                 qp=queryParams;
832                         }
833                 }
834
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() {
842                         @Override
843                         public void transfer(OutputStream os) throws IOException, APIException {
844                                 df.newData().out(type).direct(t,os);
845                         }
846                 });
847
848                 client.send();
849                 queryParams = fragment = null;
850                 return client.future(t);
851         }
852
853
854         public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
855                 final String qp; 
856                 if(pathinfo==null) {
857                         qp=queryParams;
858                 } else {
859                         final int idx = pathinfo.indexOf('?');
860                         if(idx>=0) {
861                                 qp=pathinfo.substring(idx+1);
862                                 pathinfo=pathinfo.substring(0,idx);
863                         } else {
864                                 qp=queryParams;
865                         }
866                 }
867
868
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);
876                 client.send();
877                 queryParams = fragment = null;
878                 return client.future((T)null);
879         }
880
881         public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
882                 final String qp; 
883                 if(pathinfo==null) {
884                         qp=queryParams;
885                 } else {
886                         final int idx = pathinfo.indexOf('?');
887                         if(idx>=0) {
888                                 qp=pathinfo.substring(idx+1);
889                                 pathinfo=pathinfo.substring(0,idx);
890                         } else {
891                                 qp=queryParams;
892                         }
893                 }
894
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);
902                 client.send();
903                 queryParams = fragment = null;
904                 return client.future(null);
905         }
906
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();
909                 URI uri;
910                 try {
911                         uri = new URI(req.getRequestURI());
912                 } catch (Exception e) {
913                         throw new CadiException("Invalid incoming URI",e);
914                 }
915                 String name;
916                 for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
917                         name = en.nextElement();
918                         client.addHeader(name,req.getHeader(name));
919                 }
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() {
927                                 @Override
928                                 public void transfer(OutputStream os) throws IOException, APIException {
929                                         final ServletInputStream is = req.getInputStream();
930                                         int read;
931                                         // reuse Buffers
932                                         Pooled<byte[]> pbuff = buffPool.get();
933                                         try { 
934                                                 while((read=is.read(pbuff.content))>=0) {
935                                                         os.write(pbuff.content,0,read);
936                                                 }
937                                         } finally {
938                                                 pbuff.done();
939                                         }
940                                 }
941                         });
942                 }
943                 client.send();
944                 return client.future(resp, expected);
945         }
946
947         public String toString() {
948                 return uri.toString();
949         }
950
951         /**
952          * @param queryParams the queryParams to set
953          * @return 
954          */
955         public Rcli<CT> setQueryParams(String queryParams) {
956                 this.queryParams = queryParams;
957                 return this;
958         }
959         
960
961         /**
962          * @param fragment the fragment to set
963          * @return 
964          */
965         public Rcli<CT> setFragment(String fragment) {
966                 this.fragment = fragment;
967                 return this;
968         }
969
970         public URI getURI() {
971                 return uri;
972         }
973
974 }