package com.silverforge.elasticsearchrawclient.elasticFacade; import android.text.TextUtils; import com.silverforge.elasticsearchrawclient.model.BulkActionResult; import com.silverforge.elasticsearchrawclient.model.BulkTuple; import com.silverforge.elasticsearchrawclient.model.ElasticSettings; import com.silverforge.elasticsearchrawclient.elasticFacade.operations.BulkOperations; import com.silverforge.elasticsearchrawclient.elasticFacade.operations.DocumentOperations; import com.silverforge.elasticsearchrawclient.elasticFacade.operations.IndexOperations; import com.silverforge.elasticsearchrawclient.elasticFacade.operations.QueryOperations; import com.silverforge.elasticsearchrawclient.exceptions.IndexCannotBeNullException; import com.silverforge.elasticsearchrawclient.exceptions.TypeCannotBeNullException; import com.silverforge.elasticsearchrawclient.definition.Queryable; import com.silverforge.webconnector.EndpointConnector; import com.silverforge.webconnector.definitions.Connectable; import com.silverforge.webconnector.exceptions.SettingsIsNullException; import com.silverforge.webconnector.model.ConnectorSettings; import com.silverforge.webconnector.model.InvokeStringResult; import java.net.URISyntaxException; import java.util.List; import rx.Observable; public class ElasticClient implements ElasticRawClient { private Connectable connector; private Raw raw = new Raw(); private ElasticSettings elasticSettings; private IndexOperations indexOperations; private DocumentOperations documentOperations; private BulkOperations bulkOperations; private QueryOperations queryOperations; // region Constructors /** * Constructor of ElasticClient * @param connector the Connector instance */ public ElasticClient(Connectable connector, ElasticSettings elasticSettings) { this.connector = connector; this.elasticSettings = elasticSettings; indexOperations = new IndexOperations(connector, elasticSettings); documentOperations = new DocumentOperations(connector, elasticSettings); bulkOperations = new BulkOperations(connector, elasticSettings); queryOperations = new QueryOperations(connector, elasticSettings); } /** * Constructor of ElasticClient *<pre> *<code> *ConnectorSettings settings = ConnectorSettings * .builder() * .baseUrl(ELASTIC_URL) * .types(ELASTIC_TYPES) * .userName(ELASTIC_APIKEY) * .build(); * *ElasticSettings elasticSettings = ElasticSettings * .builder() * .indices(ELASTIC_INDICES) * .build(); * * try { * client = new ElasticClient(settings); * } catch (URISyntaxException e) { * e.printStackTrace(); * Log.e(TAG, e.getMessage()); * fail(e.getMessage()); * } *</code> *</pre> * @param settings the settings of the ElasticClient * @throws URISyntaxException */ public ElasticClient(ConnectorSettings settings, ElasticSettings elasticSettings) throws SettingsIsNullException, URISyntaxException { this(new EndpointConnector(settings), elasticSettings); } /** * Constructor of ElasticClient *<pre> *<code> *ConnectorSettings settings = ConnectorSettings * .builder() * .baseUrl(ELASTIC_URL) * .types(ELASTIC_TYPES) * .userName(ELASTIC_APIKEY) * .build(); * * try { * client = new ElasticClient(settings); * } catch (URISyntaxException e) { * e.printStackTrace(); * Log.e(TAG, e.getMessage()); * fail(e.getMessage()); * } *</code> *</pre> * @param settings the settings of the ElasticClient * @throws URISyntaxException */ public ElasticClient(ConnectorSettings settings) throws SettingsIsNullException, URISyntaxException { this(new EndpointConnector(settings), ElasticSettings.builder().build()); } // endregion /** * Proxy method for connector in order to have "raw" access to ElasticSearch */ public Raw executeRawRequest() { return raw; } // region Index operations /** * Creates index based on indexName and the data * @param indexName the name of the index * @param data the json string defines structure of the index for example *<pre> *{@code * { * "mappings" : { * "testcity" : { * "properties" : { * "name" : { "type": "string"} * } * } * } * } *} *</pre> * @return true : if success */ @Override public boolean createIndex(String indexName, String data) { return indexOperations.createIndex(indexName, data); } /** * Adds alias to an index * @param indexName the index name, it could be a group as well e.g.: "testind*" * @param aliasName the alias */ @Override public void addAlias(String indexName, String aliasName) { indexOperations.addAlias(indexName, aliasName); } /** * Removes all the indices defined in the ConnectorSettings */ @Override public void removeIndices() { removeIndices(elasticSettings.getIndices()); } /** * Removes all indices given by parameter * @param indexNames the indices */ @Override public void removeIndices(String[] indexNames) { indexOperations.removeIndices(indexNames); } /** * Checks if the index already exists * @param indexName The name of the index * @return true if exists */ @Override public boolean indexExists(String indexName) { return indexOperations.indexExists(indexName); } /** * Retrieves the aliases of the given index * @param index the index * @return List of aliases */ @Override public List<String> getAliases(String index) { return indexOperations.getAliases(index); } /** * Removes alias from index * @param indexName the index name * @param aliasName the alias name */ @Override public void removeAlias(String indexName, String aliasName) { indexOperations.removeAlias(indexName, aliasName); } // endregion // region Add document operations /** * Adds a document to the index defined in ConnectorSettings * @param entity the entity should be added to index (will be json serialized) * @param <T> the type of the entity * @return the id of the newly created document * @throws IndexCannotBeNullException * @throws IllegalArgumentException * @throws TypeCannotBeNullException */ @Override public <T> String addDocument(T entity) throws IndexCannotBeNullException, IllegalArgumentException, TypeCannotBeNullException { return addDocument(null, entity); } /** * Adds a document to the index defined in ConnectorSettings * @param id the id of the document * @param entity the entity should be added to index (will be json serialized) * @param <T> the type of the entity * @return the id of the newly created document * @throws IndexCannotBeNullException * @throws IllegalArgumentException * @throws TypeCannotBeNullException */ @Override public <T> String addDocument(String id, T entity) throws IndexCannotBeNullException, IllegalArgumentException, TypeCannotBeNullException { return documentOperations.addDocument(id, entity); } /** * Adds a document to the index, in case of IOException empty id will be retrieved * @param index the index (Elastic) * @param type the type of the document (Elastic) * @param id the id of the document * @param entity the entity * @param <T> the type of the entity * @return the id of the newly created document, it's equal to the param id * @throws IllegalArgumentException */ @Override public <T> String addDocument(String index, String type, String id, T entity) throws IllegalArgumentException { return documentOperations.addDocument(index, type, id, entity); } // endregion // region Remove document methods /** * Removes document from index defined in ConnectorSettings based on the given id * @param id the id * @throws IllegalArgumentException * @throws IndexCannotBeNullException * @throws TypeCannotBeNullException */ @Override public void removeDocument(String id) throws IllegalArgumentException, IndexCannotBeNullException, TypeCannotBeNullException { documentOperations.removeDocument(id); } /** * Removes document from index given by parameters * @param index the index (Elastic) * @param type the type (Elastic) * @param id the id (Elastic) * @throws IllegalArgumentException */ @Override public void removeDocument(String index, String type, String id) throws IllegalArgumentException { documentOperations.removeDocument(index, type, id); } /** * Removes documents by query from index defined in ConnectorSettings * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "term": { * "name": { * "value": "myCityName" * } * } * } *} *} *</pre> */ @Override public void removeDocumentsQuery(String query) { documentOperations.removeDocumentsQuery(query); } /** * Removes documents based on the given query on the given indices * @param indices the indices * @param types the types of the indices * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "term": { * "name": { * "value": "myCityName" * } * } * } *} *} *</pre> */ @Override public void removeDocumentsQuery(String[] indices, String[] types, String query) { documentOperations.removeDocumentsQuery(indices, types, query); } // endregion // region Update document methods /** * Updates document based on the given parameters in index defined in ConnectorSettings * @param id the id * @param entity the entity (will be json serialized) * @param <T> the type of the entity * @throws IndexCannotBeNullException * @throws TypeCannotBeNullException */ @Override public <T> void updateDocument(String id, T entity) throws IndexCannotBeNullException, TypeCannotBeNullException { documentOperations.updateDocument(id, entity); } /** * Updates document based on the given parameters * @param index the index (Elastic) * @param type the type (Elastic) * @param id the id of the document (Elastic) * @param entity the entity (will be json serialized) * @param <T> the tpe of the entity * @throws IllegalArgumentException */ @Override public <T> void updateDocument(String index, String type, String id, T entity) throws IllegalArgumentException { documentOperations.updateDocument(index, type, id, entity); } // endregion // region Bulk document method /** * Bulk processor for create/update/index/delete documents * @param bulkItems the action items for bulk processor * @return the result of every single action compared with the initial bulkitem */ public List<BulkActionResult> bulk(List<BulkTuple> bulkItems) { return bulkOperations.bulk(bulkItems); } // endregion // region Get document methods /** * Retrieves with document(s) based on the given parameters * @param ids the id(s) of the document(s) (Elastic) * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @throws IndexCannotBeNullException * @return List of entity/entities retrieved by the given id(s) */ @Override public <T> List<T> getDocument(String[] ids, Class<T> classType) throws IndexCannotBeNullException { String[] indices = elasticSettings.getIndices(); if (indices == null || indices.length == 0) throw new IndexCannotBeNullException(); return queryOperations.getDocument(indices, null, ids, classType); } /** * Retrieves with document(s) based on the given parameters * @param type the type of the document (Elastic) * @param ids the id(s) of the document(s) (Elastic) * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @throws IndexCannotBeNullException * @return List of entity/entities retrieved by the given id(s) and type */ @Override public <T> List<T> getDocument(String type, String[] ids, Class<T> classType) throws IndexCannotBeNullException { String[] indices = elasticSettings.getIndices(); if (indices == null || indices.length == 0) throw new IndexCannotBeNullException(); return queryOperations.getDocument(indices, type, ids, classType); } /** * Retrieves with document(s) based on the given parameters * @param index the index name (Elastic) * @param type the type of the document (Elastic) * @param ids the id(s) of the document(s) (Elastic) * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @return List of entity/entities retrieved by the given id(s) and type */ @Override public <T> List<T> getDocument(String index, String type, String[] ids, Class<T> classType) { String[] indexParam = null; if (!TextUtils.isEmpty(index)) indexParam = new String[] {index}; return queryOperations.getDocument(indexParam, type, ids, classType); } /** * Retrieves with document(s) based on the given parameters * @param indices the indices for search (Elastic) * @param type the type of the document (Elastic) * @param ids the id(s) of the document(s) (Elastic) * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @return List of entity/entities retrieved by the given id(s) */ @Override public <T> List<T> getDocument(String[] indices, String type, String[] ids, Class<T> classType) { return queryOperations.getDocument(indices, type, ids, classType); } public <T> Observable<T> getDocumentAsync(String[] ids, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> documents = getDocument(ids, classType); Observable .from(documents) .subscribe(subscriber::onNext); } catch (IndexCannotBeNullException e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } public <T> Observable<T> getDocumentAsync(String type, String[] ids, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> documents = getDocument(type, ids, classType); Observable .from(documents) .subscribe(subscriber::onNext); } catch (IndexCannotBeNullException e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } public <T> Observable<T> getDocumentAsync(String index, String type, String[] ids, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> documents = getDocument(index, type, ids, classType); Observable .from(documents) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } public <T> Observable<T> getDocumentAsync(String[] indices, String type, String[] ids, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> documents = getDocument(indices, type, ids, classType); Observable .from(documents) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } // endregion // region Search methods /** * Searches in index based on the query and retrieves with the list of entities from index defined in ConnectorSettings * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "match_all": {} * } *} *} *</pre> * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @return List of entity/entities retrieved by query * @return List of entity/entities retrieved by query * * @deprecated in v2.0 * @see #search(Queryable, Class <T>) */ @Override public <T> List<T> search(String query, Class<T> classType) { return queryOperations.search(query, classType); } /** * Searches in index based on the query and retrieves with the list of entities * @param index the index * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "match_all": {} * } *} *} *</pre> * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @throws IllegalArgumentException * @return List of entity/entities retrieved by query * * @deprecated in v2.0 * @see #search(String, Queryable, Class <T>) */ @Override public <T> List<T> search(String index, String query, Class<T> classType) throws IllegalArgumentException{ return queryOperations.search(index, query, classType); } /** * Searches in index based on the query and retrieves with the data sequenc of entities from index defined in ConnectorSettings * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "match_all": {} * } *} *} *</pre> * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @return List of entity/entities retrieved by query * @return List of entity/entities retrieved by query * * @deprecated in v2.0 * @see #searchAsync(Queryable, Class <T>) */ public <T> Observable<T> searchAsync(String query, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> searchResult = search(query, classType); Observable .from(searchResult) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } /** * Searches in index based on the query and retrieves with the data sequence of entities * @param index the index * @param query the query, e.g.: *<pre> *{@code *{ * "query": { * "match_all": {} * } *} *} *</pre> * @param classType the type of the entity will be retrieved for mapping, e.g.: <strong>City.class</strong> * @param <T> the type of the entity * @throws IllegalArgumentException check onError * @return List of entity/entities retrieved by query * * @deprecated in v2.0 * @see #searchAsync(String, Queryable, Class <T>) */ public <T> Observable<T> searchAsync(String index, String query, Class<T> classType) { return Observable.create(subscriber -> { if (TextUtils.isEmpty(index)) { IllegalArgumentException illegalArgumentException = new IllegalArgumentException("index cannot be null or empty"); subscriber.onError(illegalArgumentException); subscriber.onCompleted(); } else { try { List<T> searchResult = search(index, query, classType); Observable .from(searchResult) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } } }); } public <T> List<T> search(Queryable query, Class<T> classType) { return queryOperations.search(query, classType); } public <T> List<T> search(String index, Queryable query, Class<T> classType) { return queryOperations.search(index, query, classType); } public <T> Observable<T> searchAsync(Queryable query, Class<T> classType) { return Observable.create(subscriber -> { try { List<T> searchResult = queryOperations.search(query, classType); Observable .from(searchResult) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } }); } public <T> Observable<T> searchAsync(String index, Queryable query, Class<T> classType) { return Observable.create(subscriber -> { if (TextUtils.isEmpty(index)) { IllegalArgumentException illegalArgumentException = new IllegalArgumentException("index cannot be null or empty"); subscriber.onError(illegalArgumentException); subscriber.onCompleted(); } else { try { List<T> searchResult = queryOperations.search(index, query, classType); Observable .from(searchResult) .subscribe(subscriber::onNext); } catch (Exception e) { subscriber.onError(e); } finally { subscriber.onCompleted(); } } }); } // endregion /** * Proxy class for connector in order to have "raw" access to ElasticSearch */ public final class Raw { private Raw() {} /** * HTTP method HEAD on given path. The url is defined in ConnectorSettings * @param path the path, e.g.: /apple/pear/1 * @return the result of the invoke */ public InvokeStringResult head(String path) { return connector.head(path); } /** * HTTP method GET on given path. The url is defined in ConnectorSettings * @param path the path, e.g.: /apple/pear/1 * @return the result of the invoke */ public InvokeStringResult get(String path) { return connector.get(path); } /** * HTTP method POST on given path. The url is defined in ConnectorSettings * @param path the path, e.g.: /apple/pear/1 * @param data the request data * @return the result of the invoke */ public InvokeStringResult post(String path, String data) { return connector.post(path, data); } /** * HTTP method PUT on given path. The url is defined in ConnectorSettings * @param path the path, e.g.: /apple/pear/1 * @param data the request data * @return the result of the invoke */ public InvokeStringResult put(String path, String data) { return connector.put(path, data); } /** * HTTP method DELETE on given path. The url is defined in ConnectorSettings * @param path the path, e.g.: /apple/pear/1 * @param data the request data * @return the result of the invoke */ public InvokeStringResult delete(String path, String data) { return connector.delete(path, data); } } }