Update REST Samples for required behavior
[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 oneCallQueryParams;
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(final String pathinfo, final String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
136                 final ParsePath pp = new ParsePath(pathinfo);
137
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() {
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                 return client.futureCreate(df.getTypeClass());
152         }
153
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);
156
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() {
164                         @Override
165                         public void transfer(OutputStream os) throws IOException, APIException {
166                                 df.newData().out(type).direct(t,os);
167                         }
168                 });
169                 client.send();
170                 return client.futureCreate(df.getTypeClass());
171         }
172
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);
175
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() {
183                         @Override
184                         public void transfer(OutputStream os) throws IOException, APIException {
185                                 df.newData().out(type).direct(t,os);
186                         }
187                 });
188                 client.send();
189                 return client.futureCreate(df.getTypeClass());
190         }
191
192         public<T> Future<T> create(String pathinfo, Class<T> cls) throws APIException, CadiException {
193                 final ParsePath pp = new ParsePath(pathinfo);
194
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);
202                 client.send();
203                 return client.futureCreate(cls);
204         }
205
206         public Future<Void> create(String pathinfo, String contentType) throws APIException, CadiException {
207                 final ParsePath pp = new ParsePath(pathinfo);
208
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);
216                 client.send();
217                 return client.futureCreate(Void.class);
218         }
219
220
221         /**
222          * Post Data in WWW expected format, with the format tag1=value1&tag2=value2, etc
223          * Note Shortcut:
224          *   Because typically, you will want to have a variable as value, you can type, as long as tag ends with "="
225          *   postForm(..., "tag1=value1","tag2=",var2);
226          * @param pathinfo
227          * @param df
228          * @param cls
229          * @param formParam
230          * @return
231          * @throws APIException
232          * @throws CadiException
233          */
234         public <T> Future<T> postForm(String pathinfo, final RosettaDF<T> df, final String ... formParam) throws APIException, CadiException {
235                 final ParsePath pp = new ParsePath(pathinfo);
236
237                 EClient<CT> client = client();
238                 client.setMethod(POST);
239                 client.addHeader(CONTENT_TYPE,FORM_ENCODED);
240                 switch(type) {
241                         case JSON:
242                                 client.addHeader(ACCEPT, APPL_JSON);
243                                 break;
244                         case XML:
245                                 client.addHeader(ACCEPT, APPL_XML);
246                                 break;
247                         default:
248                                 break;
249                 }
250                 client.setPathInfo(pp.path());
251                 client.setQueryParams(pp.query());
252                 client.setFragment(pp.frag());
253                 client.setPayload(new Transfer() {
254                         @Override
255                         public void transfer(OutputStream os) throws IOException, APIException {
256                                 PrintStream ps;
257                                 if(os instanceof PrintStream) {
258                                         ps = (PrintStream)os;
259                                 } else {
260                                         ps = new PrintStream(os);
261                                 }
262                                 boolean first = true;
263                                 for(String fp : formParam) {
264                                         if(fp!=null) {
265                                                 if(first) {
266                                                         first = false;
267                                                 } else {
268                                                         ps.print('&');
269                                                 }
270                                                 if(fp.endsWith("=")) {
271                                                         first = true;
272                                                 }
273                                                 ps.print(fp);
274                                         }
275                                 }
276                         }});
277                 client.send();
278                 return client.futureRead(df,TYPE.JSON);
279         }
280
281         /**
282          * Read String, using POST for keyInfo
283          * 
284          * @param pathinfo
285          * @param df
286          * @param t
287          * @param resp
288          * @return
289          * @throws APIException
290          * @throws CadiException
291          */
292         public<T> Future<String> readPost(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
293                 final ParsePath pp = new ParsePath(pathinfo);
294
295                 EClient<CT> client = client();
296                 client.setMethod(POST);
297                 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
298                 client.setPathInfo(pp.path());
299                 client.setQueryParams(pp.query());
300                 client.setFragment(pp.frag());
301                 client.setPayload(new EClient.Transfer() {
302                         @Override
303                         public void transfer(OutputStream os) throws IOException, APIException {
304                                 df.newData().out(type).direct(t,os);
305                         }
306                 });
307                 client.send();
308                 return client.futureReadString();
309         }
310
311         /**
312          * Read using POST for keyInfo, responding with marshaled Objects
313          *
314          * @param pathinfo
315          * @param df
316          * @param t
317          * @param resp
318          * @return
319          * @throws APIException
320          * @throws CadiException
321          */
322         public<T,R> Future<R> readPost(String pathinfo, final RosettaDF<T> df, final T t, final RosettaDF<R> resp) throws APIException, CadiException {
323                 final ParsePath pp = new ParsePath(pathinfo);
324                 
325                 EClient<CT> client = client();
326                 client.setMethod(POST);
327                 client.addHeader(CONTENT_TYPE,typeString(df.getTypeClass()));
328                 client.setPathInfo(pp.path());
329                 client.setQueryParams(pp.query());
330                 client.setFragment(pp.frag());
331                 client.setPayload(new EClient.Transfer() {
332                         @Override
333                         public void transfer(OutputStream os) throws IOException, APIException {
334                                 df.newData().out(type).direct(t,os);
335                         }
336                 });
337                 client.send();
338                 return client.futureRead(resp,resp.getOutType());
339         }
340
341         public Future<String> readPost(String pathinfo, String contentType, String ... headers) throws CadiException, APIException {
342                 final ParsePath pp = new ParsePath(pathinfo);
343
344                 EClient<CT> client = client();
345                 client.setMethod(POST);
346                 client.addHeader(CONTENT_TYPE,contentType);
347                 client.setPathInfo(pp.path());
348                 client.setQueryParams(pp.query());
349                 client.setFragment(pp.frag());
350                 client.setPayload(new EClient.Transfer() {
351                         @Override
352                         public void transfer(OutputStream os) throws IOException, APIException {
353                         }});
354                 client.send();
355                 return client.futureReadString();
356         }
357
358         public Future<String> read(String pathinfo, String accept, String ... headers) throws APIException, CadiException {
359                 final ParsePath pp = new ParsePath(pathinfo);
360         
361                 EClient<CT> client = client();
362                 client.setMethod(GET);
363                 client.addHeader(ACCEPT, accept);
364                 
365                 for(int i=1;i<headers.length;i=i+2) {
366                         client.addHeader(headers[i-1],headers[i]);
367                 }
368                 client.setPathInfo(pp.path());
369                 client.setQueryParams(pp.query());
370                 client.setFragment(pp.frag());
371                 client.setPayload(null);
372                 client.send();
373                 return client.futureReadString();
374         }
375
376         public<T> Future<T> read(String pathinfo, String accept, RosettaDF<T> df, String ... headers) throws APIException, CadiException {
377                 final ParsePath pp = new ParsePath(pathinfo);
378
379                 EClient<CT> client = client();
380                 client.setMethod(GET);
381                 client.addHeader(ACCEPT, accept);
382                 for(int i=1;i<headers.length;i=i+2) {
383                         client.addHeader(headers[i-1],headers[i]);
384                 }
385                 client.setPathInfo(pp.path());
386                 client.setQueryParams(pp.query());
387                 client.setFragment(pp.frag());
388                 client.setPayload(null);
389                 client.send();
390                 return client.futureRead(df,type);
391         }
392
393         public<T> Future<T> read(String pathinfo, RosettaDF<T> df,String ... headers) throws APIException, CadiException {
394                 final ParsePath pp = new ParsePath(pathinfo);
395
396                 EClient<CT> client = client();
397                 client.setMethod(GET);
398                 client.addHeader(ACCEPT, typeString(df.getTypeClass()));
399                 for(int i=1;i<headers.length;i=i+2) {
400                         client.addHeader(headers[i-1],headers[i]);
401                 }
402                 client.setPathInfo(pp.path());
403                 client.setQueryParams(pp.query());
404                 client.setFragment(pp.frag());
405                 
406                 client.setPayload(null);
407                 client.send();
408                 return client.futureRead(df,type);
409         }
410
411         public<T> Future<T> read(String pathinfo, Class<?> cls, RosettaDF<T> df) throws APIException, CadiException {
412                 final ParsePath pp = new ParsePath(pathinfo);
413
414                 EClient<CT> client = client();
415                 client.setMethod(GET);
416                 client.addHeader(ACCEPT, typeString(cls));
417                 client.setPathInfo(pp.path());
418                 client.setQueryParams(pp.query());
419                 client.setFragment(pp.frag());          
420
421                 client.setPayload(null);
422                 client.send();
423                 return client.futureRead(df,type);
424         }
425
426         public<T> Future<T> update(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
427                 final ParsePath pp = new ParsePath(pathinfo);
428
429                 EClient<CT> client = client();
430                 client.setMethod(PUT);
431                 client.addHeader(CONTENT_TYPE,contentType);
432                 client.setPathInfo(pp.path());
433                 client.setQueryParams(pp.query());
434                 client.setFragment(pp.frag());          
435                 client.setPayload(new EClient.Transfer() {
436                         @Override
437                         public void transfer(OutputStream os) throws IOException, APIException {
438                                 df.newData().out(type).direct(t,os);
439                         }
440                 });
441                 client.send();
442                 return client.future(t);
443         }
444         
445         public<T> Future<String> updateRespondString(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
446                 final ParsePath pp = new ParsePath(pathinfo);
447                 
448                 EClient<CT> client = client();
449                 client.setMethod(PUT);
450                 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
451                 client.setPathInfo(pp.path());
452                 client.setQueryParams(pp.query());
453                 client.setFragment(pp.frag());          
454
455                 client.setPayload(new EClient.Transfer() {
456                         @Override
457                         public void transfer(OutputStream os) throws IOException, APIException {
458                                 df.newData().out(type).direct(t,os);
459                         }
460                 });
461                 client.send();
462                 return client.futureReadString();
463         }
464
465
466         public<T> Future<T> update(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
467                 final ParsePath pp = new ParsePath(pathinfo);
468
469                 EClient<CT> client = client();
470                 client.setMethod(PUT);
471                 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
472                 client.setPathInfo(pp.path());
473                 client.setQueryParams(pp.query());
474                 client.setFragment(pp.frag());  
475                 
476                 client.setPayload(new EClient.Transfer() {
477                         @Override
478                         public void transfer(OutputStream os) throws IOException, APIException {
479                                 df.newData().out(type).direct(t,os);
480                         }
481                 });
482                 client.send();
483                 return client.future(t);
484         }
485         
486         public<T> Future<T> update(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
487                 final ParsePath pp = new ParsePath(pathinfo);
488                 
489                 EClient<CT> client = client();
490                 client.setMethod(PUT);
491                 client.addHeader(CONTENT_TYPE, typeString(cls));
492                 client.setPathInfo(pp.path());
493                 client.setQueryParams(pp.query());
494                 client.setFragment(pp.frag());  
495
496                 client.setPayload(new EClient.Transfer() {
497                         @Override
498                         public void transfer(OutputStream os) throws IOException, APIException {
499                                 df.newData().out(type).direct(t,os);
500                         }
501                 });
502                 client.send();
503                 return client.future(t);
504         }
505
506         /**
507          * A method to update with a VOID
508          * @param pathinfo
509          * @param resp
510          * @param expected
511          * @return
512          * @throws APIException
513          * @throws CadiException
514          */
515         public<T> Future<Void> update(String pathinfo) throws APIException, CadiException {
516                 final ParsePath pp = new ParsePath(pathinfo);
517
518                 EClient<CT> client = client();
519                 client.setMethod(PUT);
520                 client.addHeader(CONTENT_TYPE, typeString(Void.class));
521                 client.setPathInfo(pp.path());
522                 client.setQueryParams(pp.query());
523                 client.setFragment(pp.frag());  
524
525 //              client.setPayload(new EClient.Transfer() {
526 //                      @Override
527 //                      public void transfer(OutputStream os) throws IOException, APIException {
528 //                      }
529 //              });
530                 client.send();
531                 return client.future(null);
532         }
533
534         public<T> Future<T> delete(String pathinfo, String contentType, final RosettaDF<T> df, final T t) throws APIException, CadiException {
535                 final ParsePath pp = new ParsePath(pathinfo);
536
537                 EClient<CT> client = client();
538                 client.setMethod(DELETE);
539                 client.addHeader(CONTENT_TYPE, contentType);
540                 client.setPathInfo(pp.path());
541                 client.setQueryParams(pp.query());
542                 client.setFragment(pp.frag());  
543
544                 client.setPayload(new EClient.Transfer() {
545                         @Override
546                         public void transfer(OutputStream os) throws IOException, APIException {
547                                 df.newData().out(type).direct(t,os);
548                         }
549                 });
550                 client.send();
551                 return client.future(t);
552         }
553
554         public<T> Future<T> delete(String pathinfo, Class<?> cls, final RosettaDF<T> df, final T t) throws APIException, CadiException {
555                 final ParsePath pp = new ParsePath(pathinfo);
556
557                 EClient<CT> client = client();
558                 client.setMethod(DELETE);
559                 client.addHeader(CONTENT_TYPE, typeString(cls));
560                 client.setPathInfo(pp.path());
561                 client.setQueryParams(pp.query());
562                 client.setFragment(pp.frag());  
563                 client.setPayload(new EClient.Transfer() {
564                         @Override
565                         public void transfer(OutputStream os) throws IOException, APIException {
566                                 df.newData().out(type).direct(t,os);
567                         }
568                 });
569                 client.send();
570                 return client.future(t);
571         }
572
573         public<T> Future<T> delete(String pathinfo, final RosettaDF<T> df, final T t) throws APIException, CadiException {
574                 final ParsePath pp = new ParsePath(pathinfo);
575
576                 EClient<CT> client = client();
577                 client.setMethod(DELETE);
578                 client.addHeader(CONTENT_TYPE, typeString(df.getTypeClass()));
579                 client.setPathInfo(pp.path());
580                 client.setQueryParams(pp.query());
581                 client.setFragment(pp.frag());  
582                 client.setPayload(new EClient.Transfer() {
583                         @Override
584                         public void transfer(OutputStream os) throws IOException, APIException {
585                                 df.newData().out(type).direct(t,os);
586                         }
587                 });
588
589                 client.send();
590                 return client.future(t);
591         }
592
593
594         public<T> Future<T> delete(String pathinfo, Class<T> cls) throws APIException, CadiException {
595                 final ParsePath pp = new ParsePath(pathinfo);
596
597                 EClient<CT> client = client();
598                 client.setMethod(DELETE);
599                 client.addHeader(CONTENT_TYPE, typeString(cls));
600                 client.setPathInfo(pp.path());
601                 client.setQueryParams(pp.query());
602                 client.setFragment(pp.frag());  
603
604                 client.setPayload(null);
605                 client.send();
606                 return client.future((T)null);
607         }
608
609         public Future<Void> delete(String pathinfo, String contentType) throws APIException, CadiException {
610                 final ParsePath pp = new ParsePath(pathinfo);
611
612                 EClient<CT> client = client();
613                 client.setMethod(DELETE);
614                 client.addHeader(CONTENT_TYPE, contentType);
615                 client.setPathInfo(pp.path());
616                 client.setQueryParams(pp.query());
617                 client.setFragment(pp.frag());  
618
619                 client.setPayload(null);
620                 client.send();
621                 return client.future(null);
622         }
623
624         public Future<Void> transfer(final HttpServletRequest req, final HttpServletResponse resp, final String pathParam, final int expected) throws CadiException, APIException {
625                 EClient<CT> client = client();
626                 URI uri;
627                 try {
628                         uri = new URI(req.getRequestURI());
629                 } catch (Exception e) {
630                         throw new CadiException("Invalid incoming URI",e);
631                 }
632                 String name;
633                 for(Enumeration<String> en = req.getHeaderNames();en.hasMoreElements();) {
634                         name = en.nextElement();
635                         client.addHeader(name,req.getHeader(name));
636                 }
637                 client.setQueryParams(req.getQueryString());
638                 client.setFragment(uri.getFragment());
639                 client.setPathInfo(pathParam);
640                 String meth = req.getMethod();
641                 client.setMethod(meth);
642                 if(!"GET".equals(meth)) {
643                         client.setPayload(new EClient.Transfer() {
644                                 @Override
645                                 public void transfer(OutputStream os) throws IOException, APIException {
646                                         final ServletInputStream is = req.getInputStream();
647                                         int read;
648                                         // reuse Buffers
649                                         Pooled<byte[]> pbuff = buffPool.get();
650                                         try { 
651                                                 while((read=is.read(pbuff.content))>=0) {
652                                                         os.write(pbuff.content,0,read);
653                                                 }
654                                         } finally {
655                                                 pbuff.done();
656                                         }
657                                 }
658                         });
659                 }
660                 client.send();
661                 return client.future(resp, expected);
662         }
663
664         private class ParsePath {
665                 private final String path;
666                 private final int query;
667                 private final int queryEnd;
668                 private final int pound;
669                 private final String queryParams;
670
671                 public ParsePath(final String origPath) {
672                         path = origPath;
673                         if(origPath==null) {
674                                 query=queryEnd=pound=-1;
675                                 queryParams=null;
676                         } else {
677                                 query = origPath.indexOf('?');
678                                 pound = origPath.indexOf('#');
679                                 queryEnd = pound>=0?pound:path.length();
680                                 if(oneCallQueryParams==null) {
681                                         if(query>=0) {
682                                                 queryParams = path.substring(query+1,queryEnd); 
683                                         } else {
684                                                 queryParams=null;
685                                         }
686                                 } else {
687                                         if(query>=0) {
688                                                 queryParams = oneCallQueryParams + '&' + path.substring(query+1,queryEnd); 
689                                         } else {
690                                                 queryParams = oneCallQueryParams;
691                                         }
692                                         oneCallQueryParams = null;
693                                 }
694                         }
695                 }
696                 
697                 public String path() {
698                         if(query>=0) {
699                                 if(pound>=0) {
700                                         return path.substring(pound+1);
701                                 }
702                                 return path.substring(0,query);
703                         } else if(pound>=0) {
704                                 return path.substring(0,pound);
705                         } else {
706                                 return path;
707                         }
708                 }
709                 
710                 public String query() {
711                         return queryParams;
712                 }
713                 
714                 public String frag() {
715                         if(pound>=0) {
716                                 return path.substring(pound+1);
717                         } else {
718                                 return null;
719                         }
720                 }
721         }
722
723         public String toString() {
724                 return uri.toString();
725         }
726
727         public URI getURI() {
728                 return uri;
729         }
730
731         public void setQueryParams(final String queryParams) {
732                 oneCallQueryParams=queryParams;
733         }
734
735 }