/*******************************************************************************
* 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.pambu;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import au.edu.anu.datacommons.data.solr.SolrManager;
import au.edu.anu.datacommons.data.solr.model.SolrSearchResult;
import au.edu.anu.datacommons.properties.GlobalProps;
import au.edu.anu.datacommons.util.Util;
import com.sun.jersey.api.view.Viewable;
/**
* PambuSearchService
*
* Australian National University Data Commons
*
* Placeholder
*
* JUnit Coverage:
* None
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner (GT) Initial
* 0.2 13/06/2012 Genevieve Turner (GT) Updated to use solrj classes and added and/or query functionality
* 0.3 10/08/2012 Genevieve Turner (GT) Updated to provide more get options.
* 0.4 14/08/2012 Genevieve Turner (GT) Updated to show links for the web crawler
* 0.5 31/10/2012 Genevieve Turner (GT) Updated to add id and alternate name fields to be returned
* 0.6 28/11/2012 Genevieve Turner (GT) Updated to add the digital format field to be returned
* </pre>
*
*/
@Component
@Path("/pambu")
public class PambuSearchResource {
private static final Logger LOGGER = LoggerFactory.getLogger(PambuSearchResource.class);
/**
* doGetPAMBUHTML
*
* Returns a html response for a get for pambu
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* 0.3 10/08/2012 Genevieve Turner (GT) Updated to provide more get options.
* </pre>
*
* @return The html response
*/
@GET
@Path("/search")
@Produces(MediaType.TEXT_HTML)
public Response doGetPAMBUHTML(@Context HttpServletRequest request) {
Response response = null;
if (Util.isNotEmpty(request.getParameter("submit"))) {
response = doPostPAMBUHTML(request);
}
else if (Util.isNotEmpty(request.getParameter("browseAll"))) {
response = doPostPAMBUHTML(request);
}
else {
response = Response.ok(new Viewable("/pambu/pambusearch.jsp")).build();
}
return response;
}
/**
* doPostPAMBUHTML
*
* Returns a html response for a get for pambu
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* </pre>
*
* @param request Request information
* @return The html response
*/
@POST
@Path("/search")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_HTML)
public Response doPostPAMBUHTML(@Context HttpServletRequest request) {
int numRows = 1000;
String selection = request.getParameter("selection");
String pmbHolding = request.getParameter("pmbHolding");
String modifier = request.getParameter("modifier");
String preferredOrder = request.getParameter("preferredOrder");
String output = request.getParameter("output");
String entry = request.getParameter("entry");
String page = request.getParameter("page");
SolrQuery solrQuery = new SolrQuery();
solrQuery.setRows(numRows);
if (Util.isNotEmpty(page)) {
int pageNum = Integer.valueOf(page);
int start = (pageNum - 1) * numRows;
solrQuery.setStart(start);
}
if (Util.isNotEmpty(request.getParameter("submit"))) {
entry = processModifier(modifier, entry, solrQuery);
}
else if (Util.isNotEmpty(request.getParameter("clear"))) {
return Response.ok(new Viewable("/pambu/pambusearch.jsp")).build();
}
else if (Util.isNotEmpty(request.getParameter("browseAll"))) {
selection = "browseAll";
}
Response response = null;
Map<String, Object> model = new HashMap<String, Object>();
// Set fields to search
setPAMBUQueryFields(selection, entry, solrQuery);
// Filter out documents and manuscripts
setPAMBUFilterFields(pmbHolding, solrQuery);
// Sort items
setPAMBUSortFields(preferredOrder, solrQuery);
// Set the values to be returned
setPAMBUReturnFields(output, solrQuery);
SolrServer solrServer = SolrManager.getInstance().getSolrServer();
try {
QueryResponse queryResponse = solrServer.query(solrQuery);
SolrDocumentList resultList = queryResponse.getResults();
LOGGER.debug("Number of results: {}",resultList.getNumFound());
SolrSearchResult solrSearchResult = new SolrSearchResult(resultList);
model.put("resultSet", solrSearchResult);
}
catch (SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
response = Response.ok(new Viewable("/pambu/pambu.jsp", model)).build();
return response;
}
/**
* processModifier
*
* Adds a filter to make sure that the field contains all fields when AND has been selected.
* It also ensures that all fields selected are searched for
*
* <pre>
* Version Date Developer Description
* 0.2 12/06/2012 Genevieve Turner(GT) Initial
* </pre>
*
* @param value The value of the search criteria filter
* @param entry The value of the entry field in the request
* @param solrQuery The solrQuery to execute
* @return A string to add to the query
*/
private String processModifier(String value, String entry, SolrQuery solrQuery) {
if ("AND".equals(value)) {
String[] entries = entry.split(" ");
for (String filter : entries) {
solrQuery.addFilterQuery("published.all:" + filter);
}
}
return "(" + entry + ")";
}
/**
* setPAMBUQueryFields
*
* Sets the query fields for PAMBU
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* 0.2 13/06/2012 Genevieve Turner (GT) Updated to use solrj classes and added and/or query functionality
* </pre>
*
* @param value The value of the search criteria filter
* @param entry The value of the entry field in the request
* @param solrQuery The SolrQuery to add fields to
*/
private void setPAMBUQueryFields(String value, String entry, SolrQuery solrQuery) {
StringBuffer query = new StringBuffer();
if ("author".equals(value) || "all".equals(value)) {
addQueryField(query, "published.combinedAuthors", entry);
}
if ("title".equals(value) || "all".equals(value)) {
addQueryField(query, "published.name", entry);
}
if ("serial".equals(value) || "all".equals(value)) {
addQueryField(query, "published.serialNum", entry);
}
if ("notes".equals(value) || "all".equals(value)) {
addQueryField(query, "published.briefDesc", entry);
addQueryField(query, "published.fullDesc", entry);
}
if ("browseAll".equals(value)) {
addQueryField(query, "*","*");
}
solrQuery.setQuery(query.toString());
}
/**
* addQueryField
*
* Add the field to the query fields string
*
* <pre>
* Version Date Developer Description
* 0.1 13/06/2012 Genevieve Turner(GT) Initial
* </pre>
*
* @param query
* @param field
* @param value
*/
private void addQueryField(StringBuffer query, String field, String value) {
if (!query.toString().equals("")) {
query.append(" ");
}
query.append(field);
query.append(":");
query.append(value);
}
/**
* setPAMBUReturnFields
*
* Sets the fields to be returned for the PAMBU search
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* 0.2 13/06/2012 Genevieve Turner (GT) Updated to use solrj classes and added and/or query functionality
* 0.5 31/10/2012 Genevieve Turner (GT) Updated to add id and alternate name fields to be returned
* 0.6 28/11/2012 Genevieve Turner (GT) Updated to add the digital format field to be returned
* </pre>
*
* @param value The value of the return criteria filter
* @param solrQuery The SolrQuery to add fields to
*/
private void setPAMBUReturnFields(String value, SolrQuery solrQuery) {
solrQuery.addField("published.combinedAuthors");
solrQuery.addField("published.name");
solrQuery.addField("published.combinedDates.formatted");
solrQuery.addField("published.holdingLocation");
solrQuery.addField("published.numReels");
solrQuery.addField("published.serialNum");
solrQuery.addField("published.accessRights");
solrQuery.addField("published.format");
solrQuery.addField("published.digiFormat");
solrQuery.addField("id");
solrQuery.addField("published.altName");
if ("long".equals(value)) {
solrQuery.addField("published.briefDesc");
solrQuery.addField("published.fullDesc");
solrQuery.addField("published.holdingType");
solrQuery.addField("published.reelList");
}
}
/**
* setPAMBUFilterFields
*
* Set the filter fields for the PAMBU search
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* 0.2 13/06/2012 Genevieve Turner (GT) Updated to use solrj classes and added and/or query functionality
* </pre>
*
* @param value The value of the filter fields criteria filter
* @param solrQuery The SolrQuery to add fields to
*/
private void setPAMBUFilterFields(String value, SolrQuery solrQuery) {
solrQuery.addFilterQuery("location.published:PAMBU");
if (value.equals("doc")) {
solrQuery.addFilterQuery("published.holdingType:doc");
}
if (value.equals("ms")) {
solrQuery.addFilterQuery("published.holdingType:ms");
}
else {
solrQuery.addFilterQuery("published.holdingType:doc,ms");
}
}
/**
* setPAMBUSortFields
*
* Set the sort order for the PAMBU search
*
* <pre>
* Version Date Developer Description
* 0.1 08/06/2012 Genevieve Turner(GT) Initial
* 0.2 13/06/2012 Genevieve Turner (GT) Updated to use solrj classes and added and/or query functionality
* </pre>
*
* @param value The value of the sort order
* @param solrQuery The SolrQuery to add fields to
*/
private void setPAMBUSortFields(String value, SolrQuery solrQuery) {
if ("sortVal".equals(value)) {
solrQuery.addSortField("published.sortVal", ORDER.asc);
}
else if ("author".equals(value)) {
solrQuery.addSortField("published.combinedAuthors", ORDER.asc);
}
else if ("date".equals(value)) {
solrQuery.addSortField("published.combinedDates", ORDER.asc);
}
}
/**
* listAllPAMBUPublished
*
* Gets a list of links for the web crawler. For Printed Documents and Manuscripts
* the link is a search result for the id.
*
* <pre>
* Version Date Developer Description
* 0.4 14/08/2012 Genevieve Turner(GT) Initial
* </pre>
*
* @param context Uri information
* @return A page with links for the web crawler
*/
@GET
@Path("/published")
@Produces(MediaType.TEXT_HTML)
public Response listAllPAMBUPublished(@Context UriInfo context) {
int numResults = 1000;
StringBuffer linksPage = new StringBuffer();
linksPage.append("<html><body>");
Response response = null;
// get manuscript and document series
SolrQuery solrQuery = new SolrQuery();
solrQuery.setRows(numResults);
// Get all the records
setPAMBUQueryFields("browseAll", "", solrQuery);
// Get all both manuscripts and printed documents
setPAMBUFilterFields("", solrQuery);
// Sort items
setPAMBUSortFields("sortVal", solrQuery);
// Set the values to be returned
// may need to change this to the serial number and then adjust createLinks accordingly
solrQuery.addField("published.externalId");
SolrServer solrServer = SolrManager.getInstance().getSolrServer();
try {
QueryResponse queryResponse = solrServer.query(solrQuery);
SolrDocumentList resultList = queryResponse.getResults();
long numFound = resultList.getNumFound();
linksPage.append(createLinks(resultList, context));
for (int i = numResults; i < numFound; i = i + numResults) {
LOGGER.info("Start: {}", i);
solrQuery.setStart(i);
queryResponse = solrServer.query(solrQuery);
resultList = queryResponse.getResults();
linksPage.append(createLinks(resultList, context));
}
}
catch (SolrServerException e) {
LOGGER.error("Exception querying solr", e);
}
linksPage.append("</html></body>");
response = Response.ok(linksPage.toString()).build();
return response;
}
/**
* createLinks
*
* Generates a list of links for the given list of documents
*
* <pre>
* Version Date Developer Description
* 0.4 14/08/2012 Genevieve Turner(GT) Initial
* </pre>
*
* @param resultList A list of results to create links for
* @param context Uri information
* @return HTML formatted links
*/
private String createLinks(SolrDocumentList resultList, UriInfo context) {
String patternStr = "(ms|doc){1}([0-9]*)";
Pattern pattern = Pattern.compile(patternStr);
StringBuffer sb = new StringBuffer();
resultList.iterator();
Iterator<SolrDocument> it = resultList.iterator();
while (it.hasNext()) {
SolrDocument document = it.next();
String value = (String) document.getFirstValue("published.externalId");
Matcher matcher = pattern.matcher(value);
boolean matchFound = matcher.find();
if (matchFound) {
String typeStr = matcher.group(1);
String numberStr = matcher.group(2);
String urlStr = String.format("%s%spambu/search?selection=serial&pmbHolding=%s&modifier=AND&preferredOrder=sortVal&output=long&entry=%s&page=1&submit=Submit+this+search",GlobalProps.getProperty(GlobalProps.PROP_APP_SERVER), context.getBaseUri().getRawPath(), typeStr, numberStr);
sb.append("<a href='");
sb.append(urlStr);
sb.append("'>");
sb.append(matcher.group(0));
sb.append("</a>");
sb.append("<br />");
}
}
return sb.toString();
}
}