package org.limewire.rest; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpException; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.protocol.HttpContext; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.limewire.core.api.search.GroupedSearchResult; import org.limewire.core.api.search.Search; import org.limewire.core.api.search.SearchDetails; import org.limewire.core.api.search.SearchFactory; import org.limewire.core.api.search.SearchManager; import org.limewire.core.api.search.SearchResultList; import org.limewire.io.GUID; import com.google.inject.Inject; /** * Request handler for Search services. */ class SearchRequestHandler extends AbstractRestRequestHandler { private static final String ALL = ""; private static final String FILES = "/files"; private static final String START = ""; private static final int MAX_LIMIT = 1000; private final SearchManager searchManager; private final SearchFactory searchFactory; @Inject public SearchRequestHandler(SearchManager searchManager, SearchFactory searchFactory) { this.searchManager = searchManager; this.searchFactory = searchFactory; } @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { // Get request method and uri target. String method = request.getRequestLine().getMethod(); String uriTarget = RestUtils.getUriTarget(request, RestPrefix.SEARCH.pattern()); Map<String, String> queryParams = RestUtils.getQueryParams(request); if (RestUtils.GET.equals(method) && ALL.equals(uriTarget)) { // Get metadata for all searches. doGetAll(uriTarget, queryParams, response); } else if (RestUtils.GET.equals(method) && (uriTarget.length() > 0)) { // Get data for single search. doGetSearch(uriTarget, queryParams, response); } else if (RestUtils.POST.equals(method) && START.equals(uriTarget)) { // Start search. doStart(uriTarget, queryParams, response); } else if (RestUtils.DELETE.equals(method) && (uriTarget.length() > 0)) { // Delete search. doDelete(uriTarget, response); } else { response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED); } } /** * Processes request to retrieve metadata for all searches. */ private void doGetAll(String uriTarget, Map<String, String> queryParams, HttpResponse response) throws IOException { // Get active search lists. List<SearchResultList> searchLists = searchManager.getActiveSearchLists(); try { // Create JSON result. JSONArray jsonArr = new JSONArray(); for (SearchResultList searchList : searchLists) { jsonArr.put(RestUtils.createSearchJson(searchList)); } // Set response entity and status. HttpEntity entity = RestUtils.createStringEntity(jsonArr.toString()); response.setEntity(entity); response.setStatusCode(HttpStatus.SC_OK); } catch (JSONException ex) { throw new IOException(ex); } } /** * Processes request to retrieve data for a single search. */ private void doGetSearch(String uriTarget, Map<String, String> queryParams, HttpResponse response) throws IOException { // Use GUID to get search result list. SearchResultList searchList; try { String guidStr = parseGuid(uriTarget); searchList = searchManager.getSearchResultList(new GUID(guidStr)); } catch (Exception ex) { searchList = null; } // Return empty object if null. if (searchList == null) { response.setEntity(RestUtils.createStringEntity("{}")); response.setStatusCode(HttpStatus.SC_OK); return; } try { if (uriTarget.indexOf(FILES) < 0) { // Return search metadata. JSONObject jsonObj = RestUtils.createSearchJson(searchList); HttpEntity entity = RestUtils.createStringEntity(jsonObj.toString()); response.setEntity(entity); response.setStatusCode(HttpStatus.SC_OK); } else { // Get query parameters. String offsetStr = queryParams.get("offset"); String limitStr = queryParams.get("limit"); int offset = (offsetStr != null) ? Integer.parseInt(offsetStr) : 0; int limit = (limitStr != null) ? Math.min(Integer.parseInt(limitStr), MAX_LIMIT) : MAX_LIMIT; // Create search result array. List<GroupedSearchResult> resultList = new ArrayList<GroupedSearchResult>(searchList.getGroupedResults()); JSONArray jsonArr = new JSONArray(); for (int i = offset, max = Math.min(offset + limit, resultList.size()); i < max; i++) { GroupedSearchResult result = resultList.get(i); jsonArr.put(RestUtils.createSearchResultJson(result)); } // Set response entity and status. HttpEntity entity = RestUtils.createStringEntity(jsonArr.toString()); response.setEntity(entity); response.setStatusCode(HttpStatus.SC_OK); } } catch (JSONException ex) { throw new IOException(ex); } } /** * Starts a new search using the specified uri target and query parameters. */ private void doStart(String uriTarget, Map<String, String> queryParams, HttpResponse response) throws IOException { // Get parameters to start search. String searchQuery = queryParams.get("q"); // Create search. SearchDetails searchDetails = RestSearchDetails.createKeywordSearch(searchQuery); Search search = searchFactory.createSearch(searchDetails); // Add search to search manager. The search is monitored so it will // be cancelled if we stop polling for its results. SearchResultList searchList = searchManager.addMonitoredSearch(search, searchDetails); // Start search. search.start(); try { // Return search metadata. JSONObject jsonObj = RestUtils.createSearchJson(searchList); HttpEntity entity = RestUtils.createStringEntity(jsonObj.toString()); response.setEntity(entity); response.setStatusCode(HttpStatus.SC_OK); } catch (JSONException ex) { throw new IOException(ex); } } /** * Deletes a search using the specified uri target. */ private void doDelete(String uriTarget, HttpResponse response) throws IOException { // Use GUID to get search result list. SearchResultList searchList; try { String guidStr = parseGuid(uriTarget); searchList = searchManager.getSearchResultList(new GUID(guidStr)); } catch (Exception ex) { searchList = null; } if (searchList != null) { Search search = searchList.getSearch(); // Stop search. search.stop(); // Remove search from core management. searchManager.removeSearch(search); // Set OK status. response.setStatusCode(HttpStatus.SC_OK); } else { response.setStatusCode(HttpStatus.SC_NOT_FOUND); } } /** * Returns the GUID string from the specified URI target. The GUID string * should be between the first and second slash characters. */ private String parseGuid(String uriTarget) { int pos1 = uriTarget.indexOf("/"); String guid = (pos1 < 0) ? uriTarget : uriTarget.substring(pos1 + 1); int pos2 = guid.indexOf("/"); return (pos2 < 0) ? guid : guid.substring(0, pos2); } }