2020import java .net .CookieManager ;
2121import java .net .HttpCookie ;
2222import java .net .HttpURLConnection ;
23+ import java .net .URI ;
24+ import java .net .URISyntaxException ;
2325import java .net .URL ;
2426import java .net .URLEncoder ;
2527import java .nio .charset .Charset ;
3032public class JsonServiceClient implements ServiceClient {
3133 static Charset UTF8 = Charset .forName ("UTF-8" );
3234 String baseUrl ;
35+ URI baseUri ;
3336 String replyUrl ;
3437
3538 boolean alwaysSendBasicAuthHeaders ;
3639 String userName ;
3740 String password ;
41+ String bearerToken ;
3842
3943 Integer timeoutMs ;
4044 public ConnectionFilter RequestFilter ;
@@ -47,8 +51,16 @@ public class JsonServiceClient implements ServiceClient {
4751 Gson gson ;
4852
4953 public JsonServiceClient (String baseUrl ) {
54+ this (baseUrl , true );
55+ }
56+ public JsonServiceClient (String baseUrl , boolean initCookies ) {
5057 setBaseUrl (baseUrl );
58+ if (initCookies ) {
59+ initCookieHandler ();
60+ }
61+ }
5162
63+ public void initCookieHandler () {
5264 //Automatically populate response cookies
5365 if (CookieHandler .getDefault () == null ){
5466 CookieHandler .setDefault (new CookieManager ());
@@ -57,6 +69,11 @@ public JsonServiceClient(String baseUrl) {
5769
5870 public void setBaseUrl (String baseUrl ) {
5971 this .baseUrl = baseUrl .endsWith ("/" ) ? baseUrl : baseUrl + "/" ;
72+ try {
73+ this .baseUri = new URI (this .baseUrl );
74+ } catch (URISyntaxException e ) {
75+ throw new RuntimeException (e );
76+ }
6077 this .replyUrl = this .baseUrl + "json/reply/" ;
6178 }
6279
@@ -66,13 +83,13 @@ public void setTimeout(int timeoutMs) {
6683
6784 public GsonBuilder getGsonBuilder () {
6885 return new GsonBuilder ()
69- .registerTypeAdapterFactory (JsonSerializers .getCaseInsensitiveEnumTypeAdapterFactory ())
70- .registerTypeAdapter (Date .class , JsonSerializers .getDateSerializer ())
71- .registerTypeAdapter (Date .class , JsonSerializers .getDateDeserializer ())
72- .registerTypeAdapter (TimeSpan .class , JsonSerializers .getTimeSpanSerializer ())
73- .registerTypeAdapter (TimeSpan .class , JsonSerializers .getTimeSpanDeserializer ())
74- .registerTypeAdapter (UUID .class , JsonSerializers .getGuidSerializer ())
75- .registerTypeAdapter (UUID .class , JsonSerializers .getGuidDeserializer ());
86+ .registerTypeAdapterFactory (JsonSerializers .getCaseInsensitiveEnumTypeAdapterFactory ())
87+ .registerTypeAdapter (Date .class , JsonSerializers .getDateSerializer ())
88+ .registerTypeAdapter (Date .class , JsonSerializers .getDateDeserializer ())
89+ .registerTypeAdapter (TimeSpan .class , JsonSerializers .getTimeSpanSerializer ())
90+ .registerTypeAdapter (TimeSpan .class , JsonSerializers .getTimeSpanDeserializer ())
91+ .registerTypeAdapter (UUID .class , JsonSerializers .getGuidSerializer ())
92+ .registerTypeAdapter (UUID .class , JsonSerializers .getGuidDeserializer ());
7693 }
7794
7895 public Gson getGson () {
@@ -137,10 +154,10 @@ public String createUrl(Object requestDto, Map<String,String> query){
137154 }
138155
139156 public HttpURLConnection createRequest (String requestUrl , String httpMethod , byte [] requestBody , String requestType ) {
140- return createRequest (requestUrl , httpMethod , requestBody , requestType , false );
141-
157+ return createRequest (requestUrl , httpMethod , requestBody , requestType , false );
158+
142159 }
143-
160+
144161 public HttpURLConnection createRequest (String requestUrl , String httpMethod , byte [] requestBody , String requestType , Boolean forceAuthentication ) {
145162 try {
146163 URL url = new URL (requestUrl );
@@ -159,8 +176,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt
159176 req .setRequestProperty (HttpHeaders .ContentType , requestType );
160177 }
161178
162- if (forceAuthentication || alwaysSendBasicAuthHeaders ) {
163- addBasicAuth (req , userName , password );
179+ if (bearerToken != null ) {
180+ req .setRequestProperty (HttpHeaders .Authorization , "Bearer " + bearerToken );
181+ req .setRequestProperty ("X-Auth" , "Bearer" ); // HttpURLConnection doesn't allow re-reading Authorization Header
182+ } else if (forceAuthentication || alwaysSendBasicAuthHeaders ) {
183+ req .setRequestProperty (HttpHeaders .Authorization , "Basic " + Utils .toBase64String (userName + ":" + password ));
184+ req .setRequestProperty ("X-Auth" , "Basic" ); // HttpURLConnection doesn't allow re-reading Authorization Header
164185 }
165186
166187 if (RequestFilter != null ) {
@@ -187,18 +208,12 @@ public HttpURLConnection createRequest(String requestUrl, String httpMethod, byt
187208 }
188209 }
189210
190- private static void addBasicAuth (HttpURLConnection req , String userName , String password ) {
191- req .setRequestProperty (HttpHeaders .Authorization ,
192- "Basic " + Utils .toBase64String (userName + ":" + password ));
193- req .setRequestProperty ("X-Auth" , "Basic" ); // HttpURLConnection doesn't allow re-reading Authorization Header
194- }
195-
196211 private static boolean shouldAuthenticate (HttpURLConnection req , String userName , String password ){
197212 try {
198213 return req .getResponseCode () == 401
199- && req .getRequestProperty ("X-Auth" ) == null //only auth if auth never attempted
200- && userName != null
201- && password != null ;
214+ && req .getRequestProperty ("X-Auth" ) == null //only auth if auth never attempted
215+ && userName != null
216+ && password != null ;
202217 } catch (IOException e ) {
203218 return false ;
204219 }
@@ -211,8 +226,8 @@ public static RuntimeException createException(HttpURLConnection res, int respon
211226 InputStream errorStream = res .getErrorStream ();
212227
213228 String responseBody = errorStream != null
214- ? Utils .readToEnd (errorStream , UTF8 .name ())
215- : null ;
229+ ? Utils .readToEnd (errorStream , UTF8 .name ())
230+ : null ;
216231
217232 webEx = new WebServiceException (responseCode , res .getResponseMessage (), responseBody );
218233
@@ -243,16 +258,16 @@ public static RuntimeException createException(HttpURLConnection res, int respon
243258 public static String GetSendMethod (Object request )
244259 {
245260 return request instanceof IGet ?
246- HttpMethods .Get
247- : request instanceof IPost ?
248- HttpMethods .Post
249- : request instanceof IPut ?
250- HttpMethods .Put
251- : request instanceof IDelete ?
252- HttpMethods .Delete
253- : request instanceof IPatch ?
254- HttpMethods .Patch :
255- HttpMethods .Post ;
261+ HttpMethods .Get
262+ : request instanceof IPost ?
263+ HttpMethods .Post
264+ : request instanceof IPut ?
265+ HttpMethods .Put
266+ : request instanceof IDelete ?
267+ HttpMethods .Delete
268+ : request instanceof IPatch ?
269+ HttpMethods .Patch :
270+ HttpMethods .Post ;
256271 }
257272
258273 public static boolean hasRequestBody (String httpMethod )
@@ -278,6 +293,21 @@ public void setAlwaysSendBasicAuthHeaders(boolean value) {
278293 this .alwaysSendBasicAuthHeaders = value ;
279294 }
280295
296+ @ Override
297+ public void setBearerToken (String bearerToken ) {
298+ this .bearerToken = bearerToken ;
299+ }
300+
301+ @ Override
302+ public String getBearerToken () {
303+ return bearerToken ;
304+ }
305+
306+ @ Override
307+ public void setTokenCookie (String value ) {
308+ setCookie ("ss-tok" , value , (long ) (365 * 24 * 60 * 60 )); //1 year
309+ }
310+
281311 @ Override
282312 public void setCredentials (String userName , String password ) {
283313 this .userName = userName ;
@@ -303,7 +333,7 @@ public <TResponse> TResponse send(IReturn<TResponse> request) {
303333 public void send (IReturnVoid request ) {
304334 String httpMethod = GetSendMethod (request );
305335 send (Utils .combinePath (replyUrl , typeName (request )), httpMethod , request ,
306- IReturnVoid .class );
336+ IReturnVoid .class );
307337 }
308338
309339 public <TResponse > TResponse send (String url , String httpMethod , Object responseClass ) {
@@ -343,7 +373,7 @@ public <TResponse> TResponse send(String requestUrl, String httpMethod, byte[] r
343373 if (shouldAuthenticate (req , userName , password )){
344374 req .disconnect ();
345375 req = createRequest (requestUrl , httpMethod , requestBody , requestType , true );
346-
376+
347377 success = req .getResponseCode () < 400 ;
348378 }
349379
@@ -384,16 +414,16 @@ public <TResponse> TResponse send(String requestUrl, String httpMethod, byte[] r
384414 Log .d (json );
385415
386416 TResponse response = resClass != null
387- ? (TResponse ) getGson ().fromJson (json , resClass )
388- : (TResponse ) getGson ().fromJson (json , resType );
417+ ? (TResponse ) getGson ().fromJson (json , resClass )
418+ : (TResponse ) getGson ().fromJson (json , resType );
389419
390420 return response ;
391421 }
392422 else {
393423 BufferedReader reader = new BufferedReader (new InputStreamReader (is ));
394424 TResponse response = resClass != null
395- ? (TResponse ) getGson ().fromJson (reader , resClass )
396- : (TResponse ) getGson ().fromJson (reader , resType );
425+ ? (TResponse ) getGson ().fromJson (reader , resClass )
426+ : (TResponse ) getGson ().fromJson (reader , resType );
397427
398428 Utils .closeQuietly (reader );
399429 return response ;
@@ -413,9 +443,9 @@ static String typeName(Object o){
413443
414444 private String resolveUrl (String relativeOrAbsoluteUrl ) {
415445 return relativeOrAbsoluteUrl .startsWith ("http:" )
416- || relativeOrAbsoluteUrl .startsWith ("https:" )
417- ? relativeOrAbsoluteUrl
418- : Utils .combinePath (baseUrl , relativeOrAbsoluteUrl );
446+ || relativeOrAbsoluteUrl .startsWith ("https:" )
447+ ? relativeOrAbsoluteUrl
448+ : Utils .combinePath (baseUrl , relativeOrAbsoluteUrl );
419449 }
420450
421451 @ Override
@@ -451,8 +481,8 @@ public HttpURLConnection get(String path) {
451481 @ Override
452482 public <TResponse > TResponse post (IReturn <TResponse > request ) {
453483 return send (
454- Utils .combinePath (replyUrl , typeName (request )), HttpMethods .Post , request ,
455- request .getResponseType ());
484+ Utils .combinePath (replyUrl , typeName (request )), HttpMethods .Post , request ,
485+ request .getResponseType ());
456486 }
457487
458488 @ Override
@@ -488,14 +518,14 @@ public HttpURLConnection post(String path, byte[] requestBody, String contentTyp
488518 @ Override
489519 public <TResponse > TResponse put (IReturn <TResponse > request ) {
490520 return send (
491- Utils .combinePath (replyUrl , typeName (request )), HttpMethods .Put , request ,
492- request .getResponseType ());
521+ Utils .combinePath (replyUrl , typeName (request )), HttpMethods .Put , request ,
522+ request .getResponseType ());
493523 }
494524
495525 @ Override
496526 public void put (IReturnVoid request ) {
497527 send (Utils .combinePath (replyUrl , typeName (request )), HttpMethods .Put , request ,
498- IReturnVoid .class );
528+ IReturnVoid .class );
499529 }
500530
501531 @ Override
@@ -562,10 +592,11 @@ public void setCookie(String name, String value) {
562592 public void setCookie (String name , String value , Long expiresInSecs ) {
563593 CookieManager cookieManager = (CookieManager ) CookieHandler .getDefault ();
564594 HttpCookie cookie = new HttpCookie (name , value );
595+ cookie .setVersion (0 ); // Required otherwise it quotes values https://stackoverflow.com/a/20204076/85785
565596 if (expiresInSecs != null ){
566597 cookie .setMaxAge (expiresInSecs );
567598 }
568- cookieManager .getCookieStore ().getCookies (). add (cookie );
599+ cookieManager .getCookieStore ().add (baseUri , cookie );
569600 }
570601
571602 @ Override
0 commit comments