Improve coverage of Cadi/client
[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 = setupParams(pathinfo);
137
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() {
145                         @Override
146                         public void transfer(OutputStream os) throws IOException, APIException {
147                                 df.newData().out(type).direct(t,os);
148                         }
149                 });
150                 client.send();
151                 queryParams = fragment = null;
152                 return client.futureCreate(df.getTypeClass());
153         }
154
155         public<T> Future<T> create(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
156                 final String qp = setupParams(pathinfo);
157
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() {
165                         @Override
166                         public void transfer(OutputStream os) throws IOException, APIException {
167                                 df.newData().out(type).direct(t,os);
168                         }
169                 });
170                 client.send();
171                 queryParams = fragment = null;
172                 return client.futureCreate(df.getTypeClass());
173         }
174
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);
177
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() {
185                         @Override
186                         public void transfer(OutputStream os) throws IOException, APIException {
187                                 df.newData().out(type).direct(t,os);
188                         }
189                 });
190                 client.send();
191                 queryParams = fragment = null;
192                 return client.futureCreate(df.getTypeClass());
193         }
194
195         public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
196                 final String qp = setupParams(pathinfo);
197
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);
205                 client.send();
206                 queryParams = fragment = null;
207                 return client.futureCreate(cls);
208         }
209
210         public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
211                 final String qp = setupParams(pathinfo);
212
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);
220                 client.send();
221                 queryParams = fragment = null;
222                 return client.futureCreate(Void.class);
223         }
224
225
226         /**
227          * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
228          * Note Shortcut:
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);
231          * @param pathinfo
232          * @param df
233          * @param cls
234          * @param formParam
235          * @return
236          * @throws APIException
237          * @throws CadiException
238          */
239         public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
240                 final String qp = setupParams(pathinfo);
241
242                 EClient<CT> client = client();
243                 client.setMethod(POST);
244                 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
245                 switch(type) {
246                         case JSON:
247                                 client.addHeader(ACCEPT, APPL_JSON);
248                                 break;
249                         case XML:
250                                 client.addHeader(ACCEPT, APPL_XML);
251                                 break;
252                         default:
253                                 break;
254                 }
255                 client.setPathInfo(pathinfo);
256                 client.setQueryParams(qp);
257                 client.setFragment(fragment);
258                 client.setPayload(new Transfer() {
259                         @Override
260                         public void transfer(OutputStream os) throws IOException, APIException {
261                                 PrintStream ps;
262                                 if(os instanceof PrintStream) {
263                                         ps = (PrintStream)os;
264                                 } else {
265                                         ps = new PrintStream(os);
266                                 }
267                                 boolean first = true;
268                                 for(String fp : formParam) {
269                                         if(fp!=null) {
270                                                 if(first) {
271                                                         first = false;
272                                                 } else {
273                                                         ps.print('&');
274                                                 }
275                                                 if(fp.endsWith("=")) {
276                                                         first = true;
277                                                 }
278                                                 ps.print(fp);
279                                         }
280                                 }
281                         }});
282                 client.send();
283                 queryParams = fragment = null;
284                 return client.futureRead(df,TYPE.JSON);
285         }
286
287         /**
288          * Read String, using POST for keyInfo
289          * 
290          * @param pathinfo
291          * @param df
292          * @param t
293          * @param resp
294          * @return
295          * @throws APIException
296          * @throws CadiException
297          */
298         public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
299                 final String qp = setupParams(pathinfo);
300
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() {
308                         @Override
309                         public void transfer(OutputStream os) throws IOException, APIException {
310                                 df.newData().out(type).direct(t,os);
311                         }
312                 });
313                 client.send();
314                 queryParams = fragment = null;
315                 return client.futureReadString();
316         }
317
318         /**
319          * Read using POST for keyInfo, responding with marshaled Objects
320          *
321          * @param pathinfo
322          * @param df
323          * @param t
324          * @param resp
325          * @return
326          * @throws APIException
327          * @throws CadiException
328          */
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);
331
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() {
339                         @Override
340                         public void transfer(OutputStream os) throws IOException, APIException {
341                                 df.newData().out(type).direct(t,os);
342                         }
343                 });
344                 client.send();
345                 queryParams = fragment = null;
346                 return client.futureRead(resp,resp.getOutType());
347         }
348
349         public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
350                 final String qp = setupParams(pathinfo);
351
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() {
359                         @Override
360                         public void transfer(OutputStream os) throws IOException, APIException {
361                         }});
362                 client.send();
363                 queryParams = fragment = null;
364                 return client.futureReadString();
365         }
366
367         public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
368                 final String qp = setupParams(pathinfo);
369         
370                 EClient<CT> client = client();
371                 client.setMethod(GET);
372                 client.addHeader(ACCEPT, accept);
373                 
374                 for(int i=1;i<headers.length;i=i+2) {
375                         client.addHeader(headers[i-1],headers[i]);
376                 }
377                 client.setQueryParams(qp);
378                 client.setFragment(fragment);
379         
380                 client.setPathInfo(pathinfo);
381                 
382                 client.setPayload(null);
383                 client.send();
384                 queryParams = fragment = null;
385                 return client.futureReadString();
386         }
387
388         public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
389                 final String qp = setupParams(pathinfo);
390
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]);
396                 }
397                 client.setQueryParams(qp);
398                 client.setFragment(fragment);
399                 client.setPathInfo(pathinfo);
400                 
401                 client.setPayload(null);
402                 client.send();
403                 queryParams = fragment = null;
404                 return client.futureRead(df,type);
405         }
406
407         public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
408                 final String qp = setupParams(pathinfo);
409
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]);
415                 }
416                 client.setQueryParams(qp);
417                 client.setFragment(fragment);
418                 client.setPathInfo(pathinfo);
419                 
420                 client.setPayload(null);
421                 client.send();
422                 queryParams = fragment = null;
423                 return client.futureRead(df,type);
424         }
425
426         public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
427                 final String qp = setupParams(pathinfo);
428
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);
435                 
436                 client.setPayload(null);
437                 client.send();
438                 queryParams = fragment = null;
439                 return client.futureRead(df,type);
440         }
441
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);
444
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() {
452                         @Override
453                         public void transfer(OutputStream os) throws IOException, APIException {
454                                 df.newData().out(type).direct(t,os);
455                         }
456                 });
457                 client.send();
458                 queryParams = fragment = null;
459                 return client.future(t);
460         }
461         
462         public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
463                 final String qp = setupParams(pathinfo);
464
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() {
472                         @Override
473                         public void transfer(OutputStream os) throws IOException, APIException {
474                                 df.newData().out(type).direct(t,os);
475                         }
476                 });
477                 client.send();
478                 queryParams = fragment = null;
479                 return client.futureReadString();
480         }
481
482
483         public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
484                 final String qp = setupParams(pathinfo);
485
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() {
493                         @Override
494                         public void transfer(OutputStream os) throws IOException, APIException {
495                                 df.newData().out(type).direct(t,os);
496                         }
497                 });
498                 client.send();
499                 queryParams = fragment = null;
500                 return client.future(t);
501         }
502         
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);
505
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() {
513                         @Override
514                         public void transfer(OutputStream os) throws IOException, APIException {
515                                 df.newData().out(type).direct(t,os);
516                         }
517                 });
518                 client.send();
519                 queryParams = fragment = null;
520                 return client.future(t);
521         }
522
523         /**
524          * A method to update with a VOID
525          * @param pathinfo
526          * @param resp
527          * @param expected
528          * @return
529          * @throws APIException
530          * @throws CadiException
531          */
532         public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
533                 final String qp = setupParams(pathinfo);
534
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() {
542 //                      @Override
543 //                      public void transfer(OutputStream os) throws IOException, APIException {
544 //                      }
545 //              });
546                 client.send();
547                 queryParams = fragment = null;
548                 return client.future(null);
549         }
550
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);
553
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() {
561                         @Override
562                         public void transfer(OutputStream os) throws IOException, APIException {
563                                 df.newData().out(type).direct(t,os);
564                         }
565                 });
566                 client.send();
567                 queryParams = fragment = null;
568                 return client.future(t);
569         }
570
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);
573
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() {
581                         @Override
582                         public void transfer(OutputStream os) throws IOException, APIException {
583                                 df.newData().out(type).direct(t,os);
584                         }
585                 });
586                 client.send();
587                 queryParams = fragment = null;
588                 return client.future(t);
589         }
590
591         public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
592                 final String qp = setupParams(pathinfo);
593
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() {
601                         @Override
602                         public void transfer(OutputStream os) throws IOException, APIException {
603                                 df.newData().out(type).direct(t,os);
604                         }
605                 });
606
607                 client.send();
608                 queryParams = fragment = null;
609                 return client.future(t);
610         }
611
612
613         public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
614                 final String qp = setupParams(pathinfo);
615
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);
623                 client.send();
624                 queryParams = fragment = null;
625                 return client.future((T)null);
626         }
627
628         public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
629                 final String qp = setupParams(pathinfo);
630
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);
638                 client.send();
639                 queryParams = fragment = null;
640                 return client.future(null);
641         }
642
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();
645                 URI uri;
646                 try {
647                         uri = new URI(req.getRequestURI());
648                 } catch (Exception e) {
649                         throw new CadiException("Invalid incoming URI",e);
650                 }
651                 String name;
652                 for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
653                         name = en.nextElement();
654                         client.addHeader(name,req.getHeader(name));
655                 }
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() {
663                                 @Override
664                                 public void transfer(OutputStream os) throws IOException, APIException {
665                                         final ServletInputStream is = req.getInputStream();
666                                         int read;
667                                         // reuse Buffers
668                                         Pooled<byte[]> pbuff = buffPool.get();
669                                         try { 
670                                                 while((read=is.read(pbuff.content))>=0) {
671                                                         os.write(pbuff.content,0,read);
672                                                 }
673                                         } finally {
674                                                 pbuff.done();
675                                         }
676                                 }
677                         });
678                 }
679                 client.send();
680                 return client.future(resp, expected);
681         }
682
683         private String setupParams(String pathinfo) {
684                 final String qp;
685                 if(pathinfo==null) {
686                         qp=queryParams;
687                 } else {
688                         final int idx = pathinfo.indexOf('?');
689                         if(idx>=0) {
690                                 qp=pathinfo.substring(idx+1);
691                                 pathinfo=pathinfo.substring(0,idx);
692                         } else {
693                                 qp=queryParams;
694                         }
695                 }
696                 return qp;
697         }
698
699         public String toString() {
700                 return uri.toString();
701         }
702
703         /**
704          * @param queryParams the queryParams to set
705          * @return 
706          */
707         public Rcli<CT> setQueryParams(String queryParams) {
708                 this.queryParams = queryParams;
709                 return this;
710         }
711         
712
713         /**
714          * @param fragment the fragment to set
715          * @return 
716          */
717         public Rcli<CT> setFragment(String fragment) {
718                 this.fragment = fragment;
719                 return this;
720         }
721
722         public URI getURI() {
723                 return uri;
724         }
725
726 }