signature:
public class Index { /** * Searches inside the index .
 * @ param requestOptions Request - specific options .
 * @ return a JSONObject containing search results
 * @ throws AlgoliaException */
public JSONObject search ( @ Nullable Query query , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation: if ( query == null ) { query = new Query ( ) ; } String cacheKey = null ; byte [ ] rawResponse = null ; if ( isCacheEnabled ) { cacheKey = query . build ( ) ; rawResponse = searchCache . get ( cacheKey ) ; } try { if ( rawResponse == null ) { rawResponse = searchRaw ( query , requestOptions ) ; if ( isCacheEnabled ) { searchCache . put ( cacheKey , rawResponse ) ; } } return Client . _getJSONObject ( rawResponse ) ; } catch ( UnsupportedEncodingException | JSONException e ) { throw new AlgoliaException ( e . getMessage ( ) ) ; }


signature:
public class Index { /** * Searches inside the index .
 * @ param requestOptions Request - specific options .
 * @ return a byte array containing search results
 * @ throws AlgoliaException */
protected byte [ ] searchRaw ( @ Nullable Query query , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
if ( query == null ) { query = new Query ( ) ; } try { String paramsString = query . build ( ) ; if ( paramsString . length ( ) > 0 ) { JSONObject body = new JSONObject ( ) ; body . put ( "params" , paramsString ) ; return client . postRequestRaw ( "/1/indexes/" + encodedIndexName + "/query" , /* urlParameters : */
null , body . toString ( ) , true , requestOptions ) ; } else { return client . getRequestRaw ( "/1/indexes/" + encodedIndexName , /* urlParameters : */
null , true , requestOptions ) ; } } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
}


signature:
public class Index { /** * Wait the publication of a task on the server .
 * All server task are asynchronous and you can check with this method that the task is published .
 * @ param taskID the id of the task returned by server
 * @ param timeToWait time to sleep seed
 * @ throws AlgoliaException */
public JSONObject waitTask ( String taskID , long timeToWait ) throws AlgoliaException { } }

implementation:
try { while ( true ) { JSONObject obj = client . getRequest ( "/1/indexes/" + encodedIndexName + "/task/" + URLEncoder . encode ( taskID , "UTF-8" ) , /* urlParameters : */
null , false , /* requestOptions : */
null ) ; if ( obj . getString ( "status" ) . equals ( "published" ) ) { return obj ; } try { Thread . sleep ( timeToWait >= MAX_TIME_MS_TO_WAIT ? MAX_TIME_MS_TO_WAIT : timeToWait ) ; } catch ( InterruptedException e ) { continue ; } final long newTimeout = timeToWait * 2 ; timeToWait = ( newTimeout <= 0 || newTimeout >= MAX_TIME_MS_TO_WAIT ) ? MAX_TIME_MS_TO_WAIT : newTimeout ; } } catch ( JSONException e ) { throw new AlgoliaException ( e . getMessage ( ) ) ; } catch ( UnsupportedEncodingException e ) { throw new RuntimeException ( e ) ; }


signature:
public class Index { /** * Gets the settings of this index .
 * @ param requestOptions Request - specific options . */
public JSONObject getSettings ( @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation: Map < String , String > urlParameters = new HashMap < > ( ) ; urlParameters . put ( "getVersion" , Integer . toString ( DEFAULT_SETTINGS_VERSION ) ) ; return client . getRequest ( "/1/indexes/" + encodedIndexName + "/settings" , urlParameters , false , requestOptions ) ;


signature:
public class Index { /** * Set settings for this index .
 * @ param settings the settings object .
 * @ param forwardToReplicas if true , the new settings will be forwarded to replica indices .
 * @ param requestOptions Request - specific options .
 * @ throws AlgoliaException */
public JSONObject setSettings ( JSONObject settings , boolean forwardToReplicas , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation: Map < String , String > urlParameters = new HashMap < > ( ) ; urlParameters . put ( "forwardToReplicas" , Boolean . toString ( forwardToReplicas ) ) ; return client . putRequest ( "/1/indexes/" + encodedIndexName + "/settings" , urlParameters , settings . toString ( ) , requestOptions ) ;


signature:
public class Index { /** * Deletes the index content without removing settings and index specific API keys .
 * @ param requestOptions Request - specific options .
 * @ throws AlgoliaException */
public JSONObject clearIndex ( @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
return client . postRequest ( "/1/indexes/" + encodedIndexName + "/clear" , /* urlParameters : */
null , "" , false , requestOptions ) ;


signature:
public class Index { /** * Run multiple queries on this index with one API call .
 * A variant of { @ link Client # multipleQueries ( List , String , RequestOptions ) } where all queries target this index .
 * @ param queries Queries to run .
 * @ param strategy Strategy to use .
 * @ param requestOptions Request - specific options .
 * @ return The JSON results returned by the server .
 * @ throws AlgoliaException */
protected JSONObject multipleQueries ( @ NonNull Collection < Query > queries , String strategy , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation: List < IndexQuery > requests = new ArrayList < > ( queries . size ( ) ) ; for ( Query query : queries ) { requests . add ( new IndexQuery ( this , query ) ) ; } return client . multipleQueries ( requests , strategy , requestOptions ) ;


signature:
public class AbstractQuery { /** * Build a query string from a map of URL parameters .
 * @ return A string suitable for use inside the query part of a URL ( i . e . after the question mark ) . */
static @ NonNull String build ( @ NonNull Map < String , String > parameters ) { } }

implementation:
StringBuilder stringBuilder = new StringBuilder ( ) ; try { for ( Map . Entry < String , String > entry : parameters . entrySet ( ) ) { String key = entry . getKey ( ) ; if ( stringBuilder . length ( ) > 0 ) stringBuilder . append ( '&' ) ; stringBuilder . append ( urlEncode ( key ) ) ; String value = entry . getValue ( ) ; if ( value != null ) { stringBuilder . append ( '=' ) ; stringBuilder . append ( urlEncode ( value ) ) ; } } } catch ( UnsupportedEncodingException e ) { throw new RuntimeException ( e ) ; // should never happen : UTF - 8 is always supported
} return stringBuilder . toString ( ) ;


signature:
public class AbstractQuery { /** * Parse a URL query parameter string and store the resulting parameters into this query .
 * @ param queryParameters URL query parameter string . */
public void parseFrom ( @ NonNull String queryParameters ) { } }

implementation:
try { String [ ] parameters = queryParameters . split ( "&" ) ; for ( String parameter : parameters ) { String [ ] components = parameter . split ( "=" ) ; if ( components . length < 1 || components . length > 2 ) continue ; // ignore invalid values
String name = URLDecoder . decode ( components [ 0 ] , "UTF-8" ) ; String value = components . length >= 2 ? URLDecoder . decode ( components [ 1 ] , "UTF-8" ) : null ; set ( name , value ) ; } // for each parameter
} catch ( UnsupportedEncodingException e ) { // Should never happen since UTF - 8 is one of the default encodings .
throw new RuntimeException ( e ) ; }


signature:
public class AbstractQuery { /** * Set a parameter in an untyped fashion .
 * This low - level accessor is intended to access parameters that this client does not yet support .
 * @ param name The parameter ' s name .
 * @ param value The parameter ' s value , or null to remove it .
 * It will first be converted to a String by the ` toString ( ) ` method .
 * @ return This instance ( used to chain calls ) . */
public @ NonNull AbstractQuery set ( @ NonNull String name , @ Nullable Object value ) { } }

implementation: if ( value == null ) { parameters . remove ( name ) ; } else { parameters . put ( name , value . toString ( ) ) ; } return this ;


signature:
public class Query { /** * Search for entries around a given latitude / longitude . */
public @ NonNull Query setAroundLatLng ( @ Nullable LatLng location ) { } }

implementation: if ( location == null ) { return set ( KEY_AROUND_LAT_LNG , null ) ; } else { return set ( KEY_AROUND_LAT_LNG , location . lat + "," + location . lng ) ; }


signature:
public class Query { /** * Change the radius for around latitude / longitude queries .
 * @ param radius the radius to set , or Query . RADIUS _ ALL to disable stopping at a specific radius . */
public @ NonNull Query setAroundRadius ( Integer radius ) { } }

implementation: if ( radius == Query . RADIUS_ALL ) { return set ( KEY_AROUND_RADIUS , "all" ) ; } return set ( KEY_AROUND_RADIUS , radius ) ;


signature:
public class Query { /** * Deprecated , use { @ link # setAttributesToHighlight ( String . . . ) } */
@ Deprecated public @ NonNull Query setAttributesToHighlight ( List < String > attributes ) { } }

implementation: return set ( KEY_ATTRIBUTES_TO_HIGHLIGHT , buildJSONArray ( ( String [ ] ) attributes . toArray ( ) ) ) ;


signature:
public class Query { /** * Deprecated , use { @ link # setAttributesToRetrieve ( String . . . ) } */
@ Deprecated public @ NonNull Query setAttributesToRetrieve ( List < String > attributes ) { } }

implementation: return set ( KEY_ATTRIBUTES_TO_RETRIEVE , buildJSONArray ( ( String [ ] ) attributes . toArray ( ) ) ) ;


signature:
public class Query { /** * Get the value of < b > deprecated < / b > { @ code facetFilters } parameter .
 * @ deprecated Use { @ link Query # getFilters ( ) } instead . */
public @ Nullable JSONArray getFacetFilters ( ) { } }

implementation:
try { String value = get ( KEY_FACET_FILTERS ) ; if ( value != null ) { return new JSONArray ( value ) ; } } catch ( JSONException e ) { // Will return null
} return null ;


signature:
public class Query { /** * A list of language codes for which plural won ' t be considered as a typo ( for example
 * car / cars will be considered as equals ) . If empty or null , this disables the feature . */
public @ NonNull Query setIgnorePlurals ( @ Nullable Collection < String > languageISOCodes ) { } }

implementation: return set ( KEY_IGNORE_PLURALS , new IgnorePlurals ( languageISOCodes ) ) ;


signature:
public class Query { /** * Search for entries inside one area or the union of several areas
 * defined by the two extreme points of a rectangle . */
public @ NonNull Query setInsideBoundingBox ( @ Nullable GeoRect ... boxes ) { } }

implementation: if ( boxes == null ) { set ( KEY_INSIDE_BOUNDING_BOX , null ) ; } else { StringBuilder sb = new StringBuilder ( ) ; for ( GeoRect box : boxes ) { if ( sb . length ( ) != 0 ) { sb . append ( ',' ) ; } sb . append ( box . p1 . lat ) ; sb . append ( ',' ) ; sb . append ( box . p1 . lng ) ; sb . append ( ',' ) ; sb . append ( box . p2 . lat ) ; sb . append ( ',' ) ; sb . append ( box . p2 . lng ) ; } set ( KEY_INSIDE_BOUNDING_BOX , sb . toString ( ) ) ; } return this ;


signature:
public class Query { /** * Search for entries inside a given area defined by the points of a polygon . */
public @ NonNull Query setInsidePolygon ( @ Nullable LatLng ... points ) { } }

implementation: set ( KEY_INSIDE_POLYGON , points == null ? null : new Polygon ( points ) . toString ( ) ) ; return this ;


signature:
public class Query { /** * Search for entries inside a given area defined by several polygons . */
public @ NonNull Query setInsidePolygon ( @ Nullable Polygon ... polygons ) { } }

implementation: String insidePolygon = null ; if ( polygons == null ) { insidePolygon = null ; } else if ( polygons . length == 1 ) { insidePolygon = polygons [ 0 ] . toString ( ) ; } else { for ( Polygon polygon : polygons ) { String polygonStr = "[" + polygon + "]" ; if ( insidePolygon == null ) { insidePolygon = "[" ; } else { insidePolygon += "," ; } insidePolygon += polygonStr ; } insidePolygon += "]" ; } set ( KEY_INSIDE_POLYGON , insidePolygon ) ; return this ;


signature:
public class Query { /** * Get the value of < b > deprecated < / b > { @ code facetFilters } parameter .
 * @ deprecated Use { @ link Query # getFilters ( ) } instead . */
public @ Nullable JSONArray getNumericFilters ( ) { } }

implementation:
try { String value = get ( KEY_NUMERIC_FILTERS ) ; if ( value != null ) { return new JSONArray ( value ) ; } } catch ( JSONException e ) { // Will return null
} return null ;


signature:
public class Query { /** * Select how the query words are interpreted : */
public @ NonNull Query setQueryType ( @ Nullable QueryType type ) { } }

implementation: set ( KEY_QUERY_TYPE , type == null ? null : type . toString ( ) ) ; return this ;


signature:
public class Query { /** * Enable the removal of stop words , disabled by default .
 * In most use - cases , we don ’ t recommend enabling this option .
 * @ param removeStopWords Boolean : enable or disable all 41 supported languages ,
 * String : comma separated list of languages you have in your record ( using language iso code ) . */
public @ NonNull Query setRemoveStopWords ( Object removeStopWords ) throws AlgoliaException { } }

implementation: if ( removeStopWords instanceof Boolean || removeStopWords instanceof String ) { return set ( KEY_REMOVE_STOP_WORDS , removeStopWords ) ; } throw new AlgoliaException ( "removeStopWords should be a Boolean or a String." ) ;


signature:
public class Query { /** * Select the strategy to adopt when a query does not return any result . */
public @ NonNull Query setRemoveWordsIfNoResults ( @ Nullable RemoveWordsIfNoResults type ) { } }

implementation: set ( KEY_REMOVE_WORDS_IF_NO_RESULT , type == null ? null : type . toString ( ) ) ; return this ;


signature:
public class Query { /** * Parse a query object from a URL query parameter string .
 * @ param queryParameters URL query parameter string .
 * @ return The parsed query object . */
protected static @ NonNull Query parse ( @ NonNull String queryParameters ) { } }

implementation: Query query = new Query ( ) ; query . parseFrom ( queryParameters ) ; return query ;


signature:
public class DisjunctiveFaceting { /** * Perform a search with disjunctive facets , generating as many queries as number of disjunctive facets .
 * @ param query The query .
 * @ param disjunctiveFacets List of disjunctive facets .
 * @ param refinements The current refinements , mapping facet names to a list of values .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public < T extends Collection < String > > Request searchDisjunctiveFacetingAsync ( @ NonNull Query query , @ NonNull final Collection < String > disjunctiveFacets , @ NonNull final Map < String , T > refinements , @ NonNull final CompletionHandler completionHandler ) { } }

implementation: final List < Query > queries = computeDisjunctiveFacetingQueries ( query , disjunctiveFacets , refinements ) ; return multipleQueriesAsync ( queries , new CompletionHandler ( ) { @ Override public void requestCompleted ( JSONObject content , AlgoliaException error ) { JSONObject aggregatedResults = null ; try { if ( content != null ) { aggregatedResults = aggregateDisjunctiveFacetingResults ( content , disjunctiveFacets , refinements ) ; } } catch ( AlgoliaException e ) { error = e ; } completionHandler . requestCompleted ( aggregatedResults , error ) ; } } ) ;


signature:
public class DisjunctiveFaceting { /** * Filter disjunctive refinements from generic refinements and a list of disjunctive facets .
 * @ param disjunctiveFacets the array of disjunctive facets
 * @ param refinements Map representing the current refinements
 * @ return The disjunctive refinements */
static private @ NonNull < T extends Collection < String > > Map < String , T > filterDisjunctiveRefinements ( @ NonNull Collection < String > disjunctiveFacets , @ NonNull Map < String , T > refinements ) { } }

implementation: Map < String , T > disjunctiveRefinements = new HashMap < > ( ) ; for ( Map . Entry < String , T > elt : refinements . entrySet ( ) ) { if ( disjunctiveFacets . contains ( elt . getKey ( ) ) ) { disjunctiveRefinements . put ( elt . getKey ( ) , elt . getValue ( ) ) ; } } return disjunctiveRefinements ;


signature:
public class DisjunctiveFaceting { /** * Compute the queries to run to implement disjunctive faceting .
 * @ param query The query .
 * @ param disjunctiveFacets List of disjunctive facets .
 * @ param refinements The current refinements , mapping facet names to a list of values .
 * @ return A list of queries suitable for { @ link Index # multipleQueries } . */
static private @ NonNull < T extends Collection < String > > List < Query > computeDisjunctiveFacetingQueries ( @ NonNull Query query , @ NonNull Collection < String > disjunctiveFacets , @ NonNull Map < String , T > refinements ) { } }

implementation:
// Retain only refinements corresponding to the disjunctive facets .
Map < String , ? extends Collection < String > > disjunctiveRefinements = filterDisjunctiveRefinements ( disjunctiveFacets , refinements ) ; // build queries
List < Query > queries = new ArrayList < > ( ) ; // first query : hits + regular facets
JSONArray facetFilters = new JSONArray ( ) ; for ( Map . Entry < String , T > elt : refinements . entrySet ( ) ) { JSONArray orFilters = new JSONArray ( ) ; for ( String val : elt . getValue ( ) ) { // When already refined facet , or with existing refinements
if ( disjunctiveRefinements . containsKey ( elt . getKey ( ) ) ) { orFilters . put ( formatFilter ( elt , val ) ) ; } else { facetFilters . put ( formatFilter ( elt , val ) ) ; } } // Add or
if ( disjunctiveRefinements . containsKey ( elt . getKey ( ) ) ) { facetFilters . put ( orFilters ) ; } } // noinspection deprecation Deprecated for end - users
queries . add ( new Query ( query ) . setFacetFilters ( facetFilters ) ) ; // one query per disjunctive facet ( use all refinements but the current one + hitsPerPage = 1 + single facet
for ( String disjunctiveFacet : disjunctiveFacets ) { facetFilters = new JSONArray ( ) ; for ( Map . Entry < String , T > elt : refinements . entrySet ( ) ) { if ( disjunctiveFacet . equals ( elt . getKey ( ) ) ) { continue ; } JSONArray orFilters = new JSONArray ( ) ; for ( String val : elt . getValue ( ) ) { if ( disjunctiveRefinements . containsKey ( elt . getKey ( ) ) ) { orFilters . put ( formatFilter ( elt , val ) ) ; } else { facetFilters . put ( formatFilter ( elt , val ) ) ; } } // Add or
if ( disjunctiveRefinements . containsKey ( elt . getKey ( ) ) ) { facetFilters . put ( orFilters ) ; } } String [ ] facets = new String [ ] { disjunctiveFacet } ; // noinspection deprecation Deprecated for end - users
queries . add ( new Query ( query ) . setHitsPerPage ( 0 ) . setAnalytics ( false ) . setAttributesToRetrieve ( ) . setAttributesToHighlight ( ) . setAttributesToSnippet ( ) . setFacets ( facets ) . setFacetFilters ( facetFilters ) ) ; } return queries ;


signature:
public class DisjunctiveFaceting { /** * Aggregate results from multiple queries into disjunctive faceting results .
 * @ param answers The response from the multiple queries .
 * @ param disjunctiveFacets List of disjunctive facets .
 * @ param refinements Facet refinements .
 * @ return The aggregated results .
 * @ throws AlgoliaException when aggregation fails due to a JSONException */
static private < T extends Collection < String > > JSONObject aggregateDisjunctiveFacetingResults ( @ NonNull JSONObject answers , @ NonNull Collection < String > disjunctiveFacets , @ NonNull Map < String , T > refinements ) throws AlgoliaException { } }

implementation:
Map < String , T > disjunctiveRefinements = filterDisjunctiveRefinements ( disjunctiveFacets , refinements ) ; // aggregate answers
// first answer stores the hits + regular facets
try { boolean nonExhaustiveFacetsCount = false ; JSONArray results = answers . getJSONArray ( "results" ) ; JSONObject aggregatedAnswer = results . getJSONObject ( 0 ) ; JSONObject disjunctiveFacetsJSON = new JSONObject ( ) ; for ( int i = 1 ; i < results . length ( ) ; ++ i ) { if ( ! results . getJSONObject ( i ) . optBoolean ( "exhaustiveFacetsCount" ) ) { nonExhaustiveFacetsCount = true ; } JSONObject facets = results . getJSONObject ( i ) . getJSONObject ( "facets" ) ; @ SuppressWarnings ( "unchecked" ) Iterator < String > keys = facets . keys ( ) ; while ( keys . hasNext ( ) ) { String key = keys . next ( ) ; // Add the facet to the disjunctive facet hash
disjunctiveFacetsJSON . put ( key , facets . getJSONObject ( key ) ) ; // concatenate missing refinements
if ( ! disjunctiveRefinements . containsKey ( key ) ) { continue ; } for ( String refine : disjunctiveRefinements . get ( key ) ) { if ( ! disjunctiveFacetsJSON . getJSONObject ( key ) . has ( refine ) ) { disjunctiveFacetsJSON . getJSONObject ( key ) . put ( refine , 0 ) ; } } } } aggregatedAnswer . put ( "disjunctiveFacets" , disjunctiveFacetsJSON ) ; if ( nonExhaustiveFacetsCount ) { aggregatedAnswer . put ( "exhaustiveFacetsCount" , false ) ; } return aggregatedAnswer ; } catch ( JSONException e ) { throw new AlgoliaException ( "Failed to aggregate results" , e ) ; }


signature:
public class OfflineIndex { /** * Search inside this index ( asynchronously ) .
 * @ param query Search parameters . May be null to use an empty query .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request searchAsync ( @ NonNull Query query , @ NonNull CompletionHandler completionHandler ) { } }

implementation: final Query queryCopy = new Query ( query ) ; return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return searchSync ( queryCopy ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Search inside this index ( synchronously ) .
 * @ return Search results . */
private JSONObject searchSync ( @ NonNull Query query ) throws AlgoliaException { } }

implementation: return OfflineClient . parseSearchResults ( localIndex . search ( query . build ( ) ) ) ;


signature:
public class OfflineIndex { /** * Run multiple queries on this index with one API call .
 * A variant of { @ link Client # multipleQueriesAsync ( List , Client . MultipleQueriesStrategy , CompletionHandler ) }
 * where the targeted index is always the receiver .
 * @ param queries The queries to run .
 * @ param strategy The strategy to use .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request multipleQueriesAsync ( final @ NonNull List < Query > queries , @ Nullable final Client . MultipleQueriesStrategy strategy , @ NonNull CompletionHandler completionHandler ) { } }

implementation: final List < Query > queriesCopy = new ArrayList < > ( queries ) ; return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return multipleQueriesSync ( queriesCopy , strategy ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Get an object from this index , optionally restricting the retrieved content ( asynchronously ) .
 * @ param objectID Identifier of the object to retrieve .
 * @ param attributesToRetrieve List of attributes to retrieve .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request getObjectAsync ( final @ NonNull String objectID , final List < String > attributesToRetrieve , @ NonNull CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return getObjectSync ( objectID , attributesToRetrieve ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Get several objects from this index ( asynchronously ) .
 * @ param objectIDs Identifiers of objects to retrieve .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request getObjectsAsync ( final @ NonNull List < String > objectIDs , @ NonNull CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return getObjectsSync ( objectIDs , null ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Get this index ' s settings ( asynchronously ) .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request getSettingsAsync ( @ NonNull CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return getSettingsSync ( ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Browse all index content ( initial call ) .
 * This method should be called once to initiate a browse . It will return the first page of results and a cursor ,
 * unless the end of the index has been reached . To retrieve subsequent pages , call ` browseFromAsync ` with that
 * cursor .
 * @ param query The query parameters for the browse .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request browseAsync ( @ NonNull Query query , @ NonNull CompletionHandler completionHandler ) { } }

implementation: final Query queryCopy = new Query ( query ) ; return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return browseSync ( queryCopy ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Browse the index from a cursor .
 * This method should be called after an initial call to ` browseAsync ( ) ` . It returns a cursor , unless the end of
 * the index has been reached .
 * @ param cursor The cursor of the next page to retrieve .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request browseFromAsync ( final @ NonNull String cursor , @ NonNull CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return browseFromSync ( cursor ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Search for facet values ( asynchronously ) .
 * Same parameters as { @ link Index # searchForFacetValues ( String , String , Query , CompletionHandler ) } . */
public Request searchForFacetValuesAsync ( final @ NonNull String facetName , final @ NonNull String facetQuery , @ Nullable Query query , @ NonNull CompletionHandler completionHandler ) { } }

implementation: final Query queryCopy = query != null ? new Query ( query ) : null ; return getClient ( ) . new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return searchForFacetValuesSync ( facetName , facetQuery , queryCopy ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Search for facet values ( synchronously ) . */
private JSONObject searchForFacetValuesSync ( @ NonNull String facetName , @ NonNull String facetQuery , @ Nullable Query query ) throws AlgoliaException { } }

implementation: return OfflineClient . parseSearchResults ( localIndex . searchForFacetValues ( facetName , facetQuery , query != null ? query . build ( ) : null ) ) ;


signature:
public class OfflineIndex { /** * Build the index from local data stored on the filesystem .
 * @ param settingsFile Absolute path to the file containing the index settings , in JSON format .
 * @ param objectFiles Absolute path ( s ) to the file ( s ) containing the objects . Each file must contain an array of
 * objects , in JSON format .
 * @ param completionHandler Optional completion handler to be notified of the build ' s outcome .
 * @ return A cancellable request .
 * * * Note : * * Cancelling the request does * not * cancel the build ; it merely prevents the completion handler from
 * being called . */
public Request buildFromFiles ( @ NonNull final File settingsFile , @ NonNull final File [ ] objectFiles , @ Nullable CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler , getClient ( ) . localBuildExecutorService ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return _build ( settingsFile , objectFiles ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Build the index from local data stored in raw resources .
 * @ param resources A { @ link Resources } instance to read resources from .
 * @ param settingsResId Resource identifier of the index settings , in JSON format .
 * @ param objectsResIds Resource identifiers of the various objects files . Each file must contain an array of
 * objects , in JSON format .
 * @ param completionHandler Optional completion handler to be notified of the build ' s outcome .
 * @ return A cancellable request .
 * * * Note : * * Cancelling the request does * not * cancel the build ; it merely prevents the completion handler from
 * being called . */
public Request buildFromRawResources ( @ NonNull final Resources resources , @ NonNull final int settingsResId , @ NonNull final int [ ] objectsResIds , @ Nullable CompletionHandler completionHandler ) { } }

implementation: return getClient ( ) . new AsyncTaskRequest ( completionHandler , getClient ( ) . localBuildExecutorService ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return _buildFromRawResources ( resources , settingsResId , objectsResIds ) ; } } . start ( ) ;


signature:
public class OfflineIndex { /** * Perform a search with disjunctive facets , generating as many queries as number of disjunctive facets ( helper ) .
 * @ param query The query .
 * @ param disjunctiveFacets List of disjunctive facets .
 * @ param refinements The current refinements , mapping facet names to a list of values .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request searchDisjunctiveFacetingAsync ( @ NonNull Query query , @ NonNull final List < String > disjunctiveFacets , @ NonNull final Map < String , List < String > > refinements , @ NonNull final CompletionHandler completionHandler ) { } }

implementation: return new DisjunctiveFaceting ( ) { @ Override protected Request multipleQueriesAsync ( @ NonNull Collection < Query > queries , @ NonNull CompletionHandler completionHandler ) { return OfflineIndex . this . multipleQueriesAsync ( new ArrayList ( queries ) , null , completionHandler ) ; } } . searchDisjunctiveFacetingAsync ( query , disjunctiveFacets , refinements , completionHandler ) ;


signature:
public class OfflineIndex { /** * Delete all objects matching a query ( helper ) .
 * @ param query The query that objects to delete must match .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request deleteByQueryAsync ( @ NonNull Query query , CompletionHandler completionHandler ) { } }

implementation:
final WriteTransaction transaction = newTransaction ( ) ; final Query queryCopy = new Query ( query ) ; return getClient ( ) . new AsyncTaskRequest ( completionHandler , getClient ( ) . transactionExecutorService ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { try { Collection < String > deletedObjectIDs = deleteByQuerySync ( queryCopy , transaction ) ; transaction . commitSync ( ) ; return new JSONObject ( ) . put ( "objectIDs" , new JSONArray ( deletedObjectIDs ) ) . put ( "updatedAt" , DateUtils . iso8601String ( new Date ( ) ) ) . put ( "taskID" , transaction . id ) ; } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
} } } . start ( ) ;


signature:
public class OfflineIndex { /** * Create a copy of a JSON object with a specific < code > objectID < / code > attribute .
 * @ param object The object to copy .
 * @ param objectID The ID for the new object .
 * @ return A new JSON object with the specified object ID . */
private static JSONObject objectWithID ( @ NonNull JSONObject object , @ NonNull String objectID ) { } }

implementation:
try { // WARNING : Could not find a better way to clone the object .
JSONObject patchedObject = new JSONObject ( object . toString ( ) ) ; patchedObject . put ( "objectID" , objectID ) ; return patchedObject ; } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
}


signature:
public class OfflineIndex { /** * Write a temporary file containing a JSON object .
 * @ param object JSON object to write .
 * @ return Path to the created file .
 * @ throws AlgoliaException */
private @ NonNull File writeTmpJSONFile ( @ NonNull JSONObject object ) throws AlgoliaException { } }

implementation: return writeTempFile ( object . toString ( ) ) ;


signature:
public class OfflineIndex { /** * Write a temporary file containing JSON objects . The files are written as an array .
 * @ param objects JSON objects to write .
 * @ return Path to the created file .
 * @ throws AlgoliaException */
private File writeTmpJSONFile ( @ NonNull Collection < JSONObject > objects ) throws AlgoliaException { } }

implementation:
// TODO : Maybe split in several files if too big ?
// TODO : Stream writing .
JSONArray array = new JSONArray ( ) ; for ( JSONObject object : objects ) { array . put ( object ) ; } return writeTempFile ( array . toString ( ) ) ;


signature:
public class OfflineIndex { /** * Write a temporary file containing textual data in UTF - 8 encoding .
 * @ param data Data to write .
 * @ return Path to the created file .
 * @ throws AlgoliaException */
private File writeTempFile ( @ NonNull String data ) throws AlgoliaException { } }

implementation:
try { // Create temporary file .
File tmpDir = client . getTempDir ( ) ; File tmpFile = File . createTempFile ( "algolia." , ".json" , tmpDir ) ; // Write to file .
Writer writer = new OutputStreamWriter ( new FileOutputStream ( tmpFile ) , "UTF-8" ) ; writer . write ( data ) ; writer . close ( ) ; return tmpFile ; } catch ( IOException e ) { throw new AlgoliaException ( "Could not create temporary file" , e ) ; }


signature:
public class OfflineClient { /** * Obtain a mirrored index . Although this will always be an instance of { @ link MirroredIndex } , mirroring is
 * deactivated by default .
 * @ param indexName The name of the index .
 * @ return A proxy to the specified index .
 * * * Warning : * * The name should not overlap with any ` OfflineIndex ` . See { @ link # getOfflineIndex ( String ) } . */
@ Override public @ NonNull MirroredIndex getIndex ( @ NonNull String indexName ) { } }

implementation: MirroredIndex index = null ; WeakReference < Object > existingIndex = indices . get ( indexName ) ; if ( existingIndex != null ) { index = ( MirroredIndex ) existingIndex . get ( ) ; } if ( index == null ) { index = new MirroredIndex ( this , indexName ) ; indices . put ( indexName , new WeakReference < Object > ( index ) ) ; } return index ;


signature:
public class OfflineClient { /** * Obtain a purely offline index .
 * @ param indexName The name of the index .
 * @ return A proxy to the specified index .
 * * * Warning : * * The name should not overlap with any ` MirroredIndex ` . See { @ link # getIndex ( String ) } . */
public OfflineIndex getOfflineIndex ( @ NonNull String indexName ) { } }

implementation: OfflineIndex index = null ; WeakReference < Object > existingIndex = indices . get ( indexName ) ; if ( existingIndex != null ) { index = ( OfflineIndex ) existingIndex . get ( ) ; } if ( index == null ) { index = new OfflineIndex ( this , indexName ) ; indices . put ( indexName , new WeakReference < Object > ( index ) ) ; } return index ;


signature:
public class OfflineClient { /** * Test if an index has offline data on disk .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * * * Warning : * * This method is synchronous !
 * @ param name The index ' s name .
 * @ return ` true ` if data exists on disk for this index , ` false ` otherwise . */
public boolean hasOfflineData ( @ NonNull String name ) { } }

implementation:
// TODO : Suboptimal ; we should be able to test existence without instantiating a ` LocalIndex ` .
return new LocalIndex ( getRootDataDir ( ) . getAbsolutePath ( ) , getApplicationID ( ) , name ) . exists ( ) ;


signature:
public class OfflineClient { /** * List existing offline indices .
 * Only indices that * actually exist * on disk are listed . If an instance was created but never synced or written
 * to , it will not appear in the list .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request listIndexesOfflineAsync ( @ NonNull CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return listIndexesOfflineSync ( ) ; } } . start ( ) ;


signature:
public class OfflineClient { /** * List existing offline indices .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances . Only indices that
 * * actually exist * on disk are listed . If an instance was created but never synced or written to , it will not
 * appear in the list .
 * @ return A JSON object with an ` items ` attribute containing the indices details as JSON objects . */
private JSONObject listIndexesOfflineSync ( ) throws AlgoliaException { } }

implementation:
try { final String rootDataPath = getRootDataDir ( ) . getAbsolutePath ( ) ; final File appDir = getAppDir ( ) ; final File [ ] directories = appDir . listFiles ( new FileFilter ( ) { @ Override public boolean accept ( File pathname ) { return pathname . isDirectory ( ) ; } } ) ; JSONObject response = new JSONObject ( ) ; JSONArray items = new JSONArray ( ) ; if ( directories != null ) { for ( File directory : directories ) { final String name = directory . getName ( ) ; if ( hasOfflineData ( name ) ) { items . put ( new JSONObject ( ) . put ( "name" , name ) ) ; // TODO : Do we need other data as in the online API ?
} } } response . put ( "items" , items ) ; return response ; } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
}


signature:
public class OfflineClient { /** * Delete an offline index .
 * This deletes the data on disk . If the index does not exist , this method does nothing .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * @ param indexName Name of index to delete .
 * @ return A JSON object . */
public Request deleteIndexOfflineAsync ( final @ NonNull String indexName , CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler , localBuildExecutorService ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return deleteIndexOfflineSync ( indexName ) ; } } . start ( ) ;


signature:
public class OfflineClient { /** * Delete an offline index .
 * This deletes the data on disk . If the index does not exist , this method does nothing .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * @ param indexName Name of index to delete .
 * @ return A JSON response . */
private JSONObject deleteIndexOfflineSync ( final @ NonNull String indexName ) throws AlgoliaException { } }

implementation:
try { FileUtils . deleteRecursive ( getIndexDir ( indexName ) ) ; return new JSONObject ( ) . put ( "deletedAt" , DateUtils . iso8601String ( new Date ( ) ) ) ; } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
}


signature:
public class OfflineClient { /** * Move an existing offline index .
 * * * Warning : * * This will overwrite the destination index if it exists .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * @ param srcIndexName Name of index to move .
 * @ param dstIndexName The new index name .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request moveIndexOfflineAsync ( final @ NonNull String srcIndexName , final @ NonNull String dstIndexName , CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler , localBuildExecutorService ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return moveIndexOfflineSync ( srcIndexName , dstIndexName ) ; } } . start ( ) ;


signature:
public class OfflineClient { /** * Move an existing offline index .
 * * * Warning : * * This will overwrite the destination index if it exists .
 * * * Note : * * This applies both to { @ link MirroredIndex } and { @ link OfflineIndex } instances .
 * @ param srcIndexName Name of index to move .
 * @ param dstIndexName The new index name .
 * @ return A JSON response . */
private JSONObject moveIndexOfflineSync ( final @ NonNull String srcIndexName , final @ NonNull String dstIndexName ) throws AlgoliaException { } }

implementation:
try { final File srcDir = getIndexDir ( srcIndexName ) ; final File dstDir = getIndexDir ( dstIndexName ) ; if ( dstDir . exists ( ) ) { FileUtils . deleteRecursive ( dstDir ) ; } if ( srcDir . renameTo ( dstDir ) ) { return new JSONObject ( ) . put ( "updatedAt" , DateUtils . iso8601String ( new Date ( ) ) ) ; } else { throw new AlgoliaException ( "Could not move index" ) ; } } catch ( JSONException e ) { throw new RuntimeException ( e ) ; // should never happen
}


signature: public class OfflineClient { static protected JSONObject parseSearchResults ( Response searchResults ) throws AlgoliaException { } }

implementation:
try { if ( searchResults . getStatusCode ( ) == 200 ) { if ( searchResults . getData ( ) != null ) { String jsonString = new String ( searchResults . getData ( ) , "UTF-8" ) ; return new JSONObject ( jsonString ) ; } else { // may happen when building : no output
return new JSONObject ( ) ; } } else { throw new AlgoliaException ( searchResults . getErrorMessage ( ) , searchResults . getStatusCode ( ) ) ; } } catch ( JSONException | UnsupportedEncodingException e ) { throw new AlgoliaException ( "Offline Core returned invalid JSON" , e ) ; }


signature:
public class FileUtils { /** * Delete a file or directory , recursively deleting any descendant files / directories if it ' s a directory .
 * @ param item The item to delete .
 * @ return true if success , false if error . */
public static boolean deleteRecursive ( @ NonNull File item ) { } }

implementation: boolean ok = true ; if ( item . isDirectory ( ) ) { for ( File child : item . listFiles ( ) ) { ok = ok && deleteRecursive ( child ) ; } } ok = ok && item . delete ( ) ; return ok ;


signature:
public class FileUtils { /** * Write a stream of bytes to a file .
 * @ param destinationFile The file to be written to . The parent directory must exist . If the file already exists ,
 * it will be overwritten .
 * @ param content The bytes to write .
 * @ throws IOException if anything goes wrong . */
public static void writeFile ( @ NonNull File destinationFile , @ NonNull InputStream content ) throws IOException { } }

implementation:
byte [ ] buffer = new byte [ 64 * 1024 ] ; // 64 kB buffer
FileOutputStream outputStream = new FileOutputStream ( destinationFile ) ; try { int bytesRead ; while ( ( bytesRead = content . read ( buffer ) ) >= 0 ) { outputStream . write ( buffer , 0 , bytesRead ) ; } } finally { content . close ( ) ; outputStream . close ( ) ; }


signature:
public class RequestOptions { /** * Set a URL parameter ( untyped version ) .
 * Whenever possible , you should use a typed accessor .
 * @ param name Name of the parameter .
 * @ param value Value of the parameter , or ` null ` to remove it . */
public RequestOptions setUrlParameter ( @ NonNull String name , @ Nullable String value ) { } }

implementation: if ( value == null ) { urlParameters . remove ( name ) ; } else { urlParameters . put ( name , value ) ; } return this ;


signature:
public class AbstractClient { /** * Set an HTTP header that will be sent with every request .
 * @ param name Header name .
 * @ param value Value for the header . If null , the header will be removed . */
public void setHeader ( @ NonNull String name , @ Nullable String value ) { } }

implementation: if ( value == null ) { headers . remove ( name ) ; } else { headers . put ( name , value ) ; }


signature:
public class AbstractClient { /** * Add a software library to the list of user agents .
 * @ param userAgent The library to add . */
public void addUserAgent ( @ NonNull LibraryVersion userAgent ) { } }

implementation: if ( ! userAgents . contains ( userAgent ) ) { userAgents . add ( userAgent ) ; } updateUserAgents ( ) ;


signature:
public class AbstractClient { /** * Reads the InputStream as UTF - 8
 * @ param stream the InputStream to read
 * @ return the stream ' s content as a String
 * @ throws IOException if the stream can ' t be read , decoded as UTF - 8 or closed */
private static String _toCharArray ( InputStream stream ) throws IOException { } }

implementation: InputStreamReader is = new InputStreamReader ( stream , "UTF-8" ) ; StringBuilder builder = new StringBuilder ( ) ; char [ ] buf = new char [ 1000 ] ; int l = 0 ; while ( l >= 0 ) { builder . append ( buf , 0 , l ) ; l = is . read ( buf ) ; } is . close ( ) ; return builder . toString ( ) ;


signature:
public class AbstractClient { /** * Reads the InputStream into a byte array
 * @ param stream the InputStream to read
 * @ return the stream ' s content as a byte [ ]
 * @ throws AlgoliaException if the stream can ' t be read or flushed */
private static byte [ ] _toByteArray ( InputStream stream ) throws AlgoliaException { } }

implementation: ByteArrayOutputStream out = new ByteArrayOutputStream ( ) ; int read ; byte [ ] buffer = new byte [ 1024 ] ; try { while ( ( read = stream . read ( buffer , 0 , buffer . length ) ) != - 1 ) { out . write ( buffer , 0 , read ) ; } out . flush ( ) ; return out . toByteArray ( ) ; } catch ( IOException e ) { throw new AlgoliaException ( "Error while reading stream: " + e . getMessage ( ) ) ; }


signature:
public class AbstractClient { /** * Send the query according to parameters and returns its result as a JSONObject
 * @ param m HTTP Method to use
 * @ param url Endpoint URL , * without query string * . The query string is handled by ` urlParameters ` .
 * @ param urlParameters URL parameters
 * @ param json optional JSON Object to send
 * @ param hostsArray array of hosts to try successively
 * @ param connectTimeout maximum wait time to open connection
 * @ param readTimeout maximum time to read data on socket
 * @ return a JSONObject containing the resulting data or error
 * @ throws AlgoliaException if the request data is not valid json */
private JSONObject _request ( @ NonNull Method m , @ NonNull String url , @ Nullable Map < String , String > urlParameters , @ Nullable String json , @ NonNull List < String > hostsArray , int connectTimeout , int readTimeout , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation: try { return _getJSONObject ( _requestRaw ( m , url , urlParameters , json , hostsArray , connectTimeout , readTimeout , requestOptions ) ) ; } catch ( JSONException e ) { throw new AlgoliaException ( "JSON decode error:" + e . getMessage ( ) ) ; } catch ( UnsupportedEncodingException e ) { throw new AlgoliaException ( "UTF-8 decode error:" + e . getMessage ( ) ) ; }


signature:
public class AbstractClient { /** * Send the query according to parameters and returns its result as a JSONObject
 * @ param m HTTP Method to use
 * @ param url Endpoint URL , * without query string * . The query string is handled by ` urlParameters ` .
 * @ param urlParameters URL parameters
 * @ param json ( optional ) JSON body
 * @ param hostsArray array of hosts to try successively
 * @ param connectTimeout maximum wait time to open connection
 * @ param readTimeout maximum time to read data on socket
 * @ return a JSONObject containing the resulting data or error
 * @ throws AlgoliaException in case of connection or data handling error */
private byte [ ] _requestRaw ( @ NonNull Method m , @ NonNull String url , @ Nullable Map < String , String > urlParameters , @ Nullable String json , @ NonNull List < String > hostsArray , int connectTimeout , int readTimeout , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
String requestMethod ; List < Exception > errors = new ArrayList < > ( hostsArray . size ( ) ) ; // for each host
for ( String host : hostsArray ) { switch ( m ) { case DELETE : requestMethod = "DELETE" ; break ; case GET : requestMethod = "GET" ; break ; case POST : requestMethod = "POST" ; break ; case PUT : requestMethod = "PUT" ; break ; default : throw new IllegalArgumentException ( "Method " + m + " is not supported" ) ; } InputStream stream = null ; HttpURLConnection hostConnection = null ; try { // Compute final URL parameters .
final Map < String , String > parameters = new HashMap < > ( ) ; if ( urlParameters != null ) { parameters . putAll ( urlParameters ) ; } if ( requestOptions != null ) { parameters . putAll ( requestOptions . urlParameters ) ; } // Build URL .
String urlString = "https://" + host + url ; if ( ! parameters . isEmpty ( ) ) { urlString += "?" + AbstractQuery . build ( parameters ) ; } URL hostURL = new URL ( urlString ) ; // Open connection .
hostConnection = ( HttpURLConnection ) hostURL . openConnection ( ) ; // set timeouts
hostConnection . setRequestMethod ( requestMethod ) ; hostConnection . setConnectTimeout ( connectTimeout ) ; hostConnection . setReadTimeout ( readTimeout ) ; // Headers
hostConnection . setRequestProperty ( "Accept-Encoding" , "gzip" ) ; hostConnection . setRequestProperty ( "X-Algolia-Application-Id" , this . applicationID ) ; // If API key is too big , send it in the request ' s body ( if applicable ) .
if ( this . apiKey != null && this . apiKey . length ( ) > MAX_API_KEY_LENGTH && json != null ) { try { final JSONObject body = new JSONObject ( json ) ; body . put ( "apiKey" , this . apiKey ) ; json = body . toString ( ) ; } catch ( JSONException e ) { throw new AlgoliaException ( "Failed to patch JSON body" ) ; } } else { hostConnection . setRequestProperty ( "X-Algolia-API-Key" , this . apiKey ) ; } // Client - level headers
for ( Map . Entry < String , String > entry : this . headers . entrySet ( ) ) { hostConnection . setRequestProperty ( entry . getKey ( ) , entry . getValue ( ) ) ; } // Request - level headers
if ( requestOptions != null ) { for ( Map . Entry < String , String > entry : requestOptions . headers . entrySet ( ) ) { hostConnection . setRequestProperty ( entry . getKey ( ) , entry . getValue ( ) ) ; } } // set user agent
hostConnection . setRequestProperty ( "User-Agent" , userAgentRaw ) ; // write JSON entity
if ( json != null ) { if ( ! ( requestMethod . equals ( "PUT" ) || requestMethod . equals ( "POST" ) ) ) { throw new IllegalArgumentException ( "Method " + m + " cannot enclose entity" ) ; } hostConnection . setRequestProperty ( "Content-type" , "application/json; charset=UTF-8" ) ; hostConnection . setDoOutput ( true ) ; OutputStreamWriter writer = new OutputStreamWriter ( hostConnection . getOutputStream ( ) , "UTF-8" ) ; writer . write ( json ) ; writer . close ( ) ; } // read response
int code = hostConnection . getResponseCode ( ) ; final boolean codeIsError = code / 100 != 2 ; stream = codeIsError ? hostConnection . getErrorStream ( ) : hostConnection . getInputStream ( ) ; // As per the official Java docs ( not the Android docs ) :
// - ` getErrorStream ( ) ` may return null = > we have to handle this case .
// See < https : / / docs . oracle . com / javase / 7 / docs / api / java / net / HttpURLConnection . html # getErrorStream ( ) > .
// - ` getInputStream ( ) ` should never return null . . . but let ' s err on the side of caution .
// See < https : / / docs . oracle . com / javase / 7 / docs / api / java / net / URLConnection . html # getInputStream ( ) > .
if ( stream == null ) { throw new IOException ( String . format ( "Null stream when reading connection (status %d)" , code ) ) ; } hostStatuses . put ( host , new HostStatus ( true ) ) ; final byte [ ] rawResponse ; String encoding = hostConnection . getContentEncoding ( ) ; if ( encoding != null && encoding . equals ( "gzip" ) ) { rawResponse = _toByteArray ( new GZIPInputStream ( stream ) ) ; } else { rawResponse = _toByteArray ( stream ) ; } // handle http errors
if ( codeIsError ) { if ( code / 100 == 4 ) { consumeQuietly ( hostConnection ) ; throw new AlgoliaException ( _getJSONObject ( rawResponse ) . getString ( "message" ) , code ) ; } else { consumeQuietly ( hostConnection ) ; errors . add ( new AlgoliaException ( _toCharArray ( stream ) , code ) ) ; continue ; } } return rawResponse ; } catch ( JSONException e ) { // fatal
consumeQuietly ( hostConnection ) ; throw new AlgoliaException ( "Invalid JSON returned by server" , e ) ; } catch ( UnsupportedEncodingException e ) { // fatal
consumeQuietly ( hostConnection ) ; throw new AlgoliaException ( "Invalid encoding returned by server" , e ) ; } catch ( IOException e ) { // host error , continue on the next host
hostStatuses . put ( host , new HostStatus ( false ) ) ; consumeQuietly ( hostConnection ) ; errors . add ( e ) ; } finally { if ( stream != null ) { try { stream . close ( ) ; } catch ( IOException e ) { e . printStackTrace ( ) ; } } } } String errorMessage = "All hosts failed: " + Arrays . toString ( errors . toArray ( ) ) ; // When several errors occurred , use the last one as the cause for the returned exception .
Throwable lastError = errors . get ( errors . size ( ) - 1 ) ; throw new AlgoliaException ( errorMessage , lastError ) ;


signature:
public class AbstractClient { /** * Ensures that the entity content is fully consumed and the content stream , if exists ,
 * is closed . */
private static void consumeQuietly ( final HttpURLConnection connection ) { } }

implementation:
try { int read = 0 ; while ( read != - 1 ) { read = connection . getInputStream ( ) . read ( ) ; } connection . getInputStream ( ) . close ( ) ; read = 0 ; while ( read != - 1 ) { read = connection . getErrorStream ( ) . read ( ) ; } connection . getErrorStream ( ) . close ( ) ; connection . disconnect ( ) ; } catch ( IOException e ) { // no inputStream to close
}


signature:
public class AbstractClient { /** * Get the hosts that are not considered down in a given list .
 * @ param hosts a list of hosts whose { @ link HostStatus } will be checked .
 * @ return the hosts considered up , or all hosts if none is known to be reachable . */
private List < String > hostsThatAreUp ( List < String > hosts ) { } }

implementation: List < String > upHosts = new ArrayList < > ( ) ; for ( String host : hosts ) { if ( isUpOrCouldBeRetried ( host ) ) { upHosts . add ( host ) ; } } return upHosts . isEmpty ( ) ? hosts : upHosts ;


signature:
public class PlacesQuery { /** * Force to * first * search around a specific latitude / longitude .
 * The default is to search around the location of the user determined via his IP address ( geoip ) .
 * @ param location The location to start the search at , or ` null ` to use the default . */
public @ NonNull PlacesQuery setAroundLatLng ( LatLng location ) { } }

implementation: if ( location == null ) { return set ( KEY_AROUND_LAT_LNG , null ) ; } else { return set ( KEY_AROUND_LAT_LNG , location . lat + "," + location . lng ) ; }


signature:
public class PlacesQuery { /** * Change the radius for around latitude / longitude queries .
 * @ param radius The radius to set , or { @ link # RADIUS _ ALL } to disable stopping at a specific radius , or ` null ` to
 * use the default . */
public @ NonNull PlacesQuery setAroundRadius ( Integer radius ) { } }

implementation: if ( radius == PlacesQuery . RADIUS_ALL ) { return set ( KEY_AROUND_RADIUS , "all" ) ; } return set ( KEY_AROUND_RADIUS , radius ) ;


signature:
public class PlacesQuery { /** * Get the current radius for around latitude / longitude queries .
 * @ return Query . RADIUS _ ALL if set to ' all ' . */
public Integer getAroundRadius ( ) { } }

implementation: final String value = get ( KEY_AROUND_RADIUS ) ; if ( value != null && value . equals ( "all" ) ) { return PlacesQuery . RADIUS_ALL ; } return parseInt ( value ) ;


signature:
public class PlacesQuery { /** * Set the type of place to search for .
 * @ param type Type of place to search for . */
public @ NonNull PlacesQuery setType ( Type type ) { } }

implementation: if ( type == null ) { set ( KEY_TYPE , null ) ; } else { switch ( type ) { case CITY : set ( KEY_TYPE , "city" ) ; break ; case COUNTRY : set ( KEY_TYPE , "country" ) ; break ; case ADDRESS : set ( KEY_TYPE , "address" ) ; break ; case BUS_STOP : set ( KEY_TYPE , "busStop" ) ; break ; case TRAIN_STATION : set ( KEY_TYPE , "trainStation" ) ; break ; case TOWN_HALL : set ( KEY_TYPE , "townhall" ) ; break ; case AIRPORT : set ( KEY_TYPE , "airport" ) ; break ; } } return this ;


signature:
public class PlacesQuery { /** * Parse a query object from a URL query parameter string .
 * @ param queryParameters URL query parameter string .
 * @ return The parsed query object . */
protected static @ NonNull PlacesQuery parse ( @ NonNull String queryParameters ) { } }

implementation: PlacesQuery query = new PlacesQuery ( ) ; query . parseFrom ( queryParameters ) ; return query ;


signature:
public class PlacesQuery { /** * Set a parameter in an untyped fashion .
 * This low - level accessor is intended to access parameters that this client does not yet support .
 * @ param name The parameter ' s name .
 * @ param value The parameter ' s value , or null to remove it .
 * It will first be converted to a String by the ` toString ( ) ` method .
 * @ return This instance ( used to chain calls ) . */
@ Override public @ NonNull PlacesQuery set ( @ NonNull String name , @ Nullable Object value ) { } }

implementation: return ( PlacesQuery ) super . set ( name , value ) ;


signature:
public class BrowseIterator { /** * Start the iteration . */
public void start ( ) { } }

implementation: if ( started ) { throw new IllegalStateException ( ) ; } started = true ; request = index . browseAsync ( query , requestOptions , completionHandler ) ;


signature:
public class Searchable { /** * Search inside this index ( asynchronously ) .
 * @ param query Search parameters . May be null to use an empty query .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request searchAsync ( @ Nullable Query query , @ Nullable CompletionHandler completionHandler ) { } }

implementation:
return searchAsync ( query , /* requestOptions : */
null , completionHandler ) ;


signature:
public class Searchable { /** * Perform a search with disjunctive facets , generating as many queries as number of disjunctive facets ( helper ) .
 * @ param query The query .
 * @ param disjunctiveFacets List of disjunctive facets .
 * @ param refinements The current refinements , mapping facet names to a list of values .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request searchDisjunctiveFacetingAsync ( @ NonNull Query query , @ NonNull final Collection < String > disjunctiveFacets , @ NonNull final Map < String , ? extends Collection < String > > refinements , @ Nullable final RequestOptions requestOptions , @ NonNull final CompletionHandler completionHandler ) { } }

implementation: throw new UnsupportedOperationException ( "make sure to override searchDisjunctiveFacetingAsync for custom backend" ) ;


signature:
public class Searchable { /** * Search for some text in a facet values , optionally restricting the returned values to those contained in objects matching other ( regular ) search criteria .
 * @ param facetName The name of the facet to search . It must have been declared in the index ' s ` attributesForFaceting ` setting with the ` searchable ( ) ` modifier .
 * @ param facetText The text to search for in the facet ' s values .
 * @ param query An optional query to take extra search parameters into account . There parameters apply to index objects like in a regular search query . Only facet values contained in the matched objects will be returned
 * @ param requestOptions Request - specific options .
 * @ param handler A Completion handler that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request searchForFacetValuesAsync ( @ NonNull String facetName , @ NonNull String facetText , @ Nullable Query query , @ Nullable final RequestOptions requestOptions , @ NonNull final CompletionHandler handler ) { } }

implementation: throw new UnsupportedOperationException ( "make sure to override searchForFacetValuesAsync for custom backend" ) ;


signature:
public class Client { /** * List existing indexes .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request listIndexesAsync ( @ Nullable final RequestOptions requestOptions , @ NonNull CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return listIndexes ( requestOptions ) ; } } . start ( ) ;


signature:
public class Client { /** * Delete an index .
 * @ param indexName Name of index to delete .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request deleteIndexAsync ( final @ NonNull String indexName , @ Nullable final RequestOptions requestOptions , CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return deleteIndex ( indexName , requestOptions ) ; } } . start ( ) ;


signature:
public class Client { /** * Delete an index .
 * @ param indexName Name of index to delete .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request deleteIndexAsync ( final @ NonNull String indexName , CompletionHandler completionHandler ) { } }

implementation:
return deleteIndexAsync ( indexName , /* requestOptions : */
null , completionHandler ) ;


signature:
public class Client { /** * Move an existing index .
 * If the destination index already exists , its specific API keys will be preserved and the source index specific
 * API keys will be added .
 * @ param srcIndexName Name of index to move .
 * @ param dstIndexName The new index name .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request moveIndexAsync ( final @ NonNull String srcIndexName , final @ NonNull String dstIndexName , @ Nullable final RequestOptions requestOptions , CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return moveIndex ( srcIndexName , dstIndexName , requestOptions ) ; } } . start ( ) ;


signature:
public class Client { /** * Move an existing index .
 * If the destination index already exists , its specific API keys will be preserved and the source index specific
 * API keys will be added .
 * @ param srcIndexName Name of index to move .
 * @ param dstIndexName The new index name .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request moveIndexAsync ( final @ NonNull String srcIndexName , final @ NonNull String dstIndexName , CompletionHandler completionHandler ) { } }

implementation:
return moveIndexAsync ( srcIndexName , dstIndexName , /* requestOptions : */
null , completionHandler ) ;


signature:
public class Client { /** * Run multiple queries , potentially targeting multiple indexes , with one API call .
 * @ param queries The queries to run .
 * @ param strategy The strategy to use .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request multipleQueriesAsync ( final @ NonNull List < IndexQuery > queries , final MultipleQueriesStrategy strategy , @ Nullable final RequestOptions requestOptions , @ NonNull CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return multipleQueries ( queries , strategy == null ? null : strategy . toString ( ) , requestOptions ) ; } } . start ( ) ;


signature:
public class Client { /** * Run multiple queries , potentially targeting multiple indexes , with one API call .
 * @ param queries The queries to run .
 * @ param strategy The strategy to use .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request multipleQueriesAsync ( final @ NonNull List < IndexQuery > queries , final MultipleQueriesStrategy strategy , @ NonNull CompletionHandler completionHandler ) { } }

implementation:
return multipleQueriesAsync ( queries , strategy , /* requestOptions : */
null , completionHandler ) ;


signature:
public class Client { /** * Batch operations .
 * @ param operations List of operations .
 * @ param requestOptions Request - specific options .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request batchAsync ( final @ NonNull JSONArray operations , @ Nullable final RequestOptions requestOptions , CompletionHandler completionHandler ) { } }

implementation: return new AsyncTaskRequest ( completionHandler ) { @ NonNull @ Override protected JSONObject run ( ) throws AlgoliaException { return batch ( operations , requestOptions ) ; } } . start ( ) ;


signature:
public class Client { /** * Batch operations .
 * @ param operations List of operations .
 * @ param completionHandler The listener that will be notified of the request ' s outcome .
 * @ return A cancellable request . */
public Request batchAsync ( final @ NonNull JSONArray operations , CompletionHandler completionHandler ) { } }

implementation:
return batchAsync ( operations , /* requestOptions : */
null , completionHandler ) ;


signature:
public class Client { /** * List all existing indexes
 * @ param requestOptions Request - specific options .
 * @ return a JSON Object in the form :
 * { " items " : [ { " name " : " contacts " , " createdAt " : " 2013-01-18T15:33:13.556Z " } ,
 * { " name " : " notes " , " createdAt " : " 2013-01-18T15:33:13.556Z " } ] } */
protected JSONObject listIndexes ( @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
return getRequest ( "/1/indexes/" , /* urlParameters : */
null , false , requestOptions ) ;


signature:
public class Client { /** * Delete an index
 * @ param requestOptions Request - specific options .
 * @ param indexName the name of index to delete
 * @ return an object containing a " deletedAt " attribute */
protected JSONObject deleteIndex ( String indexName , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
try { return deleteRequest ( "/1/indexes/" + URLEncoder . encode ( indexName , "UTF-8" ) , /* urlParameters : */
null , requestOptions ) ; } catch ( UnsupportedEncodingException e ) { throw new RuntimeException ( e ) ; }


signature:
public class Client { /** * Move an existing index .
 * @ param srcIndexName the name of index to copy .
 * @ param dstIndexName the new index name that will contains a copy of srcIndexName ( destination will be overriten if it already exist ) .
 * @ param requestOptions Request - specific options . */
protected JSONObject moveIndex ( String srcIndexName , String dstIndexName , @ Nullable RequestOptions requestOptions ) throws AlgoliaException { } }

implementation:
try { JSONObject content = new JSONObject ( ) ; content . put ( "operation" , "move" ) ; content . put ( "destination" , dstIndexName ) ; return postRequest ( "/1/indexes/" + URLEncoder . encode ( srcIndexName , "UTF-8" ) + "/operation" , /* urlParameters : */
null , content . toString ( ) , false , requestOptions ) ; } catch ( UnsupportedEncodingException e ) { throw new RuntimeException ( e ) ; } catch ( JSONException e ) { throw new AlgoliaException ( e . getMessage ( ) ) ; }


signature:
public class ExpiringCache { /** * Puts a value in the cache , computing an expiration time
 * @ return the previous value for this key , if any */
public V put ( K key , V value ) { } }

implementation: V previous = null ; synchronized ( this ) { long timeout = System . currentTimeMillis ( ) + TimeUnit . MILLISECONDS . convert ( expirationTimeout , expirationTimeUnit ) ; final Pair < V , Long > previousPair = lruCache . put ( key , new Pair < > ( value , timeout ) ) ; if ( previousPair != null ) { previous = previousPair . first ; } } return previous ;


signature:
public class ExpiringCache { /** * Get a value from the cache
 * @ return the cached value if it is still valid , else null . */
synchronized public V get ( K key ) { } }

implementation: final Pair < V , Long > cachePair = lruCache . get ( key ) ; if ( cachePair != null && cachePair . first != null ) { if ( cachePair . second > System . currentTimeMillis ( ) ) { return cachePair . first ; } else { lruCache . remove ( key ) ; } } return null ;


signature:
public class HistogramLogProcessor { /** * Run the log processor with the currently provided arguments . */
@ Override public void run ( ) { } }

implementation:
PrintStream timeIntervalLog = null ; PrintStream histogramPercentileLog = System . out ; Double firstStartTime = 0.0 ; boolean timeIntervalLogLegendWritten = false ; if ( config . listTags ) { Set < String > tags = new TreeSet < String > ( ) ; EncodableHistogram histogram ; boolean nullTagFound = false ; while ( ( histogram = getIntervalHistogram ( ) ) != null ) { String tag = histogram . getTag ( ) ; if ( tag != null ) { tags . add ( histogram . getTag ( ) ) ; } else { nullTagFound = true ; } } System . out . println ( "Tags found in input file: " ) ; if ( nullTagFound ) { System . out . println ( "[NO TAG (default)]" ) ; } for ( String tag : tags ) { System . out . println ( tag ) ; } // listtags does nothing other than list tags :
return ; } final String logFormat = buildLogFormat ( config . logFormatCsv ) ; try { if ( config . outputFileName != null ) { try { timeIntervalLog = new PrintStream ( new FileOutputStream ( config . outputFileName ) , false , "UTF-8" ) ; outputTimeRange ( timeIntervalLog , "Interval percentile log" ) ; } catch ( FileNotFoundException ex ) { System . err . println ( "Failed to open output file " + config . outputFileName ) ; } catch ( UnsupportedEncodingException e ) { System . err . println ( "Unsupported encoding: UTF-8" ) ; } String hgrmOutputFileName = config . outputFileName + ".hgrm" ; try { histogramPercentileLog = new PrintStream ( new FileOutputStream ( hgrmOutputFileName ) , false , "UTF-8" ) ; outputTimeRange ( histogramPercentileLog , "Overall percentile distribution" ) ; } catch ( FileNotFoundException ex ) { System . err . println ( "Failed to open percentiles histogram output file " + hgrmOutputFileName ) ; } catch ( UnsupportedEncodingException e ) { System . err . println ( "Unsupported encoding: UTF-8" ) ; } } EncodableHistogram intervalHistogram = getIntervalHistogram ( config . tag ) ; Histogram accumulatedRegularHistogram = null ; DoubleHistogram accumulatedDoubleHistogram = null ; if ( intervalHistogram != null ) { // Shape the accumulated histogram like the histograms in the log file ( but clear their contents ) :
if ( intervalHistogram instanceof DoubleHistogram ) { accumulatedDoubleHistogram = ( ( DoubleHistogram ) intervalHistogram ) . copy ( ) ; accumulatedDoubleHistogram . reset ( ) ; accumulatedDoubleHistogram . setAutoResize ( true ) ; } else { accumulatedRegularHistogram = ( ( Histogram ) intervalHistogram ) . copy ( ) ; accumulatedRegularHistogram . reset ( ) ; accumulatedRegularHistogram . setAutoResize ( true ) ; } } while ( intervalHistogram != null ) { if ( intervalHistogram instanceof DoubleHistogram ) { if ( accumulatedDoubleHistogram == null ) { throw new IllegalStateException ( "Encountered a DoubleHistogram line in a log of Histograms." ) ; } accumulatedDoubleHistogram . add ( ( DoubleHistogram ) intervalHistogram ) ; } else { if ( accumulatedRegularHistogram == null ) { throw new IllegalStateException ( "Encountered a Histogram line in a log of DoubleHistograms." ) ; } accumulatedRegularHistogram . add ( ( Histogram ) intervalHistogram ) ; } if ( ( firstStartTime == 0.0 ) && ( logReader . getStartTimeSec ( ) != 0.0 ) ) { firstStartTime = logReader . getStartTimeSec ( ) ; outputStartTime ( histogramPercentileLog , firstStartTime ) ; if ( timeIntervalLog != null ) { outputStartTime ( timeIntervalLog , firstStartTime ) ; } } if ( timeIntervalLog != null ) { if ( ! timeIntervalLogLegendWritten ) { timeIntervalLogLegendWritten = true ; timeIntervalLog . println ( buildLegend ( config . logFormatCsv ) ) ; } Object [ ] statistics = intervalHistogram instanceof DoubleHistogram ? buildDoubleHistogramStatistics ( ( DoubleHistogram ) intervalHistogram , accumulatedDoubleHistogram ) : buildRegularHistogramStatistics ( ( Histogram ) intervalHistogram , accumulatedRegularHistogram ) ; timeIntervalLog . format ( Locale . US , logFormat , statistics ) ; } intervalHistogram = getIntervalHistogram ( config . tag ) ; } if ( accumulatedDoubleHistogram != null ) { accumulatedDoubleHistogram . outputPercentileDistribution ( histogramPercentileLog , config . percentilesOutputTicksPerHalf , config . outputValueUnitRatio , config . logFormatCsv ) ; } else { if ( accumulatedRegularHistogram == null ) { // If there were no histograms in the log file , we still need an empty histogram for the
// one line output ( shape / range doesn ' t matter because it is empty ) :
accumulatedRegularHistogram = new Histogram ( 1000000L , 2 ) ; } accumulatedRegularHistogram . outputPercentileDistribution ( histogramPercentileLog , config . percentilesOutputTicksPerHalf , config . outputValueUnitRatio , config . logFormatCsv ) ; } } finally { if ( config . outputFileName != null ) { closeQuietly ( timeIntervalLog ) ; closeQuietly ( histogramPercentileLog ) ; } }


signature:
public class PerformanceStats { /** * Combines { @ link PerformanceStats } instances , e . g . from different Simulator Workers .
 * For the real - time performance monitor during the { @ link TestPhase # RUN } the
 * maximum value should be set , so we get the maximum operation count and throughput values of all { @ link PerformanceStats }
 * instances of the last interval .
 * For the total performance number and the performance per Simulator Agent , the added values should be set , so we get the
 * summed up operation count and throughput values .
 * The method always sets the maximum values for latency .
 * @ param other { @ link PerformanceStats } which should be added to this instance
 * @ param addOperationCountAndThroughput { @ code true } if operation count and throughput should be added ,
 * { @ code false } if the maximum value should be set */
public void add ( PerformanceStats other , boolean addOperationCountAndThroughput ) { } }

implementation: if ( other . isEmpty ( ) ) { return ; } if ( isEmpty ( ) ) { operationCount = other . operationCount ; intervalThroughput = other . intervalThroughput ; totalThroughput = other . totalThroughput ; intervalLatencyAvgNanos = other . intervalLatencyAvgNanos ; intervalLatency999PercentileNanos = other . intervalLatency999PercentileNanos ; intervalLatencyMaxNanos = other . intervalLatencyMaxNanos ; } else { if ( addOperationCountAndThroughput ) { operationCount += other . operationCount ; intervalThroughput += other . intervalThroughput ; totalThroughput += other . totalThroughput ; } else { operationCount = max ( operationCount , other . operationCount ) ; intervalThroughput = max ( intervalThroughput , other . intervalThroughput ) ; totalThroughput = max ( totalThroughput , other . totalThroughput ) ; } intervalLatencyAvgNanos = max ( intervalLatencyAvgNanos , other . intervalLatencyAvgNanos ) ; intervalLatency999PercentileNanos = max ( intervalLatency999PercentileNanos , other . intervalLatency999PercentileNanos ) ; intervalLatencyMaxNanos = max ( intervalLatencyMaxNanos , other . intervalLatencyMaxNanos ) ; }


signature:
public class ThreadSpawner { /** * Spawns a new thread for the given { @ link Runnable } .
 * @ param namePrefix the name prefix for the thread
 * @ param runnable the { @ link Runnable } to execute
 * @ return the created thread */
public Thread spawn ( String namePrefix , Runnable runnable ) { } }

implementation: checkNotNull ( namePrefix , "namePrefix can't be null" ) ; checkNotNull ( runnable , "runnable can't be null" ) ; String name = newName ( namePrefix ) ; Thread thread ; if ( throwException ) { thread = new ThrowExceptionThread ( name , runnable ) ; thread . setUncaughtExceptionHandler ( exceptionHandler ) ; } else { thread = new ReportExceptionThread ( testId , name , runnable ) ; } threads . add ( thread ) ; thread . start ( ) ; return thread ;


signature:
public class ThreadSpawner { /** * Waits for all threads to finish .
 * If { @ link # throwException } is < code > true < / code > this method will throw the first occurred exception of a thread . */
public void awaitCompletion ( ) { } }

implementation: for ( Thread thread : threads ) { try { thread . join ( ) ; } catch ( InterruptedException e ) { throw rethrow ( e ) ; } } if ( caughtException != null ) { throw rethrow ( caughtException ) ; }


signature:
public class VersionUtils { /** * Compares two version strings .
 * Use this instead of String . compareTo ( ) for a non - lexicographical comparison that works for version strings ,
 * e . g . versionCompare ( " 1.10 " , " 1.6 " ) .
 * Warning :
 * - It does not work if " 1.10 " is supposed to be equal to " 1.10.0 " .
 * - Everything after a " - " is ignored .
 * @ param firstVersionString a string of ordinal numbers separated by decimal points .
 * @ param secondVersionString a string of ordinal numbers separated by decimal points .
 * @ return The result is a negative integer if firstVersionString is _ numerically _ less than secondVersionString .
 * The result is a positive integer if firstVersionString is _ numerically _ greater than secondVersionString .
 * The result is zero if the strings are _ numerically _ equal . */
public static int versionCompare ( String firstVersionString , String secondVersionString ) { } }

implementation:
String [ ] firstVersion = parseVersionString ( firstVersionString ) ; String [ ] secondVersion = parseVersionString ( secondVersionString ) ; int i = 0 ; // set index to first non - equal ordinal or length of shortest version string
while ( i < firstVersion . length && i < secondVersion . length && firstVersion [ i ] . equals ( secondVersion [ i ] ) ) { i ++ ; } if ( i < firstVersion . length && i < secondVersion . length ) { // compare first non - equal ordinal number
int diff = Integer . valueOf ( firstVersion [ i ] ) . compareTo ( Integer . valueOf ( secondVersion [ i ] ) ) ; return Integer . signum ( diff ) ; } else { // the strings are equal or one string is a substring of the other
// e . g . " 1.2.3 " = " 1.2.3 " or " 1.2.3 " < " 1.2.3.4"
return Integer . signum ( firstVersion . length - secondVersion . length ) ; }


signature:
public class ExceptionReporter { /** * Writes the cause to file .
 * @ param testId the id of the test that caused the exception . Is allowed to be < tt > null < / tt > if it is not known which test
 * caused the problem .
 * @ param cause the Throwable that should be reported . */
public static void report ( String testId , Throwable cause ) { } }

implementation: if ( cause == null ) { LOGGER . fatal ( "Can't call report with a null exception" ) ; return ; } long exceptionCount = FAILURE_ID . incrementAndGet ( ) ; if ( exceptionCount > MAX_EXCEPTION_COUNT ) { LOGGER . warn ( "Exception #" + exceptionCount + " detected. The maximum number of exceptions has been exceeded, so it" + " won't be reported to the Agent." , cause ) ; return ; } LOGGER . warn ( "Exception #" + exceptionCount + " detected" , cause ) ; String targetFileName = exceptionCount + ".exception" ; File dir = getUserDir ( ) ; File tmpFile = new File ( dir , targetFileName + ".tmp" ) ; try { if ( ! tmpFile . createNewFile ( ) ) { throw new IOException ( "Could not create tmp file: " + tmpFile . getAbsolutePath ( ) ) ; } } catch ( IOException e ) { LOGGER . fatal ( "Could not report exception; this means that this exception is not visible to the coordinator" , e ) ; return ; } writeText ( testId + NEW_LINE + throwableToString ( cause ) , tmpFile ) ; File file = new File ( dir , targetFileName ) ; LOGGER . info ( file . getAbsolutePath ( ) ) ; rename ( tmpFile , file ) ;


signature:
public class FileUtils { /** * Copies a directory recursively .
 * @ param src the src directory
 * @ param target the target directory */
public static void copyDirectory ( File src , File target ) { } }

implementation: checkNotNull ( src , "src can't be null" ) ; checkNotNull ( target , "target can't be null" ) ; File [ ] files = src . listFiles ( ) ; if ( files == null ) { return ; } for ( File srcFile : files ) { if ( srcFile . isDirectory ( ) ) { File targetChild = new File ( target , srcFile . getName ( ) ) ; ensureExistingDirectory ( targetChild ) ; copyDirectory ( srcFile , targetChild ) ; } else { copyFileToDirectory ( srcFile , target ) ; } }


signature:
public class SimulatorProperties { /** * Initializes the SimulatorProperties with additional properties .
 * @ param file the file to load the properties from . If { @ code null } , the { @ value # PROPERTIES _ FILE _ NAME } file in the working
 * directory is tried .
 * @ return this
 * @ throws CommandLineExitException if the given file does not exist . If file is { @ code null } no exception will be thrown ,
 * even if the { @ value # PROPERTIES _ FILE _ NAME } file in the working directory cannot be found . */
public SimulatorProperties init ( File file ) { } }

implementation:
if ( file == null ) { // if no file is explicitly given , we look in the working directory
file = new File ( getUserDir ( ) , PROPERTIES_FILE_NAME ) ; if ( ! file . exists ( ) ) { LOGGER . info ( format ( "Found no %s in working directory, relying on default properties" , PROPERTIES_FILE_NAME ) ) ; return null ; } } LOGGER . info ( format ( "Loading additional %s: %s" , PROPERTIES_FILE_NAME , file . getAbsolutePath ( ) ) ) ; check ( file ) ; load ( file , false ) ; return this ;


signature:
public class PropertyBindingSupport { /** * Binds a single property contained in the { @ link TestCase } instance onto the object instance .
 * There will be no warning if the property is not defined in the { @ link TestCase } .
 * There will be no exception if the property will not be found in the object instance , just a warning .
 * @ param instance Instance were the property should be injected
 * @ param testCase TestCase which contains
 * @ param propertyName Name of the property which should be injected
 * @ return true if a matching property was found in the testCase , false otherwise .
 * @ throws RuntimeException if there was an error binding */
public static boolean bind ( Object instance , TestCase testCase , String propertyName ) { } }

implementation: String value = getValue ( testCase , propertyName ) ; if ( value == null ) { return false ; } return bind0 ( instance , propertyName , value ) ;


signature:
public class PropertyBindingSupport { /** * Returns a single property contained in the { @ link TestCase } instance .
 * There will be no warning if the property is not defined in the { @ link TestCase } .
 * @ param testCase TestCase which contains
 * @ param propertyName Name of the property which should be injected
 * @ return Value of the property if found , { @ code null } otherwise */
private static String getValue ( TestCase testCase , String propertyName ) { } }

implementation: if ( testCase == null ) { return null ; } String propertyValue = testCase . getProperty ( propertyName ) ; if ( propertyValue == null || propertyValue . isEmpty ( ) ) { return null ; } return propertyValue ;


signature:
public class ReflectionUtils { /** * Gets the value for a static field .
 * @ param clazz class which contains the field
 * @ param fieldName name of the field
 * @ param fieldType type of the field
 * @ param < E > type of the field
 * @ return the value of the static field */
public static < E > E getStaticFieldValue ( Class clazz , String fieldName , Class fieldType ) { } }

implementation: Field field = getField ( clazz , fieldName , fieldType ) ; if ( field == null ) { throw new ReflectionException ( format ( "Field %s.%s is not found" , clazz . getName ( ) , fieldName ) ) ; } field . setAccessible ( true ) ; return getFieldValue0 ( null , field , clazz . getName ( ) , fieldName ) ;


signature:
public class ReflectionUtils { /** * Searches a method by name .
 * @ param clazz Class to scan
 * @ param methodName Name of the method
 * @ return the found method or < tt > null < / tt > if no method was found */
public static Method getMethodByName ( Class clazz , String methodName ) { } }

implementation: for ( Method method : clazz . getDeclaredMethods ( ) ) { if ( method . getName ( ) . equals ( methodName ) ) { return method ; } } return null ;


signature:
public class WorkerProcessManager { /** * launching is done asynchronous so we don ' t block the calling thread ( messaging thread ) */
public void launch ( CreateWorkerOperation op , Promise promise ) { } }

implementation:
WorkerParameters workerParameters = op . getWorkerParameters ( ) ; // we add the pid to the worker - parameters so the worker can check if the agent is still alive .
workerParameters . set ( "agent.pid" , getPID ( ) ) ; WorkerProcessLauncher launcher = new WorkerProcessLauncher ( WorkerProcessManager . this , workerParameters ) ; LaunchSingleWorkerTask task = new LaunchSingleWorkerTask ( launcher , workerParameters , promise ) ; executorService . schedule ( task , op . getDelayMs ( ) , MILLISECONDS ) ;


signature:
public class NativeUtils { /** * http : / / stackoverflow . com / questions / 35842 / how - can - a - java - program - get - its - own - process - id
 * @ return the PID of this JVM or < tt > - 1 < / tt > if not PID was retrieved */
public static int getPID ( ) { } }

implementation: Integer pid = getPidFromManagementBean ( ) ; if ( pid != null ) { return pid ; } pid = getPidViaReflection ( ) ; if ( pid != null ) { return pid ; } return - 1 ;


signature:
public class CommonUtils { /** * Sleeps a random amount of time .
 * The call is ignored if maxDelayNanos equals or smaller than zero .
 * @ param random the Random used to randomize
 * @ param maxDelayNanos the maximum sleeping period in nanoseconds */
public static void sleepRandomNanos ( Random random , long maxDelayNanos ) { } }

implementation: if ( maxDelayNanos <= 0 ) { return ; } long randomValue = Math . abs ( random . nextLong ( ) + 1 ) ; sleepNanos ( randomValue % maxDelayNanos ) ;


signature:
public class FormatUtils { /** * Formats a percentage of two numbers and adds padding to the left .
 * @ param value the value of the percentage
 * @ param baseValue the base value of the percentage
 * @ return the formatted percentage */
public static String formatPercentage ( long value , long baseValue ) { } }

implementation: double percentage = ( baseValue > 0 ? ( ONE_HUNDRED * value ) / baseValue : 0 ) ; return formatDouble ( percentage , PERCENTAGE_FORMAT_LENGTH ) ;


signature:
public class FormatUtils { /** * Formats a double number and adds padding to the left .
 * Very inefficient implementation , but a lot easier than to deal with the formatting API .
 * @ param number number to format
 * @ param length width of padding
 * @ return formatted number */
public static String formatDouble ( double number , int length ) { } }

implementation: return padLeft ( format ( Locale . US , "%,.2f" , number ) , length ) ;


signature:
public class FormatUtils { /** * Formats a long number and adds padding to the left .
 * Very inefficient implementation , but a lot easier than to deal with the formatting API .
 * @ param number number to format
 * @ param length width of padding
 * @ return formatted number */
public static String formatLong ( long number , int length ) { } }

implementation: return padLeft ( format ( Locale . US , "%,d" , number ) , length ) ;


signature:
public class RealWhorlwind { /** * Prepares the key store and our keys for encrypting / decrypting . Keys will be generated if we
 * haven ' t done so yet , and keys will be re - generated if the old ones have been invalidated . In
 * both cases , our K / V store will be cleared before continuing . */
void prepareKeyStore ( ) { } }

implementation:
try { Key key = keyStore . getKey ( keyAlias , null ) ; Certificate certificate = keyStore . getCertificate ( keyAlias ) ; if ( key != null && certificate != null ) { try { createCipher ( ) . init ( Cipher . DECRYPT_MODE , key ) ; // We have a keys in the store and they ' re still valid .
return ; } catch ( KeyPermanentlyInvalidatedException e ) { Log . d ( TAG , "Key invalidated." ) ; } } storage . clear ( ) ; keyGenerator . initialize ( new KeyGenParameterSpec . Builder ( keyAlias , KeyProperties . PURPOSE_ENCRYPT | KeyProperties . PURPOSE_DECRYPT ) . setBlockModes ( KeyProperties . BLOCK_MODE_ECB ) . setUserAuthenticationRequired ( true ) . setEncryptionPaddings ( KeyProperties . ENCRYPTION_PADDING_RSA_PKCS1 ) . build ( ) ) ; keyGenerator . generateKeyPair ( ) ; } catch ( GeneralSecurityException e ) { throw new RuntimeException ( e ) ; }


signature:
public class JsonProtocol { /** * and JsonPairContext . read */
protected void readJsonSyntaxChar ( byte [ ] b ) throws IOException { } }

implementation: byte ch = reader . read ( ) ; if ( ch != b [ 0 ] ) { throw new ProtocolException ( "Unexpected character:" + ( char ) ch ) ; }


signature:
public class JsonProtocol { /** * corresponding hex value */
private static byte hexVal ( byte ch ) throws IOException { } }

implementation: if ( ( ch >= '0' ) && ( ch <= '9' ) ) { return ( byte ) ( ( char ) ch - '0' ) ; } else if ( ( ch >= 'a' ) && ( ch <= 'f' ) ) { return ( byte ) ( ( char ) ch - 'a' + 10 ) ; } else { throw new ProtocolException ( "Expected hex character" ) ; }


signature:
public class JsonProtocol { /** * Write the bytes in array buf as a Json characters , escaping as needed */
private void writeJsonString ( byte [ ] b ) throws IOException { } }

implementation: context . write ( ) ; transport . write ( QUOTE ) ; int len = b . length ; for ( int i = 0 ; i < len ; i ++ ) { if ( ( b [ i ] & 0x00FF ) >= 0x30 ) { if ( b [ i ] == BACKSLASH [ 0 ] ) { transport . write ( BACKSLASH ) ; transport . write ( BACKSLASH ) ; } else { transport . write ( b , i , 1 ) ; } } else { tmpbuf [ 0 ] = JSON_CHAR_TABLE [ b [ i ] ] ; if ( tmpbuf [ 0 ] == 1 ) { transport . write ( b , i , 1 ) ; } else if ( tmpbuf [ 0 ] > 1 ) { transport . write ( BACKSLASH ) ; transport . write ( tmpbuf , 0 , 1 ) ; } else { transport . write ( ESCSEQ ) ; tmpbuf [ 0 ] = hexChar ( ( byte ) ( b [ i ] >> 4 ) ) ; tmpbuf [ 1 ] = hexChar ( b [ i ] ) ; transport . write ( tmpbuf , 0 , 2 ) ; } } } transport . write ( QUOTE ) ;


signature:
public class JsonProtocol { /** * wrapped in quotes to output as a Json string . */
private void writeJsonInteger ( long num ) throws IOException { } }

implementation: context . write ( ) ; String str = Long . toString ( num ) ; boolean escapeNum = context . escapeNum ( ) ; if ( escapeNum ) { transport . write ( QUOTE ) ; } try { byte [ ] buf = str . getBytes ( "UTF-8" ) ; transport . write ( buf ) ; } catch ( UnsupportedEncodingException e ) { throw new AssertionError ( e ) ; } if ( escapeNum ) { transport . write ( QUOTE ) ; }


signature:
public class JsonProtocol { /** * context dictates escaping , write out as Json string . */
private void writeJsonDouble ( double num ) throws IOException { } }

implementation:
context . write ( ) ; String str = Double . toString ( num ) ; boolean special = false ; switch ( str . charAt ( 0 ) ) { case 'N' : // NaN
case 'I' : // Infinity
special = true ; break ; case '-' : if ( str . charAt ( 1 ) == 'I' ) { // - Infinity
special = true ; } break ; default : break ; } boolean escapeNum = special || context . escapeNum ( ) ; if ( escapeNum ) { transport . write ( QUOTE ) ; } try { byte [ ] b = str . getBytes ( "UTF-8" ) ; transport . write ( b , 0 , b . length ) ; } catch ( UnsupportedEncodingException e ) { throw new AssertionError ( e ) ; } if ( escapeNum ) { transport . write ( QUOTE ) ; }


signature:
public class JsonProtocol { /** * context if skipContext is true . */
private ByteString readJsonString ( boolean skipContext ) throws IOException { } }

implementation: Buffer buffer = new Buffer ( ) ; ArrayList < Character > codeunits = new ArrayList < > ( ) ; if ( ! skipContext ) { context . read ( ) ; } readJsonSyntaxChar ( QUOTE ) ; while ( true ) { byte ch = reader . read ( ) ; if ( ch == QUOTE [ 0 ] ) { break ; } if ( ch == ESCSEQ [ 0 ] ) { ch = reader . read ( ) ; if ( ch == ESCSEQ [ 1 ] ) { transport . read ( tmpbuf , 0 , 4 ) ; short cu = ( short ) ( ( ( short ) hexVal ( tmpbuf [ 0 ] ) << 12 ) + ( ( short ) hexVal ( tmpbuf [ 1 ] ) << 8 ) + ( ( short ) hexVal ( tmpbuf [ 2 ] ) << 4 ) + ( short ) hexVal ( tmpbuf [ 3 ] ) ) ; try { if ( Character . isHighSurrogate ( ( char ) cu ) ) { if ( codeunits . size ( ) > 0 ) { throw new ProtocolException ( "Expected low surrogate char" ) ; } codeunits . add ( ( char ) cu ) ; } else if ( Character . isLowSurrogate ( ( char ) cu ) ) { if ( codeunits . size ( ) == 0 ) { throw new ProtocolException ( "Expected high surrogate char" ) ; } codeunits . add ( ( char ) cu ) ; buffer . write ( new String ( new int [ ] { codeunits . get ( 0 ) , codeunits . get ( 1 ) } , 0 , 2 ) . getBytes ( "UTF-8" ) ) ; codeunits . clear ( ) ; } else { buffer . write ( new String ( new int [ ] { cu } , 0 , 1 ) . getBytes ( "UTF-8" ) ) ; } continue ; } catch ( UnsupportedEncodingException e ) { throw new AssertionError ( e ) ; } catch ( IOException ex ) { throw new ProtocolException ( "Invalid unicode sequence" ) ; } } else { int off = ESCAPE_CHARS . indexOf ( ch ) ; if ( off == - 1 ) { throw new ProtocolException ( "Expected control char" ) ; } ch = ESCAPE_CHAR_VALS [ off ] ; } } buffer . write ( new byte [ ] { ch } ) ; } return buffer . readByteString ( ) ;


signature:
public class JsonProtocol { /** * not do a complete regex check to validate that this is actually a number . */
private String readJsonNumericChars ( ) throws IOException { } }

implementation: StringBuilder strbld = new StringBuilder ( ) ; while ( true ) { byte ch = reader . peek ( ) ; if ( ! isJsonNumeric ( ch ) ) { break ; } strbld . append ( ( char ) reader . read ( ) ) ; } return strbld . toString ( ) ;


signature:
public class JsonProtocol { /** * Read in a Json number . If the context dictates , read in enclosing quotes . */
private long readJsonInteger ( ) throws IOException { } }

implementation: context . read ( ) ; if ( context . escapeNum ( ) ) { readJsonSyntaxChar ( QUOTE ) ; } String str = readJsonNumericChars ( ) ; if ( context . escapeNum ( ) ) { readJsonSyntaxChar ( QUOTE ) ; } try { return Long . valueOf ( str ) ; } catch ( NumberFormatException ex ) { throw new ProtocolException ( "Bad data encountered in numeric data" ) ; }


signature:
public class JsonProtocol { /** * when expected or if wrapped in quotes when not expected . */
private double readJsonDouble ( ) throws IOException { } }

implementation:
context . read ( ) ; if ( reader . peek ( ) == QUOTE [ 0 ] ) { ByteString str = readJsonString ( true ) ; double dub = Double . valueOf ( str . utf8 ( ) ) ; if ( ! context . escapeNum ( ) && ! Double . isNaN ( dub ) && ! Double . isInfinite ( dub ) ) { // Throw exception - - we should not be in a string in this case
throw new ProtocolException ( "Numeric data unexpectedly quoted" ) ; } return dub ; } else { if ( context . escapeNum ( ) ) { // This will throw - we should have had a quote if escapeNum = = true
readJsonSyntaxChar ( QUOTE ) ; } try { return Double . valueOf ( readJsonNumericChars ( ) ) ; } catch ( NumberFormatException ex ) { throw new ProtocolException ( "Bad data encountered in numeric data" ) ; } }


signature:
public class JsonProtocol { /** * Read in a Json string containing base - 64 encoded data and decode it . */
private ByteString readJsonBase64 ( ) throws IOException { } }

implementation: ByteString str = readJsonString ( false ) ; return ByteString . decodeBase64 ( str . utf8 ( ) ) ;


signature:
public class ClientBase { /** * When invoked by a derived instance , sends the given call to the server .
 * @ param methodCall the remote method call to be invoked
 * @ return the result of the method call */
protected final Object execute ( MethodCall < ? > methodCall ) throws Exception { } }

implementation: if ( ! running . get ( ) ) { throw new IllegalStateException ( "Cannot write to a closed service client" ) ; } try { return invokeRequest ( methodCall ) ; } catch ( ServerException e ) { throw e . thriftException ; }