package gov.nysenate.openleg.service.log.search; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; import gov.nysenate.openleg.client.view.log.ApiLogItemView; import gov.nysenate.openleg.dao.base.LimitOffset; import gov.nysenate.openleg.dao.base.SearchIndex; import gov.nysenate.openleg.dao.base.SortOrder; import gov.nysenate.openleg.dao.log.data.ApiLogDao; import gov.nysenate.openleg.dao.log.search.ElasticApiLogSearchDao; import gov.nysenate.openleg.model.auth.ApiResponse; import gov.nysenate.openleg.model.search.ClearIndexEvent; import gov.nysenate.openleg.model.search.RebuildIndexEvent; import gov.nysenate.openleg.model.search.SearchException; import gov.nysenate.openleg.model.search.SearchResults; import gov.nysenate.openleg.service.base.search.ElasticSearchServiceUtils; import gov.nysenate.openleg.service.log.event.ApiLogIndexEvent; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import java.util.Collection; import java.util.List; @Service public class ElasticApiLogSearchService implements ApiLogSearchService { private static final Logger logger = LoggerFactory.getLogger(ElasticApiLogSearchService.class); @Autowired private EventBus eventBus; @Autowired private ApiLogDao apiLogDao; @Autowired private ElasticApiLogSearchDao apiLogSearchDao; @PostConstruct public void init() { this.eventBus.register(this); } @Override public SearchResults<ApiLogItemView> searchApiLogs(String query, String sort, LimitOffset limOff) throws SearchException { try { return apiLogSearchDao.searchLogsAndFetchData(QueryBuilders.queryStringQuery(query), null, ElasticSearchServiceUtils.extractSortBuilders(sort), limOff); } catch (SearchParseException ex) { throw new SearchException("Invalid query string"); } catch (ElasticsearchException ex) { throw new SearchException("Unexpected search exception!"); } } @Override public void updateIndex(ApiResponse apiResponse) { apiLogSearchDao.updateLogIndex(apiResponse); } @Override public void updateIndex(Collection<ApiResponse> apiResponses) { apiLogSearchDao.updateLogIndex(apiResponses); } @Subscribe public void handleUpdateIndexEvent(ApiLogIndexEvent apiLogIndexEvent) { if (apiLogIndexEvent != null) { apiLogSearchDao.updateLogIndex(apiLogIndexEvent.getApiResponse()); } } @Override public void clearIndex() { apiLogSearchDao.purgeIndices(); apiLogSearchDao.createIndices(); } @Override public void rebuildIndex() { clearIndex(); LimitOffset limOff = LimitOffset.THOUSAND; List<ApiResponse> responses; while (!(responses = apiLogDao.getResponses(limOff, SortOrder.ASC)).isEmpty()) { logger.info("Indexing logs, batch {} - {}", limOff.getOffsetStart(), limOff.getOffsetEnd()); apiLogSearchDao.updateLogIndex(responses); limOff = limOff.next(); } } @Override @Subscribe public void handleRebuildEvent(RebuildIndexEvent event) { if (event.affects(SearchIndex.API_LOG)) { rebuildIndex(); } } @Override @Subscribe public void handleClearEvent(ClearIndexEvent event) { if (event.affects(SearchIndex.API_LOG)) { clearIndex(); } } }