31
31
import org .json .JSONObject ;
32
32
import org .json .JSONTokener ;
33
33
34
+ import java .io .ByteArrayOutputStream ;
34
35
import java .io .IOException ;
35
36
import java .io .InputStream ;
36
37
import java .io .InputStreamReader ;
@@ -64,11 +65,12 @@ abstract class BaseAPIClient {
64
65
65
66
/**
66
67
* Algolia Search initialization
68
+ *
67
69
* @param applicationID the application ID you have in your admin interface
68
- * @param apiKey a valid API key for the service
69
- * @param hostsArray the list of hosts that you have received for the service
70
- * @param enableDsn set to true if your account has the Distributed Search Option
71
- * @param dsnHost override the automatic computation of dsn hostname
70
+ * @param apiKey a valid API key for the service
71
+ * @param hostsArray the list of hosts that you have received for the service
72
+ * @param enableDsn set to true if your account has the Distributed Search Option
73
+ * @param dsnHost override the automatic computation of dsn hostname
72
74
*/
73
75
protected BaseAPIClient (String applicationID , String apiKey , List <String > hostsArray , boolean enableDsn , String dsnHost ) {
74
76
if (applicationID == null || applicationID .length () == 0 ) {
@@ -103,8 +105,9 @@ public void setExtraHeader(String key, String value) {
103
105
104
106
/**
105
107
* Allow to set timeout
108
+ *
106
109
* @param connectTimeout connection timeout in MS
107
- * @param readTimeout socket timeout in MS
110
+ * @param readTimeout socket timeout in MS
108
111
*/
109
112
public void setTimeout (int connectTimeout , int readTimeout ) {
110
113
httpSocketTimeoutMS = readTimeout ;
@@ -113,9 +116,10 @@ public void setTimeout(int connectTimeout, int readTimeout) {
113
116
114
117
/**
115
118
* Allow to set timeout
119
+ *
116
120
* @param connectTimeout connection timeout in MS
117
- * @param readTimeout socket timeout in MS
118
- * @param searchTimeout socket timeout in MS
121
+ * @param readTimeout socket timeout in MS
122
+ * @param searchTimeout socket timeout in MS
119
123
*/
120
124
public void setTimeout (int connectTimeout , int readTimeout , int searchTimeout ) {
121
125
httpSocketTimeoutMS = readTimeout ;
@@ -133,7 +137,8 @@ public void setUserToken(String userToken) {
133
137
134
138
/**
135
139
* List all existing indexes
136
- * return an JSON Object in the form:
140
+ *
141
+ * @return a JSON Object in the form:
137
142
* { "items": [ {"name": "contacts", "createdAt": "2013-01-18T15:33:13.556Z"},
138
143
* {"name": "notes", "createdAt": "2013-01-18T15:33:13.556Z"}]}
139
144
*/
@@ -145,7 +150,7 @@ protected JSONObject listIndexes() throws AlgoliaException {
145
150
* Delete an index
146
151
*
147
152
* @param indexName the name of index to delete
148
- * return an object containing a "deletedAt" attribute
153
+ * @ return an object containing a "deletedAt" attribute
149
154
*/
150
155
protected JSONObject deleteIndex (String indexName ) throws AlgoliaException {
151
156
try {
@@ -157,6 +162,7 @@ protected JSONObject deleteIndex(String indexName) throws AlgoliaException {
157
162
158
163
/**
159
164
* Move an existing index.
165
+ *
160
166
* @param srcIndexName the name of index to copy.
161
167
* @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
162
168
*/
@@ -175,6 +181,7 @@ protected JSONObject moveIndex(String srcIndexName, String dstIndexName) throws
175
181
176
182
/**
177
183
* Copy an existing index.
184
+ *
178
185
* @param srcIndexName the name of index to copy.
179
186
* @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
180
187
*/
@@ -193,8 +200,9 @@ protected JSONObject copyIndex(String srcIndexName, String dstIndexName) throws
193
200
194
201
/**
195
202
* Return last logs entries.
196
- * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry).
197
- * @param length Specify the maximum number of entries to retrieve starting at offset. Maximum allowed value: 1000.
203
+ *
204
+ * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry).
205
+ * @param length Specify the maximum number of entries to retrieve starting at offset. Maximum allowed value: 1000.
198
206
* @param logType Specify the type of log to retrieve
199
207
*/
200
208
protected JSONObject getLogs (int offset , int length , LogType logType ) throws AlgoliaException {
@@ -285,7 +293,7 @@ protected JSONObject multipleQueries(List<IndexQuery> queries, String strategy)
285
293
* Custom batch
286
294
*
287
295
* @param actions the array of actions
288
- * @throws AlgoliaException
296
+ * @throws AlgoliaException if the response is not valid json
289
297
*/
290
298
protected JSONObject batch (JSONArray actions ) throws AlgoliaException {
291
299
try {
@@ -301,6 +309,10 @@ private enum Method {
301
309
GET , POST , PUT , DELETE
302
310
}
303
311
312
+ protected byte [] getRequestRaw (String url , boolean search ) throws AlgoliaException {
313
+ return _requestRaw (Method .GET , url , null , readHostsArray , httpConnectTimeoutMS , search ? httpSearchTimeoutMS : httpSocketTimeoutMS );
314
+ }
315
+
304
316
protected JSONObject getRequest (String url , boolean search ) throws AlgoliaException {
305
317
return _request (Method .GET , url , null , readHostsArray , httpConnectTimeoutMS , search ? httpSearchTimeoutMS : httpSocketTimeoutMS );
306
318
}
@@ -317,9 +329,16 @@ protected JSONObject putRequest(String url, String obj) throws AlgoliaException
317
329
return _request (Method .PUT , url , obj , writeHostsArray , httpConnectTimeoutMS , httpSocketTimeoutMS );
318
330
}
319
331
320
- private String _getAnswer (InputStream istream ) throws IOException {
321
- InputStreamReader is = new InputStreamReader (istream , "UTF-8" );
322
- StringBuilder builder = new StringBuilder ();
332
+ /**
333
+ * Reads the InputStream as UTF-8
334
+ *
335
+ * @param stream the InputStream to read
336
+ * @return the stream's content as a String
337
+ * @throws IOException if the stream can't be read, decoded as UTF-8 or closed
338
+ */
339
+ private String _toCharArray (InputStream stream ) throws IOException {
340
+ InputStreamReader is = new InputStreamReader (stream , "UTF-8" );
341
+ StringBuilder builder = new StringBuilder ();
323
342
char [] buf = new char [1000 ];
324
343
int l = 0 ;
325
344
while (l >= 0 ) {
@@ -330,15 +349,77 @@ private String _getAnswer(InputStream istream) throws IOException {
330
349
return builder .toString ();
331
350
}
332
351
352
+ /**
353
+ * Reads the InputStream into a byte array
354
+ * @param stream the InputStream to read
355
+ * @return the stream's content as a byte[]
356
+ * @throws AlgoliaException if the stream can't be read or flushed
357
+ */
358
+ private byte [] _toByteArray (InputStream stream ) throws AlgoliaException {
359
+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
360
+ int read ;
361
+ byte [] buffer = new byte [1024 ];
362
+
363
+ try {
364
+ while ((read = stream .read (buffer , 0 , buffer .length )) != -1 ) {
365
+ out .write (buffer , 0 , read );
366
+ }
367
+
368
+ out .flush ();
369
+ return out .toByteArray ();
370
+ } catch (IOException e ) {
371
+ throw new AlgoliaException ("Error while reading stream: " + e .getMessage ());
372
+ }
373
+ }
374
+
375
+
333
376
private JSONObject _getJSONObject (String input ) throws JSONException {
334
377
return new JSONObject (new JSONTokener (input ));
335
378
}
336
379
337
- private JSONObject _getAnswerObject ( InputStream istream ) throws IOException , JSONException {
338
- return _getJSONObject ( _getAnswer ( istream ));
380
+ private JSONObject _getJSONObject ( byte [] array ) throws JSONException , UnsupportedEncodingException {
381
+ return new JSONObject ( new String ( array , "UTF-8" ));
339
382
}
340
383
384
+ private JSONObject _getAnswerJSONObject (InputStream istream ) throws IOException , JSONException {
385
+ return _getJSONObject (_toCharArray (istream ));
386
+ }
387
+
388
+ /**
389
+ * Send the query according to parameters and returns its result as a JSONObject
390
+ *
391
+ * @param m HTTP Method to use
392
+ * @param url endpoint URL
393
+ * @param json optional JSON Object to send
394
+ * @param hostsArray array of hosts to try successively
395
+ * @param connectTimeout maximum wait time to open connection
396
+ * @param readTimeout maximum time to read data on socket
397
+ * @return a JSONObject containing the resulting data or error
398
+ * @throws AlgoliaException if the request data is not valid json
399
+ */
341
400
private synchronized JSONObject _request (Method m , String url , String json , List <String > hostsArray , int connectTimeout , int readTimeout ) throws AlgoliaException {
401
+ try {
402
+ return _getJSONObject (_requestRaw (m , url , json , hostsArray , connectTimeout , readTimeout ));
403
+ } catch (JSONException e ) {
404
+ throw new AlgoliaException ("JSON decode error:" + e .getMessage ());
405
+ } catch (UnsupportedEncodingException e ) {
406
+ throw new AlgoliaException ("UTF-8 decode error:" + e .getMessage ());
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Send the query according to parameters and returns its result as a JSONObject
412
+ *
413
+ * @param m HTTP Method to use
414
+ * @param url endpoint URL
415
+ * @param json optional JSON Object to send
416
+ * @param hostsArray array of hosts to try successively
417
+ * @param connectTimeout maximum wait time to open connection
418
+ * @param readTimeout maximum time to read data on socket
419
+ * @return a JSONObject containing the resulting data or error
420
+ * @throws AlgoliaException in case of connection or data handling error
421
+ */
422
+ private synchronized byte [] _requestRaw (Method m , String url , String json , List <String > hostsArray , int connectTimeout , int readTimeout ) throws AlgoliaException {
342
423
String requestMethod ;
343
424
HashMap <String , String > errors = new HashMap <String , String >();
344
425
// for each host
@@ -433,7 +514,7 @@ private synchronized JSONObject _request(Method m, String url, String json, List
433
514
} else if (code / 100 == 4 ) {
434
515
String message = "Error detected in backend" ;
435
516
try {
436
- message = _getAnswerObject (stream ).getString ("message" );
517
+ message = _getAnswerJSONObject (stream ).getString ("message" );
437
518
} catch (IOException e ) {
438
519
addError (errors , host , e );
439
520
continue ;
@@ -444,7 +525,7 @@ private synchronized JSONObject _request(Method m, String url, String json, List
444
525
throw new AlgoliaException (message );
445
526
} else {
446
527
try {
447
- errors .put (host , _getAnswer (stream ));
528
+ errors .put (host , _toCharArray (stream ));
448
529
} catch (IOException e ) {
449
530
errors .put (host , String .valueOf (code ));
450
531
}
@@ -455,13 +536,11 @@ private synchronized JSONObject _request(Method m, String url, String json, List
455
536
try {
456
537
String encoding = hostConnection .getContentEncoding ();
457
538
if (encoding != null && encoding .contains ("gzip" )) {
458
- return _getAnswerObject (new GZIPInputStream (stream ));
539
+ return _toByteArray (new GZIPInputStream (stream ));
459
540
}
460
541
else {
461
- return _getAnswerObject (stream );
542
+ return _toByteArray (stream );
462
543
}
463
- } catch (JSONException e ) {
464
- throw new AlgoliaException ("JSON decode error:" + e .getMessage ());
465
544
} catch (IOException e ) {
466
545
throw new AlgoliaException ("Data decoding error:" + e .getMessage ());
467
546
}
0 commit comments