Skip to content
This repository was archived by the owner on Jan 31, 2022. It is now read-only.

Commit 02d8b84

Browse files
committed
Merge pull request #30 from algolia/feat/SyncMethods
Synchronous search interface
2 parents a56c3ac + 8ff1680 commit 02d8b84

File tree

3 files changed

+148
-35
lines changed

3 files changed

+148
-35
lines changed

algoliasearch/src/main/java/com/algolia/search/saas/BaseAPIClient.java

Lines changed: 102 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.json.JSONObject;
3232
import org.json.JSONTokener;
3333

34+
import java.io.ByteArrayOutputStream;
3435
import java.io.IOException;
3536
import java.io.InputStream;
3637
import java.io.InputStreamReader;
@@ -64,11 +65,12 @@ abstract class BaseAPIClient {
6465

6566
/**
6667
* Algolia Search initialization
68+
*
6769
* @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
7274
*/
7375
protected BaseAPIClient(String applicationID, String apiKey, List<String> hostsArray, boolean enableDsn, String dsnHost) {
7476
if (applicationID == null || applicationID.length() == 0) {
@@ -103,8 +105,9 @@ public void setExtraHeader(String key, String value) {
103105

104106
/**
105107
* Allow to set timeout
108+
*
106109
* @param connectTimeout connection timeout in MS
107-
* @param readTimeout socket timeout in MS
110+
* @param readTimeout socket timeout in MS
108111
*/
109112
public void setTimeout(int connectTimeout, int readTimeout) {
110113
httpSocketTimeoutMS = readTimeout;
@@ -113,9 +116,10 @@ public void setTimeout(int connectTimeout, int readTimeout) {
113116

114117
/**
115118
* Allow to set timeout
119+
*
116120
* @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
119123
*/
120124
public void setTimeout(int connectTimeout, int readTimeout, int searchTimeout) {
121125
httpSocketTimeoutMS = readTimeout;
@@ -133,7 +137,8 @@ public void setUserToken(String userToken) {
133137

134138
/**
135139
* List all existing indexes
136-
* return an JSON Object in the form:
140+
*
141+
* @return a JSON Object in the form:
137142
* { "items": [ {"name": "contacts", "createdAt": "2013-01-18T15:33:13.556Z"},
138143
* {"name": "notes", "createdAt": "2013-01-18T15:33:13.556Z"}]}
139144
*/
@@ -145,7 +150,7 @@ protected JSONObject listIndexes() throws AlgoliaException {
145150
* Delete an index
146151
*
147152
* @param indexName the name of index to delete
148-
* return an object containing a "deletedAt" attribute
153+
* @return an object containing a "deletedAt" attribute
149154
*/
150155
protected JSONObject deleteIndex(String indexName) throws AlgoliaException {
151156
try {
@@ -157,6 +162,7 @@ protected JSONObject deleteIndex(String indexName) throws AlgoliaException {
157162

158163
/**
159164
* Move an existing index.
165+
*
160166
* @param srcIndexName the name of index to copy.
161167
* @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
162168
*/
@@ -175,6 +181,7 @@ protected JSONObject moveIndex(String srcIndexName, String dstIndexName) throws
175181

176182
/**
177183
* Copy an existing index.
184+
*
178185
* @param srcIndexName the name of index to copy.
179186
* @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist).
180187
*/
@@ -193,8 +200,9 @@ protected JSONObject copyIndex(String srcIndexName, String dstIndexName) throws
193200

194201
/**
195202
* 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.
198206
* @param logType Specify the type of log to retrieve
199207
*/
200208
protected JSONObject getLogs(int offset, int length, LogType logType) throws AlgoliaException {
@@ -285,7 +293,7 @@ protected JSONObject multipleQueries(List<IndexQuery> queries, String strategy)
285293
* Custom batch
286294
*
287295
* @param actions the array of actions
288-
* @throws AlgoliaException
296+
* @throws AlgoliaException if the response is not valid json
289297
*/
290298
protected JSONObject batch(JSONArray actions) throws AlgoliaException {
291299
try {
@@ -301,6 +309,10 @@ private enum Method {
301309
GET, POST, PUT, DELETE
302310
}
303311

312+
protected byte[] getRequestRaw(String url, boolean search) throws AlgoliaException {
313+
return _requestRaw(Method.GET, url, null, readHostsArray, httpConnectTimeoutMS, search ? httpSearchTimeoutMS : httpSocketTimeoutMS);
314+
}
315+
304316
protected JSONObject getRequest(String url, boolean search) throws AlgoliaException {
305317
return _request(Method.GET, url, null, readHostsArray, httpConnectTimeoutMS, search ? httpSearchTimeoutMS : httpSocketTimeoutMS);
306318
}
@@ -317,9 +329,16 @@ protected JSONObject putRequest(String url, String obj) throws AlgoliaException
317329
return _request(Method.PUT, url, obj, writeHostsArray, httpConnectTimeoutMS, httpSocketTimeoutMS);
318330
}
319331

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();
323342
char[] buf = new char[1000];
324343
int l = 0;
325344
while (l >= 0) {
@@ -330,15 +349,77 @@ private String _getAnswer(InputStream istream) throws IOException {
330349
return builder.toString();
331350
}
332351

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+
333376
private JSONObject _getJSONObject(String input) throws JSONException {
334377
return new JSONObject(new JSONTokener(input));
335378
}
336379

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"));
339382
}
340383

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+
*/
341400
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 {
342423
String requestMethod;
343424
HashMap<String, String> errors = new HashMap<String, String>();
344425
// for each host
@@ -433,7 +514,7 @@ private synchronized JSONObject _request(Method m, String url, String json, List
433514
} else if (code / 100 == 4) {
434515
String message = "Error detected in backend";
435516
try {
436-
message = _getAnswerObject(stream).getString("message");
517+
message = _getAnswerJSONObject(stream).getString("message");
437518
} catch (IOException e) {
438519
addError(errors, host, e);
439520
continue;
@@ -444,7 +525,7 @@ private synchronized JSONObject _request(Method m, String url, String json, List
444525
throw new AlgoliaException(message);
445526
} else {
446527
try {
447-
errors.put(host, _getAnswer(stream));
528+
errors.put(host, _toCharArray(stream));
448529
} catch (IOException e) {
449530
errors.put(host, String.valueOf(code));
450531
}
@@ -455,13 +536,11 @@ private synchronized JSONObject _request(Method m, String url, String json, List
455536
try {
456537
String encoding = hostConnection.getContentEncoding();
457538
if (encoding != null && encoding.contains("gzip")) {
458-
return _getAnswerObject(new GZIPInputStream(stream));
539+
return _toByteArray(new GZIPInputStream(stream));
459540
}
460541
else {
461-
return _getAnswerObject(stream);
542+
return _toByteArray(stream);
462543
}
463-
} catch (JSONException e) {
464-
throw new AlgoliaException("JSON decode error:" + e.getMessage());
465544
} catch (IOException e) {
466545
throw new AlgoliaException("Data decoding error:" + e.getMessage());
467546
}

algoliasearch/src/main/java/com/algolia/search/saas/BaseIndex.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ protected JSONObject addObject(JSONObject obj) throws AlgoliaException {
7474
/**
7575
* Add an object in this index
7676
*
77-
* @param obj the object to add.
78-
* @param objectID an objectID you want to attribute to this object
77+
* @param obj the object to add.
78+
* @param objectID an objectID you want to attribute to this object
7979
* (if the attribute already exist the old object will be overwrite)
8080
* @throws AlgoliaException
8181
*/
@@ -151,8 +151,9 @@ protected JSONObject getObject(String objectID, List<String> attributesToRetrie
151151
StringBuilder params = new StringBuilder();
152152
params.append("?attributes=");
153153
for (int i = 0; i < attributesToRetrieve.size(); ++i) {
154-
if (i > 0)
154+
if (i > 0) {
155155
params.append(",");
156+
}
156157
params.append(URLEncoder.encode(attributesToRetrieve.get(i), "UTF-8"));
157158
}
158159
return client.getRequest("/1/indexes/" + encodedIndexName + "/" + URLEncoder.encode(objectID, "UTF-8") + params.toString(), false);
@@ -261,14 +262,15 @@ protected JSONObject saveObjects(JSONArray inputArray) throws AlgoliaException {
261262
}
262263

263264
/**
264-
* Delete an object from the index
265+
* Delete an object from the index
265266
*
266267
* @param objectID the unique identifier of object to delete
267268
* @throws AlgoliaException
268269
*/
269270
protected JSONObject deleteObject(String objectID) throws AlgoliaException {
270-
if (objectID.length() == 0)
271+
if (objectID.length() == 0) {
271272
throw new AlgoliaException("Invalid objectID");
273+
}
272274
try {
273275
return client.deleteRequest("/1/indexes/" + encodedIndexName + "/" + URLEncoder.encode(objectID, "UTF-8"));
274276
} catch (UnsupportedEncodingException e) {
@@ -330,19 +332,34 @@ protected void deleteByQuery(Query query) throws AlgoliaException {
330332

331333
/**
332334
* Search inside the index
333-
*
335+
* @return a JSONObject containing search results
334336
* @throws AlgoliaException
335337
*/
336338
protected JSONObject search(Query query) throws AlgoliaException {
337339
String paramsString = query.getQueryString();
338-
if (paramsString.length() > 0)
340+
if (paramsString.length() > 0) {
339341
return client.getRequest("/1/indexes/" + encodedIndexName + "?" + paramsString, true);
340-
else
342+
} else {
341343
return client.getRequest("/1/indexes/" + encodedIndexName, true);
344+
}
342345
}
343346

344347
/**
345-
* Wait the publication of a task on the server.
348+
* Search inside the index
349+
* @return a byte array containing search results
350+
* @throws AlgoliaException
351+
*/
352+
protected byte[] searchRaw(Query query) throws AlgoliaException {
353+
String paramsString = query.getQueryString();
354+
if (paramsString.length() > 0) {
355+
return client.getRequestRaw("/1/indexes/" + encodedIndexName + "?" + paramsString, true);
356+
} else {
357+
return client.getRequestRaw("/1/indexes/" + encodedIndexName, true);
358+
}
359+
}
360+
361+
/**
362+
* Wait the publication of a task on the server.
346363
* All server task are asynchronous and you can check with this method that the task is published.
347364
*
348365
* @param taskID the id of the task returned by server
@@ -353,8 +370,9 @@ protected void waitTask(String taskID, long timeToWait) throws AlgoliaException
353370
try {
354371
while (true) {
355372
JSONObject obj = client.getRequest("/1/indexes/" + encodedIndexName + "/task/" + URLEncoder.encode(taskID, "UTF-8"), false);
356-
if (obj.getString("status").equals("published"))
373+
if (obj.getString("status").equals("published")) {
357374
return;
375+
}
358376
try {
359377
Thread.sleep(timeToWait >= MAX_TIME_MS_TO_WAIT ? MAX_TIME_MS_TO_WAIT : timeToWait);
360378
} catch (InterruptedException e) {

algoliasearch/src/main/java/com/algolia/search/saas/Index.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import com.algolia.search.saas.listeners.DeleteObjectsListener;
2929
import com.algolia.search.saas.listeners.GetObjectsListener;
3030
import com.algolia.search.saas.listeners.IndexingListener;
31-
import com.algolia.search.saas.listeners.SearchListener;
3231
import com.algolia.search.saas.listeners.SearchDisjunctiveFacetingListener;
32+
import com.algolia.search.saas.listeners.SearchListener;
3333
import com.algolia.search.saas.listeners.SettingsListener;
3434
import com.algolia.search.saas.listeners.WaitTaskListener;
3535

@@ -82,6 +82,22 @@ public void searchASync(Query query, SearchListener listener) {
8282
new ASyncSearchTask().execute(params);
8383
}
8484

85+
/**
86+
* Search inside the index synchronously
87+
* @return a JSONObject containing search results
88+
*/
89+
public JSONObject searchSync(Query query) throws AlgoliaException {
90+
return search(query);
91+
}
92+
93+
/**
94+
* Search inside the index synchronously
95+
* @return a byte array containing search results
96+
*/
97+
protected byte[] searchSyncRaw(Query query) throws AlgoliaException {
98+
return searchRaw(query);
99+
}
100+
85101
////////////////////////////////////////////////////////////////////////////////////////////////
86102
/// SEARCH DISJUNCTIVE FACETING TASK
87103
////////////////////////////////////////////////////////////////////////////////////////////////
@@ -178,7 +194,7 @@ public void addObjectASync(JSONObject object, IndexingListener listener) {
178194
*
179195
* @param object the object to add.
180196
* The object is represented by an associative array
181-
* @param objectID an objectID you want to attribute to this object
197+
* @param objectID an objectID you want to attribute to this object
182198
* (if the attribute already exist the old object will be overwrite)
183199
* @param listener the listener that will receive the result or error.
184200
*/

0 commit comments

Comments
 (0)