package org.knoesis.apihut.servlet;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.knoesis.apihut.Constants;
import org.knoesis.apihut.util.RemoteCallManager;
/**
* Servlet implementation class SearchManager
*/
public class SearchManager extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SearchManager() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect("use_post.jsp");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
int type = request.getParameter("t") == null ? Constants.Search.TYPE_REGULAR_SEARCH
: Integer.parseInt(request.getParameter("t"));
switch (type) {
case Constants.Search.TYPE_REGULAR_SEARCH:
handleRegularSearch(request, response);
break;
case Constants.Search.TYPE_FACETED_SEARCH:
handleFacetedSearch(request, response);
break;
default:
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Unsupported type argument " + type);
break;
}
}
/*
* Regular search operation
*
*/
private void handleRegularSearch(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String originalQueryString = request.getParameter("q");
String field = request.getParameter("f");
String queryString = sanitizeQueryString(originalQueryString, field);
SolrQuery searchQuery = new SolrQuery();
prepareQuery(queryString, searchQuery);
QueryResponse queryResponse = RemoteCallManager.sendSearch(searchQuery);
try {
JSONObject returnObject = formJSONResponse(request, queryResponse);
response.setContentType("application/json");
response.getWriter().print(returnObject.toString());
} catch (JSONException e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
/*
* Faceted search operation
*
*/
private void handleFacetedSearch(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String originalQueryString = request.getParameter("q");
String field = request.getParameter("f");
String facet = request.getParameter("facet");
String facetValue = request.getParameter("facetvalue");
String queryString = sanitizeQueryString(originalQueryString, field);
SolrQuery searchQuery = new SolrQuery();
prepareQuery(queryString, searchQuery);
searchQuery.addFilterQuery(facet +":\"" + facetValue +"\"");
//see http://www.lucidimagination.com/Community/Hear-from-the-Experts/Articles/Faceted-Search-Solr
QueryResponse queryResponse = RemoteCallManager.sendSearch(searchQuery);
try {
JSONObject returnObject = formJSONResponse(request, queryResponse);
response.setContentType("application/json");
response.getWriter().print(returnObject.toString());
} catch (JSONException e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
/*
* Add the basic parameters to the solr query
*/
private void prepareQuery(String queryString, SolrQuery searchQuery) {
searchQuery.setQuery(queryString).
setFacet(true).
setFacetMinCount(Constants.Search.MINIMUM_FACET_COUNT).
setFacetLimit(Constants.Search.MAXIMUM_FACET_COUNT).
setRows(Constants.Search.RESULTS_PER_PAGE);
for (int i = 0; i < Constants.Search.COMMON_FACET_FIELDS.length; i++) {
searchQuery.addFacetField(Constants.Search.COMMON_FACET_FIELDS[i]);
}
//return all the search fields
searchQuery.addField("*");
}
/*
* Formulates an acceptable query string
*/
private String sanitizeQueryString(String originalQueryString, String field) {
String queryString = originalQueryString.replaceAll(":|\"|\'", " "); //ignore any attempt to insert fields in the query
if(queryString.contains(" ")){
queryString = field + ":'" + queryString + "'";
}else{
queryString = field + ":" + queryString;
}
return queryString;
}
/*
* Form a JSON response
*/
private JSONObject formJSONResponse(HttpServletRequest request,
QueryResponse queryResponse) throws JSONException {
JSONArray facets = new JSONArray();
if (queryResponse.getFacetFields() != null){
for (FacetField f : queryResponse.getFacetFields()) {
Map<String, Object> m = new HashMap<String, Object>();
m.put("facetName", f.getName());
m.put("facetCount", f.getValueCount());
m.put("facetValues",extractFacetValues(f));
facets.put(new JSONObject(m));
}
}
JSONArray returnArray = new JSONArray();
for (SolrDocument resultDoc : queryResponse.getResults()) {
Map<String, Object> resultMap = new HashMap<String, Object>();
for (String fieldName : resultDoc.getFieldNames()) {
//exclude detail heavy fields in the JSON return
if (!Constants.Search.COMMON_EXCLUSION_FIELDS.contains(fieldName)){
resultMap.put(fieldName, resultDoc.getFieldValue(fieldName));
}
}
returnArray.put(new JSONObject(resultMap));
}
JSONObject queryParameters = new JSONObject();
for(String param : Constants.Search.RETURN_Q_PARAMS){
queryParameters.put(param, request.getParameter(param));
}
JSONObject returnObject = new JSONObject();
returnObject.put("facets", facets).
put("docs", returnArray)
.put("qparams", queryParameters);
return returnObject;
}
private JSONArray extractFacetValues(FacetField f) throws JSONException{
JSONArray values = new JSONArray();
if (f.getValueCount()>0){
for(FacetField.Count fc : f.getValues()){
values.put(new JSONObject().put("name", fc.getName()).put("count", fc.getCount()));
}
}
return values;
}
}