/*******************************************************************************
* Australian National University Data Commons
* Copyright (C) 2013 The Australian National University
*
* This file is part of Australian National University Data Commons.
*
* Australian National University Data Commons is free software: you
* can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package au.edu.anu.datacommons.search;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import au.edu.anu.datacommons.data.solr.dao.SolrSearchDAO;
import au.edu.anu.datacommons.data.solr.model.SolrSearchResult;
import au.edu.anu.datacommons.security.service.GroupService;
import au.edu.anu.datacommons.util.Util;
import com.sun.jersey.api.client.ClientResponse.Status;
import com.sun.jersey.api.view.Viewable;
/**
* SearchService
*
* Australian National University Data Commons
*
* Class provides a REST service using Jersey for searching the Fedora repository
*
* <pre>
* Version Date Developer Description
* 0.1 26/03/2012 Rahul Khanna (RK) Initial.
* 0.2 04/05/2012 Genevieve Turner (GT) Updated for the removal of the method 'runRiSearch'
* 0.4 13/06/2012 Genevieve Turner (GT) Updated for changes to use solr as the search engine
* 0.5 13/06/2012 Genevieve Turner (GT) Updated for varying search filters
* 0.6 18/06/2012 Genevieve Turner (GT) Fixed an issue where there is an error in the query if the user has no associated groups
* 0.7 23/07/2012 Genevieve Turner (GT) Added Solr query character escaping
* </pre>
*
*/
@Component
@Path("/search")
public class SearchService
{
private static final Logger LOGGER = LoggerFactory.getLogger(SearchService.class);
private static final String SEARCH_JSP = "/search.jsp";
private static final String SEARCH_ADVANCED_JSP = "/search_advanced.jsp";
private static final String BROWSE_JSP = "/browse.jsp";
private static final String BROWSE_RESULTS_JSP = "/browse_results.jsp";
@Resource(name="groupServiceImpl")
GroupService groupService;
@Resource(name="solrSearchDAOImpl")
SolrSearchDAO solrSearch;
/**
* doGetAsXml
*
* Australian National University Data Commons
*
* This method is called when the search service is accessed and the type requested is XML.
*
* <pre>
* Version Date Developer Description
* 0.1 23/03/2012 Rahul Khanna (RK) Initial
* 0.2 04/05/2012 Genevieve Turner (GT) Updated for the removal of the method 'runRiSearch'
* 0.4 13/06/2012 Genevieve Turner (GT) Updated for changes to use solr as the search engine
* </pre>
*
* @return XML containing search results as a Response object.
*/
@GET
@Produces(MediaType.TEXT_XML)
public Response doGetAsXml(@QueryParam("q") String q, @QueryParam("offset") int offset, @QueryParam("limit") int limit, @QueryParam("filter") String filter)
{
//TODO Test this function
Response response = null;
try {
SolrSearchResult resultList = solrSearch.executeSearch(q, offset, limit, filter);
response = Response.ok(resultList).build();
}
catch (SolrServerException e) {
LOGGER.error("Exception retrieving results", e);
response = Response.status(Status.BAD_REQUEST).build();
}
return response;
}
/**
* doGetAsHtml
*
* Australian National University Data Commons
*
* This method is called when the search service is accessed and the type requested is HTML.
*
* @return Response to display the Search JSP and passing an object to it.
*
* <pre>
* Version Date Developer Description
* 0.1 23/03/2012 Rahul Khanna (RK) Initial
* 0.2 04/05/2012 Genevieve Turner (GT) Updated for the removal of the method 'runRiSearch'
* 0.3 8/05/2012 Rahul Khanna (RK) Updated for RiSearchRequest object.
* 0.4 13/06/2012 Genevieve Turner (GT) Updated for changes to use solr as the search engine
* </pre>
*/
@GET
@Produces(MediaType.TEXT_HTML)
public Response doGetAsHtml(@QueryParam("q") String q, @QueryParam("offset") int offset, @QueryParam("limit") int limit
, @QueryParam("filter") String filter, @QueryParam("sort") String sortField,
@QueryParam("order") String sortOrder)
{
Response response = null;
if (Util.isNotEmpty(q)) {
Map<String, Object> model = new HashMap<String, Object>();
try {
LOGGER.info("User {} submitted search query [{}]", getCurUsername(), q);
SolrSearchResult solrSearchResult = null;
if (sortOrder != null && !"".equals(sortOrder)) {
ORDER order = ORDER.asc;
if ("desc".equals(sortOrder)) {
order = ORDER.desc;
}
solrSearchResult = solrSearch.executeSearch(q, offset, limit, filter, sortField, order);
}
else {
solrSearchResult = solrSearch.executeSearch(q, offset, limit, filter);
}
model.put("resultSet", solrSearchResult);
}
catch (SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
response = Response.ok(new Viewable(SEARCH_JSP, model)).build();
}
else {
response = Response.ok(new Viewable(SEARCH_JSP)).build();
}
return response;
}
/**
* doGetAsJson
*
* Australian National University Data Commons
*
* Submits a request to RI Search Service. Returns response as JSON.
*
* <pre>
* Version Date Developer Description
* 0.1 08/05/2012 Rahul Khanna (RK) Initial
* </pre>
*
* @param q
* Search terms.
* @param offset
* Offset as int.
* @param limit
* Limit as int.
* @param filter
* Filter as String.
* @return HTTP OK Response with JSON string as its entity.
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response doGetAsJson(@QueryParam("q") String q, @QueryParam("offset") int offset, @QueryParam("limit") int limit, @QueryParam("filter") String filter)
{
//TODO Test this function
Response response = null;
try {
SolrSearchResult resultList = solrSearch.executeSearch(q, offset, limit, filter);
response = Response.ok(resultList).build();
}
catch (SolrServerException e) {
LOGGER.error("Exception retrieving results", e);
response = Response.status(Status.BAD_REQUEST).build();
}
return response;
}
/**
* Browse the provided facet
*
* @param q The value to query
* @param facetField The field to use as a facet
* @param facetSelected The selected value within the field
* @param offset The offset
* @param limit The number of items to find
* @param filter The filter (i.e. all, team, or published)
* @return The response
*/
@GET
@Path("/browse")
@Produces(MediaType.TEXT_HTML)
public Response doGetbrowseAsHtml(@QueryParam("q") String q, @QueryParam("field") String facetField
, @QueryParam("field-select") String facetSelected, @QueryParam("offset") int offset
, @QueryParam("limit") int limit, @QueryParam("filter") String filter) {
if (Util.isNotEmpty(facetField)) {
try {
SolrSearchResult solrSearchResult = solrSearch.executeSearch(q, facetField, facetSelected, offset, limit, filter);
Map<String, Object> model = new HashMap<String, Object>();
model.put("resultSet", solrSearchResult);
return Response.ok(new Viewable(BROWSE_JSP, model)).build();
}
catch(SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
}
else {
return Response.ok(new Viewable(BROWSE_JSP)).build();
}
return Response.status(Status.BAD_REQUEST).build();
}
/**
* Get the results from a further refined browse search
*
* @param q The value to query
* @param facetField The field to use as a facet
* @param facetSelected The selected value within the field
* @param offset The offset
* @param limit The number of items to find
* @param filter The filter (i.e. all, team, or published)
* @return The response
*/
@GET
@Path("/browse/results")
@Produces(MediaType.TEXT_HTML)
public Response doGetBrowseResultsAsHtml(@QueryParam("q") String q, @QueryParam("field") String facetField
, @QueryParam("field-select") String facetSelected, @QueryParam("offset") int offset
, @QueryParam("limit") int limit, @QueryParam("filter") String filter) {
if (Util.isNotEmpty(facetField)) {
try {
SolrSearchResult solrSearchResult = solrSearch.executeSearch(q, facetField, facetSelected, offset, limit, filter);
Map<String, Object> model = new HashMap<String, Object>();
model.put("resultSet", solrSearchResult);
return Response.ok(new Viewable(BROWSE_RESULTS_JSP, model)).build();
}
catch(SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
}
else {
return Response.ok(new Viewable(BROWSE_RESULTS_JSP)).build();
}
return Response.status(Status.BAD_REQUEST).build();
}
@GET
@Path("/advanced")
@Produces(MediaType.TEXT_HTML)
public Response doGetAdvancedSearchAsHtml(@QueryParam("value-type") List<String> valueTypes
, @QueryParam("search-val") List<String> searchValues, @QueryParam("offset") int offset
, @QueryParam("limit") int limit, @QueryParam("filter") String filter) {
List<SearchTerm> searchTerms = new ArrayList<SearchTerm>();
if (searchValues != null && searchValues.size() > 0) {
for (int i = 0; i < searchValues.size(); i++) {
String value = searchValues.get(i);
String key = valueTypes.get(i);
if (value != null && !"".equals(value)) {
SearchTerm term = new SearchTerm(key, value);
searchTerms.add(term);
}
}
if (searchTerms.size() > 0) {
try {
SolrSearchResult solrSearchResult = solrSearch.executeSearch(searchTerms, offset, limit, filter);
Map<String, Object> model = new HashMap<String, Object>();
model.put("resultSet", solrSearchResult);
return Response.ok(new Viewable(SEARCH_ADVANCED_JSP, model)).build();
}
catch(SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
}
}
else {
return Response.ok(new Viewable(SEARCH_ADVANCED_JSP)).build();
}
// return Response.ok(new Viewable(SEARCH_ADVANCED_JSP)).build();
return Response.status(Status.INTERNAL_SERVER_ERROR).build();
}
private String getCurUsername() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
}