/*
* SimpleSearchServlet.java
*
* Version: $Revision: 4231 $
*
* Date: $Date: 2009-08-25 03:17:33 +0000 (Tue, 25 Aug 2009) $
*
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
* Institute of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
package org.dspace.app.webui.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.app.bulkedit.MetadataExport;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.handle.HandleManager;
import org.dspace.search.DSQuery;
import org.dspace.search.QueryArgs;
import org.dspace.search.QueryResults;
import org.dspace.sort.SortOption;
import org.dspace.browse.*;
/**
* Servlet for handling a simple search.
* <p>
* All metadata is search for the value contained in the "query" parameter. If
* the "location" parameter is present, the user's location is switched to that
* location using a redirect. Otherwise, the user's current location is used to
* constrain the query; i.e., if the user is "in" a collection, only results
* from the collection will be returned.
* <p>
* The value of the "location" parameter should be ALL (which means no
* location), a the ID of a community (e.g. "123"), or a community ID, then a
* slash, then a collection ID, e.g. "123/456".
*
* @author Robert Tansley
* @version $Id: SimpleSearchServlet.java,v 1.17 2004/12/15 15:21:10 jimdowning
* Exp $
*/
public class SimpleSearchServlet extends DSpaceServlet
{
/** log4j category */
private static Logger log = Logger.getLogger(SimpleSearchServlet.class);
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException
{
// Get the query
String query = request.getParameter("query");
int start = UIUtil.getIntParameter(request, "start");
String advanced = request.getParameter("advanced");
String fromAdvanced = request.getParameter("from_advanced");
int sortBy = UIUtil.getIntParameter(request, "sort_by");
String order = request.getParameter("order");
int rpp = UIUtil.getIntParameter(request, "rpp");
String advancedQuery = "";
HashMap queryHash = new HashMap();
// can't start earlier than 0 in the results!
if (start < 0)
{
start = 0;
}
int collCount = 0;
int commCount = 0;
int itemCount = 0;
Item[] resultsItems;
Collection[] resultsCollections;
Community[] resultsCommunities;
QueryResults qResults = null;
QueryArgs qArgs = new QueryArgs();
SortOption sortOption = null;
if (request.getParameter("etal") != null)
qArgs.setEtAl(UIUtil.getIntParameter(request, "etal"));
try
{
if (sortBy > 0)
{
sortOption = SortOption.getSortOption(sortBy);
qArgs.setSortOption(sortOption);
}
if (SortOption.ASCENDING.equalsIgnoreCase(order))
{
qArgs.setSortOrder(SortOption.ASCENDING);
}
else
{
qArgs.setSortOrder(SortOption.DESCENDING);
}
}
catch (Exception e)
{
}
// Override the page setting if exporting metadata
if ("submit_export_metadata".equals(UIUtil.getSubmitButton(request, "submit")))
{
qArgs.setPageSize(Integer.MAX_VALUE);
}
else if (rpp > 0)
{
qArgs.setPageSize(rpp);
}
// if the "advanced" flag is set, build the query string from the
// multiple query fields
if (advanced != null)
{
query = qArgs.buildQuery(request);
advancedQuery = qArgs.buildHTTPQuery(request);
}
// Ensure the query is non-null
if (query == null)
{
query = "";
}
// Get the location parameter, if any
String location = request.getParameter("location");
String newURL;
// If there is a location parameter, we should redirect to
// do the search with the correct location.
if ((location != null) && !location.equals(""))
{
String url = "";
if (!location.equals("/"))
{
// Location is a Handle
url = "/handle/" + location;
}
// Encode the query
query = URLEncoder.encode(query, Constants.DEFAULT_ENCODING);
if (advancedQuery.length() > 0)
{
query = query + "&from_advanced=true&" + advancedQuery;
}
// Do the redirect
response.sendRedirect(response.encodeRedirectURL(request
.getContextPath()
+ url + "/simple-search?query=" + query));
return;
}
// Build log information
String logInfo = "";
// Get our location
Community community = UIUtil.getCommunityLocation(request);
Collection collection = UIUtil.getCollectionLocation(request);
// get the start of the query results page
// List resultObjects = null;
qArgs.setQuery(query);
qArgs.setStart(start);
// Perform the search
if (collection != null)
{
logInfo = "collection_id=" + collection.getID() + ",";
// Values for drop-down box
request.setAttribute("community", community);
request.setAttribute("collection", collection);
qResults = DSQuery.doQuery(context, qArgs, collection);
}
else if (community != null)
{
logInfo = "community_id=" + community.getID() + ",";
request.setAttribute("community", community);
// Get the collections within the community for the dropdown box
request
.setAttribute("collection.array", community
.getCollections());
qResults = DSQuery.doQuery(context, qArgs, community);
}
else
{
// Get all communities for dropdown box
Community[] communities = Community.findAll(context);
request.setAttribute("community.array", communities);
qResults = DSQuery.doQuery(context, qArgs);
}
// now instantiate the results and put them in their buckets
for (int i = 0; i < qResults.getHitTypes().size(); i++)
{
Integer myType = (Integer) qResults.getHitTypes().get(i);
// add the handle to the appropriate lists
switch (myType.intValue())
{
case Constants.ITEM:
itemCount++;
break;
case Constants.COLLECTION:
collCount++;
break;
case Constants.COMMUNITY:
commCount++;
break;
}
}
// Make objects from the handles - make arrays, fill them out
resultsCommunities = new Community[commCount];
resultsCollections = new Collection[collCount];
resultsItems = new Item[itemCount];
collCount = 0;
commCount = 0;
itemCount = 0;
for (int i = 0; i < qResults.getHitTypes().size(); i++)
{
Integer myId = (Integer) qResults.getHitIds().get(i);
String myHandle = (String) qResults.getHitHandles().get(i);
Integer myType = (Integer) qResults.getHitTypes().get(i);
// add the handle to the appropriate lists
switch (myType.intValue())
{
case Constants.ITEM:
if (myId != null)
{
resultsItems[itemCount] = Item.find(context, myId);
}
else
{
resultsItems[itemCount] = (Item)HandleManager.resolveToObject(context, myHandle);
}
if (resultsItems[itemCount] == null)
{
throw new SQLException("Query \"" + query
+ "\" returned unresolvable item");
}
itemCount++;
break;
case Constants.COLLECTION:
if (myId != null)
{
resultsCollections[collCount] = Collection.find(context, myId);
}
else
{
resultsCollections[collCount] = (Collection)HandleManager.resolveToObject(context, myHandle);
}
if (resultsCollections[collCount] == null)
{
throw new SQLException("Query \"" + query
+ "\" returned unresolvable collection");
}
collCount++;
break;
case Constants.COMMUNITY:
if (myId != null)
{
resultsCommunities[commCount] = Community.find(context, myId);
}
else
{
resultsCommunities[commCount] = (Community)HandleManager.resolveToObject(context, myHandle);
}
if (resultsCommunities[commCount] == null)
{
throw new SQLException("Query \"" + query
+ "\" returned unresolvable community");
}
commCount++;
break;
}
}
// Log
log.info(LogManager.getHeader(context, "search", logInfo + "query=\""
+ query + "\",results=(" + resultsCommunities.length + ","
+ resultsCollections.length + "," + resultsItems.length + ")"));
// Pass in some page qualities
// total number of pages
int pageTotal = 1 + ((qResults.getHitCount() - 1) / qResults
.getPageSize());
// current page being displayed
int pageCurrent = 1 + (qResults.getStart() / qResults.getPageSize());
// pageLast = min(pageCurrent+9,pageTotal)
int pageLast = ((pageCurrent + 9) > pageTotal) ? pageTotal
: (pageCurrent + 9);
// pageFirst = max(1,pageCurrent-9)
int pageFirst = ((pageCurrent - 9) > 1) ? (pageCurrent - 9) : 1;
// Pass the results to the display JSP
request.setAttribute("items", resultsItems);
request.setAttribute("communities", resultsCommunities);
request.setAttribute("collections", resultsCollections);
request.setAttribute("pagetotal", new Integer(pageTotal));
request.setAttribute("pagecurrent", new Integer(pageCurrent));
request.setAttribute("pagelast", new Integer(pageLast));
request.setAttribute("pagefirst", new Integer(pageFirst));
request.setAttribute("queryresults", qResults);
// And the original query string
request.setAttribute("query", query);
request.setAttribute("order", qArgs.getSortOrder());
request.setAttribute("sortedBy", sortOption);
if (AuthorizeManager.isAdmin(context))
{
// Set a variable to create admin buttons
request.setAttribute("admin_button", new Boolean(true));
}
if ((fromAdvanced != null) && (qResults.getHitCount() == 0))
{
// send back to advanced form if no results
Community[] communities = Community.findAll(context);
request.setAttribute("communities", communities);
request.setAttribute("no_results", "yes");
queryHash = qArgs.buildQueryHash(request);
Iterator i = queryHash.keySet().iterator();
while (i.hasNext())
{
String key = (String) i.next();
String value = (String) queryHash.get(key);
request.setAttribute(key, value);
}
JSPManager.showJSP(request, response, "/search/advanced.jsp");
}
else if ("submit_export_metadata".equals(UIUtil.getSubmitButton(request, "submit")))
{
exportMetadata(context, response, resultsItems);
}
else
{
JSPManager.showJSP(request, response, "/search/results.jsp");
}
}
/**
* Export the search results as a csv file
*
* @param context The DSpace context
* @param response The request object
* @param items The result items
* @throws IOException
* @throws ServletException
*/
protected void exportMetadata(Context context, HttpServletResponse response, Item[] items)
throws IOException, ServletException
{
// Log the attempt
log.info(LogManager.getHeader(context, "metadataexport", "exporting_search"));
// Export a search view
ArrayList iids = new ArrayList();
for (Item item : items)
{
iids.add(item.getID());
}
ItemIterator ii = new ItemIterator(context, iids);
MetadataExport exporter = new MetadataExport(context, ii, false);
// Perform the export
DSpaceCSV csv = exporter.export();
// Return the csv file
response.setContentType("text/csv; charset=UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=search-results.csv");
PrintWriter out = response.getWriter();
out.write(csv.toString());
out.flush();
out.close();
log.info(LogManager.getHeader(context, "metadataexport", "exported_file:search-results.csv"));
return;
}
}