/* * AbstractBrowserServlet.java * * Version: $Revision: 4365 $ * * Date: $Date: 2009-10-05 23:52:42 +0000 (Mon, 05 Oct 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.sql.SQLException; 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.UIUtil; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeManager; import org.dspace.browse.BrowseEngine; import org.dspace.browse.BrowseException; import org.dspace.browse.BrowseIndex; import org.dspace.browse.BrowseInfo; import org.dspace.browse.BrowserScope; import org.dspace.sort.SortOption; import org.dspace.sort.SortException; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.LogManager; /** * Servlet for browsing through indices, as they are defined in * the configuration. This class can take a wide variety of inputs from * the user interface: * * - type: the type of browse (index name) being performed * - order: (ASC | DESC) the direction for result sorting * - value: A specific value to find items around. For example the author name or subject * - month: integer specification of the month of a date browse * - year: integer specification of the year of a date browse * - starts_with: string value at which to start browsing * - vfocus: start browsing with a value of this string * - focus: integer id of the item at which to start browsing * - rpp: integer number of results per page to display * - sort_by: integer specification of the field to search on * - etal: integer number to limit multiple value items specified in config to * * @author Richard Jones * @version $Revision: 4365 $ */ public abstract class AbstractBrowserServlet extends DSpaceServlet { /** log4j category */ private static Logger log = Logger.getLogger(AbstractBrowserServlet.class); public AbstractBrowserServlet() { super(); } /** * Create a BrowserScope from the current request * * @param context The database context * @param request The servlet request * @param response The servlet response * @return A BrowserScope for the current parameters * @throws ServletException * @throws IOException * @throws SQLException * @throws AuthorizeException */ protected BrowserScope getBrowserScopeForRequest(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { try { // first, lift all the stuff out of the request that we might need String type = request.getParameter("type"); String order = request.getParameter("order"); String value = request.getParameter("value"); String valueLang = request.getParameter("value_lang"); String month = request.getParameter("month"); String year = request.getParameter("year"); String startsWith = request.getParameter("starts_with"); String valueFocus = request.getParameter("vfocus"); String valueFocusLang = request.getParameter("vfocus_lang"); String authority = request.getParameter("authority"); int focus = UIUtil.getIntParameter(request, "focus"); int offset = UIUtil.getIntParameter(request, "offset"); int resultsperpage = UIUtil.getIntParameter(request, "rpp"); int sortBy = UIUtil.getIntParameter(request, "sort_by"); int etAl = UIUtil.getIntParameter(request, "etal"); // get the community or collection location for the browse request // Note that we are only interested in getting the "smallest" container, // so if we find a collection, we don't bother looking up the community Collection collection = null; Community community = null; collection = UIUtil.getCollectionLocation(request); if (collection == null) { community = UIUtil.getCommunityLocation(request); } // process the input, performing some inline validation BrowseIndex bi = null; if (type != null && !"".equals(type)) { bi = BrowseIndex.getBrowseIndex(type); } if (bi == null) { if (sortBy > 0) bi = BrowseIndex.getBrowseIndex(SortOption.getSortOption(sortBy)); else bi = BrowseIndex.getBrowseIndex(SortOption.getDefaultSortOption()); } // If we don't have a sort column if (bi != null && sortBy == -1) { // Get the default one SortOption so = bi.getSortOption(); if (so != null) { sortBy = so.getNumber(); } } else if (bi != null && bi.isItemIndex() && !bi.isInternalIndex()) { // If a default sort option is specified by the index, but it isn't // the same as sort option requested, attempt to find an index that // is configured to use that sort by default // This is so that we can then highlight the correct option in the navigation SortOption bso = bi.getSortOption(); SortOption so = SortOption.getSortOption(sortBy); if ( bso != null && bso != so) { BrowseIndex newBi = BrowseIndex.getBrowseIndex(so); if (newBi != null) { bi = newBi; type = bi.getName(); } } } if (order == null && bi != null) { order = bi.getDefaultOrder(); } // If the offset is invalid, reset to 0 if (offset < 0) { offset = 0; } // if no resultsperpage set, default to 20 if (resultsperpage < 0) { resultsperpage = 20; } // if year and perhaps month have been selected, we translate these into "startsWith" // if startsWith has already been defined then it is overwritten if (year != null && !"".equals(year) && !"-1".equals(year)) { startsWith = year; if ((month != null) && !"-1".equals(month) && !"".equals(month)) { // subtract 1 from the month, so the match works appropriately if ("ASC".equals(order)) { month = Integer.toString((Integer.parseInt(month) - 1)); } // They've selected a month as well if (month.length() == 1) { // Ensure double-digit month number month = "0" + month; } startsWith = year + "-" + month; if ("ASC".equals(order)) { startsWith = startsWith + "-32"; } } } // determine which level of the browse we are at: 0 for top, 1 for second int level = 0; if (value != null || authority != null) { level = 1; } // if sortBy is still not set, set it to 0, which is default to use the primary index value if (sortBy == -1) { sortBy = 0; } // figure out the setting for author list truncation if (etAl == -1) // there is no limit, or the UI says to use the default { int limitLine = ConfigurationManager.getIntProperty("webui.browse.author-limit"); if (limitLine != 0) { etAl = limitLine; } } else // if the user has set a limit { if (etAl == 0) // 0 is the user setting for unlimited { etAl = -1; // but -1 is the application setting for unlimited } } // log the request String comHandle = "n/a"; if (community != null) { comHandle = community.getHandle(); } String colHandle = "n/a"; if (collection != null) { colHandle = collection.getHandle(); } String arguments = "type=" + type + ",order=" + order + ",value=" + value + ",month=" + month + ",year=" + year + ",starts_with=" + startsWith + ",vfocus=" + valueFocus + ",focus=" + focus + ",rpp=" + resultsperpage + ",sort_by=" + sortBy + ",community=" + comHandle + ",collection=" + colHandle + ",level=" + level + ",etal=" + etAl; log.info(LogManager.getHeader(context, "browse", arguments)); // set up a BrowseScope and start loading the values into it BrowserScope scope = new BrowserScope(context); scope.setBrowseIndex(bi); scope.setOrder(order); scope.setFilterValue(value != null?value:authority); scope.setFilterValueLang(valueLang); scope.setJumpToItem(focus); scope.setJumpToValue(valueFocus); scope.setJumpToValueLang(valueFocusLang); scope.setStartsWith(startsWith); scope.setOffset(offset); scope.setResultsPerPage(resultsperpage); scope.setSortBy(sortBy); scope.setBrowseLevel(level); scope.setEtAl(etAl); scope.setAuthorityValue(authority); // assign the scope of either Community or Collection if necessary if (community != null) { scope.setBrowseContainer(community); } else if (collection != null) { scope.setBrowseContainer(collection); } // For second level browses on metadata indexes, we need to adjust the default sorting if (bi != null && bi.isMetadataIndex() && scope.isSecondLevel() && scope.getSortBy() <= 0) { scope.setSortBy(1); } return scope; } catch (SortException se) { log.error("caught exception: ", se); throw new ServletException(se); } catch (BrowseException e) { log.error("caught exception: ", e); throw new ServletException(e); } } /** * Do the usual DSpace GET method. You will notice that browse does not currently * respond to POST requests. */ protected void processBrowse(Context context, BrowserScope scope, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException { try { BrowseIndex bi = scope.getBrowseIndex(); // now start up a browse engine and get it to do the work for us BrowseEngine be = new BrowseEngine(context); BrowseInfo binfo = be.browse(scope); request.setAttribute("browse.info", binfo); if (AuthorizeManager.isAdmin(context)) { // Set a variable to create admin buttons request.setAttribute("admin_button", new Boolean(true)); } if (binfo.hasResults()) { if (bi.isMetadataIndex() && !scope.isSecondLevel()) { showSinglePage(context, request, response); } else { showFullPage(context, request, response); } } else { showNoResultsPage(context, request, response); } } catch (BrowseException e) { log.error("caught exception: ", e); throw new ServletException(e); } } /** * Display the error page * * @param context * @param request * @param response * @throws ServletException * @throws IOException * @throws SQLException * @throws AuthorizeException */ protected abstract void showError(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException; /** * Display the No Results page * * @param context * @param request * @param response * @throws ServletException * @throws IOException * @throws SQLException * @throws AuthorizeException */ protected abstract void showNoResultsPage(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException; /** * Display the single page. This is the page which lists just the single values of a * metadata browse, not individual items. Single values are links through to all the items * that match that metadata value * * @param context * @param request * @param response * @throws ServletException * @throws IOException * @throws SQLException * @throws AuthorizeException */ protected abstract void showSinglePage(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException; protected abstract void showFullPage(Context context, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, SQLException, AuthorizeException; }