package org.nextprot.api.web.controller;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jsondoc.core.annotation.ApiMethod;
import org.jsondoc.core.annotation.ApiQueryParam;
import org.jsondoc.core.pojo.ApiVerb;
import org.nextprot.api.commons.exception.NextProtException;
import org.nextprot.api.commons.exception.SearchQueryException;
import org.nextprot.api.rdf.service.SparqlEndpoint;
import org.nextprot.api.rdf.service.SparqlService;
import org.nextprot.api.solr.AutocompleteSearchResult;
import org.nextprot.api.solr.Query;
import org.nextprot.api.solr.QueryRequest;
import org.nextprot.api.solr.SearchResult;
import org.nextprot.api.solr.SolrConfiguration;
import org.nextprot.api.solr.SolrService;
import org.nextprot.api.user.domain.UserProteinList;
import org.nextprot.api.user.domain.UserQuery;
import org.nextprot.api.user.service.UserProteinListService;
import org.nextprot.api.user.service.UserQueryService;
import org.nextprot.api.user.service.impl.SparqlQueryDictionary;
import org.nextprot.api.web.service.QueryBuilderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.google.common.base.Joiner;
@Lazy
@Controller
//@Api(name="Search", description="Method to search")
public class SearchController {
// private final Log Logger = LogFactory.getLog(SearchController.class);
@Autowired private SolrService queryService;
@Autowired private SparqlService sparqlService;
@Autowired private SparqlEndpoint sparqlEndpoint;
@Autowired private UserQueryService userQueryService;
@Autowired private UserProteinListService proteinListService;
@Autowired private SolrConfiguration configuration;
@Autowired private QueryBuilderService queryBuilderService;
@Autowired
private SparqlQueryDictionary sparqlQueryDictionary;
/**
* Useful to build the cache for sparql queries on a target api server (typically build-api.nextprot.org)
* @param queryId a query public id
* @return either the number of entries returned by the queries (if query is a snorql only, the number returned will be 0) or an error message
*/
@RequestMapping(value = "/sparql/run", method = { RequestMethod.GET })
@ResponseBody
public Map<String,Object> runQuery(@RequestParam(value = "queryId", required = true) String queryId) {
Map<String,Object> result = new HashMap<String, Object>();
result.put("queryId", queryId);
try {
UserQuery uq = userQueryService.getUserQueryByPublicId(queryId);
List<String> entries = sparqlService.findEntries(uq.getSparql(), sparqlEndpoint.getUrl(), uq.getTitle());
result.put("entryCount", entries.size());
} catch (Exception e) {
result.put("error", e.getMessage());
}
return result;
}
@RequestMapping(value = "/search/{index}", method = { RequestMethod.POST })
@ResponseBody
public SearchResult search(@PathVariable("index") String indexName, @RequestBody QueryRequest queryRequest) {
if (this.queryService.checkAvailableIndex(indexName)) {
Query query = queryBuilderService.buildQueryForSearch(queryRequest, indexName);
try {
return queryService.executeQuery(query);
} catch (SearchQueryException e) {
throw new NextProtException(e);
}
} else {
throw new NextProtException("error: index " + indexName + " is not available");
}
}
@ApiMethod(path = "/autocomplete/{index}", verb = ApiVerb.GET, description = "")
@RequestMapping(value="/autocomplete/{index}", method={RequestMethod.GET, RequestMethod.POST})
public AutocompleteSearchResult autocomplete(
@ApiQueryParam(name="index", allowedvalues={"entry", "term", "publication"}, required=true) @PathVariable("index") String indexName,
@ApiQueryParam(name="query", description="Search query", required=true) @RequestParam(value="query", required=true) String queryString,
@ApiQueryParam(name="quality", description="Quality GOLD/BRONZE") @RequestParam(value="quality", required=false) String quality,
@ApiQueryParam(name="sort") @RequestParam(value="sort", required=false) String sort,
@ApiQueryParam(name="order") @RequestParam(value="order", required=false) String order,
@ApiQueryParam(name="start") @RequestParam(value="start", required=false) String start,
@RequestParam(value="filter", required=false) String filter) {
if (this.queryService.checkAvailableIndex(indexName)) {
Query q = this.queryBuilderService.buildQueryForAutocomplete(indexName, queryString, quality, sort, order, start, "0", filter);
try {
return convert(queryService.executeQuery(q));
} catch (SearchQueryException e) {
throw new NextProtException(e);
}
} else {
throw new NextProtException("error: index " + indexName + " is not available");
}
}
private static AutocompleteSearchResult convert(SearchResult searchResult) {
AutocompleteSearchResult autocompleteResult = new AutocompleteSearchResult();
autocompleteResult.setElapsedTime(searchResult.getElapsedTime());
autocompleteResult.setEntity(searchResult.getEntity());
autocompleteResult.setIndex(searchResult.getIndex());
Map<String, List<Map<String, Object>>> facets = searchResult.getFacets();
for (List<Map<String, Object>> value : facets.values()) {
for (Map<String, Object> map : value) {
autocompleteResult.addResult((String) map.get("name"), ((Long) map.get("count")).intValue());
}
}
return autocompleteResult;
}
/**
* @param indexName
* @param queryRequest
* @param model
* @return
*/
@RequestMapping(value="/search-ids/{index}", method={ RequestMethod.POST })
public String searchIds(@PathVariable("index") String indexName, @RequestBody QueryRequest queryRequest, Model model) {
if(this.queryService.checkAvailableIndex(indexName)) {
SearchResult result;
try {
Query query = null;
if((queryRequest.getMode() != null) && queryRequest.getMode().equalsIgnoreCase("advanced")){
Set<String> accessions = new HashSet<String>(sparqlService.findEntries(queryRequest.getSparql(), sparqlEndpoint.getUrl(), queryRequest.getSparqlTitle()));
String queryString = "id:" + (accessions.size() > 1 ? "(" + Joiner.on(" ").join(accessions) + ")" : accessions.iterator().next());
queryRequest.setQuery(queryString);
query = this.queryBuilderService.buildQueryForSearchIndexes(indexName, "pl_search", queryRequest);
} else {
query = this.queryBuilderService.buildQueryForSearchIndexes(indexName, "simple", queryRequest);
}
result = this.queryService.executeIdQuery(query);
model.addAttribute("SearchResult", SearchResult.class);
model.addAttribute("result", result);
} catch (SearchQueryException e) {
e.printStackTrace();
model.addAttribute("errormessage", e.getMessage());
return "exception";
}
}
return "search-ids";
}
@RequestMapping(value="/user/{username}/protein-list/{list}/results", method = RequestMethod.GET)
public String test(@PathVariable("username") String username,
@PathVariable("list") String listName,
@RequestParam(value="sort", required=false) String sort,
@RequestParam(value="order", required=false) String order,
@RequestParam(value="start", required=false) String start,
@RequestParam(value="rows", required=false) String rows,
@RequestParam(value="filter", required=false) String filter,
Model model) throws SearchQueryException {
UserProteinList proteinList = this.proteinListService.getUserProteinListByNameForUser(username, listName);
Set<String> accessions = proteinList.getAccessionNumbers();
String queryString = "id:" + ( accessions.size() > 1 ? "(" + Joiner.on(" ").join(accessions) + ")" : accessions.iterator().next() );
// SolrIndex index = this.configuration.getIndexByName("entry");
Query query = this.queryBuilderService.buildQueryForProteinLists("entry", queryString, "", sort, order, start, rows, filter);
SearchResult result = this.queryService.executeQuery(query);
model.addAttribute("result", result);
return "search";
}
}