Merge pull request #60 from abollini/DS-1217

DS-1217 Porting Discovery to the JSPUI
This commit is contained in:
abollini
2012-09-13 03:40:57 -07:00
66 changed files with 4616 additions and 682 deletions

View File

@@ -221,6 +221,24 @@ public class Item extends DSpaceObject
return new ItemIterator(context, rows);
}
/**
* Get all "final" items in the archive, both archived ("in archive" flag) or
* withdrawn items are included. The order of the list is indeterminate.
*
* @param context
* DSpace context object
* @return an iterator over the items in the archive.
* @throws SQLException
*/
public static ItemIterator findAllUnfiltered(Context context) throws SQLException
{
String myQuery = "SELECT * FROM item WHERE in_archive='1' or withdrawn='1'";
TableRowIterator rows = DatabaseManager.queryTable(context, "item", myQuery);
return new ItemIterator(context, rows);
}
/**
* Find all the items in the archive by a given submitter. The order is

View File

@@ -202,7 +202,7 @@ public class PluginManager
if (val == null)
{
log.warn("No Configuration entry found for Sequence Plugin interface="+iname);
return new Object[0];
return (Object[]) Array.newInstance(intfc, 0);
}
classname = val.trim().split("\\s*,\\s*");
sequenceConfig.put(iname, classname);

View File

@@ -0,0 +1,45 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.plugin;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Interface that must be implemented by any plugin wanting to be called at the
* inception of the Item page (in HandleServlet). Classes that
* implement the process method and appear in the configuration will be run
* before the at the start of preparing the item home page has any chance
* to continue its execution. <b>Note that the plugin is executed also before
* than the READ permission on the item is checked</b>
*
* @author Andrea Bollini
*
*/
public interface ItemHomeProcessor
{
/**
* execute the process
*
* @param context the DSpace context
* @param request the HTTP request
* @param response the HTTP response
* @param item the item object whose home page we are on
*
* @throws PluginException any particular problem with the plugin execution
* @throws AuthorizeException Authorisation errors during plugin execution
*/
void process(Context context, HttpServletRequest request,
HttpServletResponse response, Item item)
throws PluginException, AuthorizeException;
}

View File

@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.plugin;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
/**
* Interface that must be implemented by any plugin wanting to be called at the
* inception of the Site home page (in index.jsp "welcome servlet"). Classes that
* implement the process method and appear in the configuration will be run
* before the at the start of preparing the home page has any chance
* to continue its execution
*
* @author Andrea Bollini
*
*/
public interface SiteHomeProcessor
{
/**
* execute the process
*
* @param context the DSpace context
* @param request the HTTP request
* @param response the HTTP response
*
* @throws PluginException any particular problem with the plugin execution
* @throws AuthorizeException Authorisation errors during plugin execution
*/
void process(Context context, HttpServletRequest request,
HttpServletResponse response)
throws PluginException, AuthorizeException;
}

View File

@@ -10,6 +10,7 @@ package org.dspace.search;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@@ -115,6 +116,9 @@ public class DSQuery
try
{
// calculate execution time
Date startTime = new Date();
// grab a searcher, and do the search
IndexSearcher searcher = getSearcher(c);
@@ -133,7 +137,11 @@ public class DSQuery
Query myquery = qp.parse(querystring);
//Retrieve enough docs to get all the results we need !
TopDocs hits = performQuery(args, searcher, myquery, args.getPageSize() * (args.getStart() + 1));
Date endTime = new Date();
qr.setQueryTime(endTime.getTime() - startTime.getTime());
// set total number of hits
qr.setHitCount(hits.totalHits);

View File

@@ -18,6 +18,8 @@ import org.dspace.core.ConfigurationManager;
*/
public class QueryResults
{
private long queryTime; // time to search (ms)
private int hitCount; // total hits returned by search engine
private int start; // offset of query 'page'
@@ -34,6 +36,16 @@ public class QueryResults
/** number of metadata elements to display before truncating using "et al" */
private int etAl = ConfigurationManager.getIntProperty("webui.itemlist.author-limit");
public long getQueryTime()
{
return queryTime;
}
public void setQueryTime(long queryTime)
{
this.queryTime = queryTime;
}
/**
* @return the number of metadata fields at which to truncate with "et al"
*/

View File

@@ -817,16 +817,40 @@ jsp.search.advanced.type.title = Title
jsp.search.error.invalid-search-string = Invalid search string
jsp.search.error.number-format-exception = Number format exception
jsp.search.error.query-too-broad = Your query was too broad. Try a narrower query.
jsp.search.general.new-search = Start a new search
jsp.search.general.next = next
jsp.search.general.noresults = Search produced no results.
jsp.search.general.previous = previous
jsp.search.results.colhits = Collection hits:
jsp.search.results.comhits = Community Hits:
jsp.search.results.itemhits = Item hits:
jsp.search.results.results = Results {0}-{1} of {2}.
jsp.search.results.results = Results {0}-{1} of {2} (Search time: {3} seconds).
jsp.search.results.searchfor = for
jsp.search.results.searchin = Search:
jsp.search.results.title = Search Results
jsp.search.title = Search
jsp.search.error.discovery = An error has occured. Your query is invalid or the search engine is down.
jsp.search.facet.refine = Discover
jsp.search.facet.refine.author = Author
jsp.search.facet.refine.subject = Subject
jsp.search.facet.refine.dateIssued = Date issued
jsp.search.facet.refine.previous = < previous
jsp.search.facet.refine.next = next >
jsp.search.facet.narrow = Filter by {0}
jsp.search.filter.heading = Add filters:
jsp.search.filter.hint = Use filters to refine the search results.
jsp.search.filter.add = Add
jsp.search.filter.applied = Current filters:
jsp.search.filter.title = Title
jsp.search.filter.author = Author
jsp.search.filter.subject = Subject
jsp.search.filter.dateIssued = Date Issued
jsp.search.filter.op.equals = Equals
jsp.search.filter.op.notequals = Not Equals
jsp.search.filter.op.contains = Contains
jsp.search.filter.op.notcontains = Not Contains
jsp.search.filter.op.authority = ID
jsp.search.filter.op.notauthority = Not ID
jsp.statistics.title = Statistics
jsp.statistics.heading.visits = Total Visits
jsp.statistics.heading.monthlyvisits = Total Visits per Month
@@ -1456,6 +1480,10 @@ search.sort-by.relevance
search.sort-by.title = Title
search.sort-by.dateissued = Issue Date
search.sort-by.dateaccessioned = Submit Date
# used by discovery (standard sort index <metadata>_sort)
search.sort-by.dc.title_sort = Title
# used by discovery (date sort index <metadata>_dt)
search.sort-by.dc.date.issued_dt = Issue Date
search.update = Update
# authority-control confidence levels, descriptions:

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>dspace-discovery-jspui-api</artifactId>
<name>DSpace Discovery :: Discovery JSPUI API</name>
<parent>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-jspui-api</artifactId>
<exclusions>
<exclusion>
<artifactId>solr-solrj</artifactId>
<groupId>org.apache.solr</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.flexjson</groupId>
<artifactId>flexjson</artifactId>
<version>2.1</version>
</dependency>
<!-- external -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery-provider</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,793 @@
package org.dspace.app.webui.discovery;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.DiscoverFacetField;
import org.dspace.discovery.DiscoverFilterQuery;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverQuery.SORT_ORDER;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.discovery.configuration.DiscoverySortConfiguration;
import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
import org.dspace.discovery.configuration.SidebarFacetConfiguration;
import org.dspace.handle.HandleManager;
import org.dspace.search.QueryArgs;
import org.dspace.search.QueryResults;
public class DiscoverUtility
{
/** log4j category */
private static Logger log = Logger.getLogger(DiscoverUtility.class);
/**
* Get the scope of the search using the parameter found in the request
*
* @param context
* @param request
* @return
* @throws IllegalStateException
* @throws SQLException
*/
public static DSpaceObject getSearchScope(Context context,
HttpServletRequest request) throws IllegalStateException,
SQLException
{
// Get the location parameter, if any
String location = request.getParameter("location");
if (location == null)
{
if (UIUtil.getCollectionLocation(request) != null)
{
return UIUtil.getCollectionLocation(request);
}
if (UIUtil.getCommunityLocation(request) != null)
{
return UIUtil.getCommunityLocation(request);
}
return null;
}
DSpaceObject scope = HandleManager.resolveToObject(context, location);
return scope;
}
/**
* Build a DiscoverQuery object using the parameter in the request
*
* @param request
* @return
* @throws SearchServiceException
*/
public static DiscoverQuery getDiscoverQuery(Context context,
HttpServletRequest request, DSpaceObject scope, boolean enableFacet)
{
DiscoverQuery queryArgs = new DiscoverQuery();
DiscoveryConfiguration discoveryConfiguration = SearchUtils
.getDiscoveryConfiguration(scope);
List<String> userFilters = setupBasicQuery(context,
discoveryConfiguration, request, queryArgs);
setPagination(request, queryArgs, discoveryConfiguration);
if (enableFacet
&& !"submit_export_metadata".equals(UIUtil.getSubmitButton(
request, "submit")))
{
setFacet(context, request, scope, queryArgs,
discoveryConfiguration, userFilters);
}
return queryArgs;
}
/**
* Build the DiscoverQuery object for an autocomplete search using
* parameters in the request
*
* @param context
* @param request
* @param scope
* @return
*/
public static DiscoverQuery getDiscoverAutocomplete(Context context,
HttpServletRequest request, DSpaceObject scope)
{
DiscoverQuery queryArgs = new DiscoverQuery();
DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration();
setupBasicQuery(context, discoveryConfiguration, request, queryArgs);
String autoIndex = request.getParameter("auto_idx");
String autoQuery = request.getParameter("auto_query");
String sort = request.getParameter("auto_sort");
String autoType = request.getParameter("auto_type");
if ("contains".equals(autoType) || "notcontains".equals(autoType))
{
autoType = DiscoveryConfigurationParameters.TYPE_STANDARD;
}
else if ("authority".equals(autoType) || "notauthority".equals(autoType))
{
autoType = DiscoveryConfigurationParameters.TYPE_AUTHORITY;
}
else
{
autoType = DiscoveryConfigurationParameters.TYPE_AC;
}
DiscoveryConfigurationParameters.SORT sortBy = DiscoveryConfigurationParameters.SORT.VALUE;
if (StringUtils.isNotBlank(sort))
{
if ("count".equalsIgnoreCase(sort))
{
sortBy = DiscoveryConfigurationParameters.SORT.COUNT;
}
else
{
sortBy = DiscoveryConfigurationParameters.SORT.VALUE;
}
}
// no user choices... default for autocomplete should be alphabetic
// sorting in all cases except empty query where count is preferable
else if ("".equals(autoQuery))
{
sortBy = DiscoveryConfigurationParameters.SORT.COUNT;
}
if (autoIndex == null)
{
autoIndex = "all";
}
if (autoQuery == null)
{
autoQuery = "";
}
int limit = UIUtil.getIntParameter(request, "autocomplete.limit");
if (limit == -1)
{
limit = 10;
}
DiscoverFacetField autocompleteField = new DiscoverFacetField(autoIndex,
autoType,
limit, sortBy, autoQuery.toLowerCase());
queryArgs.addFacetField(autocompleteField);
queryArgs.setMaxResults(0);
queryArgs.setFacetMinCount(1);
return queryArgs;
}
// /**
// * Build the query from the advanced search form
// *
// * @param request
// * @return
// */
// public static String buildQuery(HttpServletRequest request)
// {
// int num_field = UIUtil.getIntParameter(request, "num_search_field");
// if (num_field <= 0)
// {
// num_field = 3;
// }
// StringBuffer query = new StringBuffer();
// buildQueryPart(query, request.getParameter("field"),
// request.getParameter("query"), null);
// for (int i = 1; i < num_field; i++)
// {
// buildQueryPart(query, request.getParameter("field" + i),
// request.getParameter("query" + i),
// request.getParameter("conjuction" + i));
// }
// return query.toString();
// }
//
// private static void buildQueryPart(StringBuffer currQuery, String field,
// String queryPart, String conjuction)
// {
// if (StringUtils.isBlank(queryPart))
// {
// return;
// }
// else
// {
// StringBuffer tmp = new StringBuffer(queryPart);
// if (StringUtils.isNotBlank(field))
// {
// tmp.insert(0, field + ":(").append(")");
// }
//
// if (StringUtils.isNotBlank(conjuction) && currQuery.length() > 0)
// {
// currQuery.append(conjuction);
// }
// currQuery.append(tmp);
// }
// }
/**
* Return a QueryResults object as needed by the OpenSearch classes
*
* @param qResults
* @return
*/
public static QueryResults toQueryResults(DiscoverResult qResults)
{
QueryResults qR = new QueryResults();
qR.setHitCount((int) qResults.getTotalSearchResults());
qR.setPageSize(qResults.getMaxResults());
qR.setStart(qResults.getStart());
List<String> handles = new ArrayList<String>();
List<Integer> types = new ArrayList<Integer>();
List<Integer> ids = new ArrayList<Integer>();
for (DSpaceObject dso : qResults.getDspaceObjects())
{
handles.add(dso.getHandle());
ids.add(dso.getID());
types.add(dso.getType());
}
qR.setHitIds(ids);
qR.setHitTypes(types);
qR.setHitHandles(handles);
return qR;
}
/**
* Setup the basic query argumnets: the main query and all the filters
* (default + user). Return the list of user filter
*
* @param context
* @param request
* @param queryArgs
* the query object to populate
* @return the list of user filer (as filter query)
*/
private static List<String> setupBasicQuery(Context context,
DiscoveryConfiguration discoveryConfiguration,
HttpServletRequest request, DiscoverQuery queryArgs)
{
// Get the query
String query = request.getParameter("query");
if (StringUtils.isNotBlank(query))
{
queryArgs.setQuery(query);
}
List<String> defaultFilterQueries = discoveryConfiguration
.getDefaultFilterQueries();
if (defaultFilterQueries != null)
{
for (String f : defaultFilterQueries)
{
queryArgs.addFacetQuery(f);
}
}
List<String[]> filters = getFilters(request);
List<String> userFilters = new ArrayList<String>();
for (String[] f : filters)
{
try
{
String newFilterQuery = SearchUtils.getSearchService()
.toFilterQuery(context, f[0], f[1], f[2])
.getFilterQuery();
if (newFilterQuery != null)
{
queryArgs.addFilterQueries(newFilterQuery);
userFilters.add(newFilterQuery);
}
}
catch (SQLException e)
{
log.error(LogManager.getHeader(context,
"Error in discovery while setting up user facet query",
"filter_field: " + f[0] + ",filter_type:"
+ f[1] + ",filer_value:"
+ f[2]), e);
}
}
return userFilters;
}
private static void setPagination(HttpServletRequest request,
DiscoverQuery queryArgs,
DiscoveryConfiguration discoveryConfiguration)
{
int start = UIUtil.getIntParameter(request, "start");
// can't start earlier than 0 in the results!
if (start < 0)
{
start = 0;
}
String sortBy = request.getParameter("sort_by");
String sortOrder = request.getParameter("order");
DiscoverySortConfiguration searchSortConfiguration = discoveryConfiguration
.getSearchSortConfiguration();
if (sortBy == null)
{
// Attempt to find the default one, if none found we use SCORE
sortBy = "score";
if (searchSortConfiguration != null)
{
for (DiscoverySortFieldConfiguration sortFieldConfiguration : searchSortConfiguration
.getSortFields())
{
if (sortFieldConfiguration.equals(searchSortConfiguration
.getDefaultSort()))
{
sortBy = SearchUtils
.getSearchService()
.toSortFieldIndex(
sortFieldConfiguration
.getMetadataField(),
sortFieldConfiguration.getType());
}
}
}
}
if (sortOrder == null && searchSortConfiguration != null)
{
sortOrder = searchSortConfiguration.getDefaultSortOrder()
.toString();
}
if (sortBy != null)
{
if ("asc".equalsIgnoreCase(sortOrder))
{
queryArgs.setSortField(sortBy, SORT_ORDER.asc);
}
else
{
queryArgs.setSortField(sortBy, SORT_ORDER.desc);
}
}
int rpp = UIUtil.getIntParameter(request, "rpp");
// Override the page setting if exporting metadata
if ("submit_export_metadata".equals(UIUtil.getSubmitButton(request,
"submit")))
{
queryArgs.setStart(0);
queryArgs.setMaxResults(Integer.MAX_VALUE);
// search only for items other objects are not exported
queryArgs.addFilterQueries("search.resourcetype:2");
}
else
{
// String groupBy = request.getParameter("group_by");
//
// // Enable groupBy collapsing if designated
// if (groupBy != null && !groupBy.equalsIgnoreCase("none")) {
// /** Construct a Collapse Field Query */
// queryArgs.addProperty("collapse.field", groupBy);
// queryArgs.addProperty("collapse.threshold", "1");
// queryArgs.addProperty("collapse.includeCollapsedDocs.fl",
// "handle");
// queryArgs.addProperty("collapse.facet", "before");
//
// //queryArgs.a type:Article^2
//
// // TODO: This is a hack to get Publications (Articles) to always
// be at the top of Groups.
// // TODO: I think the can be more transparently done in the solr
// solrconfig.xml with DISMAX and boosting
// /** sort in groups to get publications to top */
// queryArgs.setSortField("dc.type", DiscoverQuery.SORT_ORDER.asc);
//
// }
if (rpp > 0)
{
queryArgs.setMaxResults(rpp);
}
else
{
queryArgs.setMaxResults(discoveryConfiguration.getDefaultRpp());
}
queryArgs.setStart(start);
}
}
private static void setFacet(Context context, HttpServletRequest request,
DSpaceObject scope, DiscoverQuery queryArgs,
DiscoveryConfiguration discoveryConfiguration,
List<String> userFilters)
{
List<DiscoverySearchFilterFacet> facets = discoveryConfiguration
.getSidebarFacets();
log.info("facets for scope, " + scope + ": "
+ (facets != null ? facets.size() : null));
if (facets != null)
{
queryArgs.setFacetMinCount(1);
}
/** enable faceting of search results */
if (facets != null)
{
queryArgs.setFacetMinCount(1);
for (DiscoverySearchFilterFacet facet : facets)
{
if (facet.getType().equals(
DiscoveryConfigurationParameters.TYPE_DATE))
{
String dateFacet = facet.getIndexFieldName() + ".year";
List<String> filterQueriesList = queryArgs
.getFilterQueries();
String[] filterQueries = new String[0];
if (filterQueriesList != null)
{
filterQueries = new String[filterQueries.length];
filterQueries = filterQueriesList
.toArray(filterQueries);
}
try
{
// Get a range query so we can create facet
// queries
// ranging from out first to our last date
// Attempt to determine our oldest & newest year
// by
// checking for previously selected filters
int oldestYear = -1;
int newestYear = -1;
for (String filterQuery : filterQueries)
{
if (filterQuery.startsWith(dateFacet + ":"))
{
// Check for a range
Pattern pattern = Pattern
.compile("\\[(.*? TO .*?)\\]");
Matcher matcher = pattern.matcher(filterQuery);
boolean hasPattern = matcher.find();
if (hasPattern)
{
filterQuery = matcher.group(0);
// We have a range
// Resolve our range to a first &
// endyear
int tempOldYear = Integer
.parseInt(filterQuery.split(" TO ")[0]
.replace("[", "").trim());
int tempNewYear = Integer
.parseInt(filterQuery.split(" TO ")[1]
.replace("]", "").trim());
// Check if we have a further filter
// (or
// a first one found)
if (tempNewYear < newestYear
|| oldestYear < tempOldYear
|| newestYear == -1)
{
oldestYear = tempOldYear;
newestYear = tempNewYear;
}
}
else
{
if (filterQuery.indexOf(" OR ") != -1)
{
// Should always be the case
filterQuery = filterQuery.split(" OR ")[0];
}
// We should have a single date
oldestYear = Integer.parseInt(filterQuery
.split(":")[1].trim());
newestYear = oldestYear;
// No need to look further
break;
}
}
}
// Check if we have found a range, if not then
// retrieve our first & last year by using solr
if (oldestYear == -1 && newestYear == -1)
{
DiscoverQuery yearRangeQuery = new DiscoverQuery();
yearRangeQuery.setFacetMinCount(1);
yearRangeQuery.setMaxResults(1);
// Set our query to anything that has this
// value
yearRangeQuery.addFieldPresentQueries(dateFacet);
// Set sorting so our last value will appear
// on
// top
yearRangeQuery.setSortField(dateFacet + "_sort",
DiscoverQuery.SORT_ORDER.asc);
yearRangeQuery.addFilterQueries(filterQueries);
yearRangeQuery.addSearchField(dateFacet);
DiscoverResult lastYearResult = SearchUtils
.getSearchService().search(context, scope,
yearRangeQuery);
if (0 < lastYearResult.getDspaceObjects().size())
{
java.util.List<DiscoverResult.SearchDocument> searchDocuments = lastYearResult
.getSearchDocument(lastYearResult
.getDspaceObjects().get(0));
if (0 < searchDocuments.size()
&& 0 < searchDocuments
.get(0)
.getSearchFieldValues(dateFacet)
.size())
{
oldestYear = Integer
.parseInt(searchDocuments
.get(0)
.getSearchFieldValues(
dateFacet).get(0));
}
}
// Now get the first year
yearRangeQuery.setSortField(dateFacet + "_sort",
DiscoverQuery.SORT_ORDER.desc);
DiscoverResult firstYearResult = SearchUtils
.getSearchService().search(context, scope,
yearRangeQuery);
if (0 < firstYearResult.getDspaceObjects().size())
{
java.util.List<DiscoverResult.SearchDocument> searchDocuments = firstYearResult
.getSearchDocument(firstYearResult
.getDspaceObjects().get(0));
if (0 < searchDocuments.size()
&& 0 < searchDocuments
.get(0)
.getSearchFieldValues(dateFacet)
.size())
{
newestYear = Integer
.parseInt(searchDocuments
.get(0)
.getSearchFieldValues(
dateFacet).get(0));
}
}
// No values found!
if (newestYear == -1 || oldestYear == -1)
{
continue;
}
}
int gap = 1;
// Attempt to retrieve our gap by the algorithm
// below
int yearDifference = newestYear - oldestYear;
if (yearDifference != 0)
{
while (10 < ((double) yearDifference / gap))
{
gap *= 10;
}
}
// We need to determine our top year so we can
// start
// our count from a clean year
// Example: 2001 and a gap from 10 we need the
// following result: 2010 - 2000 ; 2000 - 1990
// hence
// the top year
int topYear = (int) (Math.ceil((float) (newestYear)
/ gap) * gap);
if (gap == 1)
{
// We need a list of our years
// We have a date range add faceting for our
// field
// The faceting will automatically be
// limited to
// the 10 years in our span due to our
// filterquery
queryArgs.addFacetField(new DiscoverFacetField(
facet.getIndexFieldName(), facet.getType(),
10, facet.getSortOrder()));
}
else
{
java.util.List<String> facetQueries = new ArrayList<String>();
// Create facet queries but limit then to 11
// (11
// == when we need to show a show more url)
for (int year = topYear - gap; year > oldestYear
&& (facetQueries.size() < 11); year -= gap)
{
// Add a filter to remove the last year
// only
// if we aren't the last year
int bottomYear = year - gap;
// Make sure we don't go below our last
// year
// found
if (bottomYear < oldestYear)
{
bottomYear = oldestYear;
}
// Also make sure we don't go above our
// newest year
int currentTop = year;
if ((year == topYear))
{
currentTop = newestYear;
}
else
{
// We need to do -1 on this one to
// get a
// better result
currentTop--;
}
facetQueries.add(dateFacet + ":[" + bottomYear
+ " TO " + currentTop + "]");
}
for (String facetQuery : facetQueries)
{
queryArgs.addFacetQuery(facetQuery);
}
}
}
catch (Exception e)
{
log.error(
LogManager
.getHeader(
context,
"Error in discovery while setting up date facet range",
"date facet: " + dateFacet), e);
}
}
else
{
int facetLimit = facet.getFacetLimit();
int facetPage = UIUtil.getIntParameter(request,
facet.getIndexFieldName() + "_page");
if (facetPage < 0)
{
facetPage = 0;
}
// at most all the user filters belong to this facet
int alreadySelected = userFilters.size();
// Add one to our facet limit to make sure that if
// we
// have more then the shown facets that we show our
// show
// more url
// add the already selected facet so to have a full
// top list
// if possible
queryArgs.addFacetField(new DiscoverFacetField(facet
.getIndexFieldName(),
DiscoveryConfigurationParameters.TYPE_TEXT,
facetLimit + 1 + alreadySelected, facet
.getSortOrder(), facetPage * facetLimit));
}
}
}
}
public static List<String[]> getFilters(HttpServletRequest request)
{
String submit = UIUtil.getSubmitButton(request, "submit");
int ignore = -1;
if (submit.startsWith("submit_filter_remove_"))
{
ignore = Integer.parseInt(submit.substring("submit_filter_remove_".length()));
}
List<String[]> appliedFilters = new ArrayList<String[]>();
List<String> filterValue = new ArrayList<String>();
List<String> filterOp = new ArrayList<String>();
List<String> filterField = new ArrayList<String>();
for (int idx = 1; ; idx++)
{
String op = request.getParameter("filter_type_"+idx);
if (StringUtils.isBlank(op))
{
break;
}
else if (idx != ignore)
{
filterOp.add(op);
filterField.add(request.getParameter("filter_field_"+idx));
filterValue.add(request.getParameter("filter_value_"+idx));
}
}
String op = request.getParameter("filtertype");
if (StringUtils.isNotBlank(op))
{
filterOp.add(op);
filterField.add(request.getParameter("filtername"));
filterValue.add(request.getParameter("filterquery"));
}
for (int idx = 0; idx < filterOp.size(); idx++)
{
appliedFilters.add(new String[] { filterField.get(idx),
filterOp.get(idx), filterValue.get(idx) });
}
return appliedFilters;
}
// /**
// * Build the query from the advanced search form
// *
// * @param request
// * @return
// */
// public static String buildQuery(HttpServletRequest request)
// {
// int num_field = UIUtil.getIntParameter(request, "num_search_field");
// if (num_field <= 0)
// {
// num_field = 3;
// }
// StringBuffer query = new StringBuffer();
// buildQueryPart(query, request.getParameter("field"),
// request.getParameter("query"), null);
// for (int i = 1; i < num_field; i++)
// {
// buildQueryPart(query, request.getParameter("field" + i),
// request.getParameter("query" + i),
// request.getParameter("conjuction" + i));
// }
// return query.toString();
// }
//
// private static void buildQueryPart(StringBuffer currQuery, String field,
// String queryPart, String conjuction)
// {
// if (StringUtils.isBlank(queryPart))
// {
// return;
// }
// else
// {
// StringBuffer tmp = new StringBuffer(queryPart);
// if (StringUtils.isNotBlank(field))
// {
// tmp.insert(0, field + ":(").append(")");
// }
//
// if (StringUtils.isNotBlank(conjuction) && currQuery.length() > 0)
// {
// currQuery.append(conjuction);
// }
// currQuery.append(tmp);
// }
// }
}

View File

@@ -0,0 +1,75 @@
package org.dspace.app.webui.discovery;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.webui.json.JSONRequest;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.DiscoverResult.FacetResult;
import org.dspace.discovery.SearchUtils;
import flexjson.JSONSerializer;
public class DiscoveryJSONRequest extends JSONRequest
{
public void doJSONRequest(Context context, HttpServletRequest request,
HttpServletResponse resp) throws AuthorizeException, IOException
{
String reqPath = request.getPathInfo();
// remove the first slash if present
if (reqPath.startsWith("/"))
{
reqPath = reqPath.substring(1);
}
if (reqPath.equalsIgnoreCase(getSubPath() + "/autocomplete"))
{
doAutocomplete(context, request, resp);
return;
}
// unkwon action (in future we can implement ajax for pagination, etc.)
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
private void doAutocomplete(Context context, HttpServletRequest request,
HttpServletResponse resp)
{
try
{
DSpaceObject scope = DiscoverUtility.getSearchScope(context,
request);
DiscoverQuery autocompleteQuery = DiscoverUtility
.getDiscoverAutocomplete(context, request, scope);
DiscoverResult qResults = SearchUtils.getSearchService().search(
context, autocompleteQuery);
// extract the only facet present in the result response
Set<String> facets = qResults.getFacetResults().keySet();
List<FacetResult> fResults = new ArrayList<DiscoverResult.FacetResult>();
if (facets != null && facets.size() > 0)
{
String autocompleteField = (String) facets.toArray()[0];
fResults = qResults
.getFacetResult(autocompleteField);
}
JSONSerializer serializer = new JSONSerializer();
serializer.rootName("autocomplete");
serializer.exclude("class","asFilterQuery");
serializer.deepSerialize(fResults, resp.getWriter());
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,481 @@
package org.dspace.app.webui.discovery;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.app.bulkedit.MetadataExport;
import org.dspace.app.util.OpenSearch;
import org.dspace.app.util.SyndicationFeed;
import org.dspace.app.webui.search.SearchProcessorException;
import org.dspace.app.webui.search.SearchRequestProcessor;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.DiscoverFilterQuery;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoverySearchFilter;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
import org.dspace.discovery.configuration.SidebarFacetConfiguration;
import org.dspace.search.QueryResults;
import org.w3c.dom.Document;
public class DiscoverySearchRequestProcessor implements SearchRequestProcessor
{
private static String msgKey = "org.dspace.app.webui.servlet.FeedServlet";
/** log4j category */
private static Logger log = Logger.getLogger(DiscoverySearchRequestProcessor.class);
// locale-sensitive metadata labels
private Map<String, Map<String, String>> localeLabels = null;
public void init()
{
localeLabels = new HashMap<String, Map<String, String>>();
}
public void doOpenSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException
{
// dispense with simple service document requests
String scope = request.getParameter("scope");
if (scope != null && "".equals(scope))
{
scope = null;
}
String path = request.getPathInfo();
if (path != null && path.endsWith("description.xml"))
{
String svcDescrip = OpenSearch.getDescription(scope);
response.setContentType(OpenSearch
.getContentType("opensearchdescription"));
response.setContentLength(svcDescrip.length());
response.getWriter().write(svcDescrip);
return;
}
// get enough request parameters to decide on action to take
String format = request.getParameter("format");
if (format == null || "".equals(format))
{
// default to atom
format = "atom";
}
// do some sanity checking
if (!OpenSearch.getFormats().contains(format))
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// then the rest - we are processing the query
DSpaceObject container;
try
{
container = DiscoverUtility.getSearchScope(context,
request);
}
catch (Exception e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
DiscoverQuery queryArgs = DiscoverUtility.getDiscoverQuery(context,
request, container, false);
String query = queryArgs.getQuery();
// Perform the search
DiscoverResult qResults = null;
try
{
qResults = SearchUtils.getSearchService().search(context,
container, queryArgs);
}
catch (SearchServiceException e)
{
log.error(
LogManager.getHeader(context, "opensearch", "query="
+ queryArgs.getQuery() + ",scope=" + scope
+ ",error=" + e.getMessage()), e);
throw new RuntimeException(e.getMessage(), e);
}
// Log
log.info(LogManager.getHeader(context, "opensearch",
"scope=" + scope + ",query=\"" + query + "\",results=("
+ qResults.getTotalSearchResults() + ")"));
// format and return results
Map<String, String> labelMap = getLabels(request);
DSpaceObject[] dsoResults = new DSpaceObject[qResults
.getDspaceObjects().size()];
qResults.getDspaceObjects().toArray(dsoResults);
QueryResults qR = DiscoverUtility.toQueryResults(qResults);
Document resultsDoc = OpenSearch.getResultsDoc(format, query, qR,
container, dsoResults, labelMap);
try
{
Transformer xf = TransformerFactory.newInstance().newTransformer();
response.setContentType(OpenSearch.getContentType(format));
xf.transform(new DOMSource(resultsDoc),
new StreamResult(response.getWriter()));
}
catch (TransformerException e)
{
log.error(e);
throw new ServletException(e.toString());
}
}
private Map<String, String> getLabels(HttpServletRequest request)
{
// Get access to the localized resource bundle
Locale locale = request.getLocale();
Map<String, String> labelMap = localeLabels.get(locale.toString());
if (labelMap == null)
{
labelMap = getLocaleLabels(locale);
localeLabels.put(locale.toString(), labelMap);
}
return labelMap;
}
private Map<String, String> getLocaleLabels(Locale locale)
{
Map<String, String> labelMap = new HashMap<String, String>();
ResourceBundle labels = ResourceBundle.getBundle("Messages", locale);
labelMap.put(SyndicationFeed.MSG_UNTITLED,
labels.getString(msgKey + ".notitle"));
labelMap.put(SyndicationFeed.MSG_LOGO_TITLE,
labels.getString(msgKey + ".logo.title"));
labelMap.put(SyndicationFeed.MSG_FEED_DESCRIPTION,
labels.getString(msgKey + ".general-feed.description"));
labelMap.put(SyndicationFeed.MSG_UITYPE, SyndicationFeed.UITYPE_JSPUI);
for (String selector : SyndicationFeed.getDescriptionSelectors())
{
labelMap.put("metadata." + selector,
labels.getString(SyndicationFeed.MSG_METADATA + selector));
}
return labelMap;
}
public void doSimpleSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException
{
Item[] resultsItems;
Collection[] resultsCollections;
Community[] resultsCommunities;
DSpaceObject scope;
try
{
scope = DiscoverUtility.getSearchScope(context, request);
}
catch (IllegalStateException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
DiscoveryConfiguration discoveryConfiguration = SearchUtils
.getDiscoveryConfiguration(scope);
List<DiscoverySortFieldConfiguration> sortFields = discoveryConfiguration
.getSearchSortConfiguration().getSortFields();
List<String> sortOptions = new ArrayList<String>();
for (DiscoverySortFieldConfiguration sortFieldConfiguration : sortFields)
{
String sortField = SearchUtils.getSearchService().toSortFieldIndex(
sortFieldConfiguration.getMetadataField(),
sortFieldConfiguration.getType());
sortOptions.add(sortField);
}
request.setAttribute("sortOptions", sortOptions);
DiscoverQuery queryArgs = DiscoverUtility.getDiscoverQuery(context,
request, scope, true);
List<DiscoverySearchFilterFacet> availableFacet = discoveryConfiguration
.getSidebarFacets();
request.setAttribute("facetsConfig",
availableFacet != null ? availableFacet
: new ArrayList<DiscoverySearchFilterFacet>());
int etal = UIUtil.getIntParameter(request, "etal");
if (etal == -1)
{
etal = ConfigurationManager
.getIntProperty("webui.itemlist.author-limit");
}
request.setAttribute("etal", etal);
String query = queryArgs.getQuery();
request.setAttribute("query", query);
request.setAttribute("queryArgs", queryArgs);
List<DiscoverySearchFilter> availableFilters = discoveryConfiguration
.getSearchFilters();
request.setAttribute("availableFilters", availableFilters);
List<String[]> appliedFilters = DiscoverUtility.getFilters(request);
request.setAttribute("appliedFilters", appliedFilters);
List<String> appliedFilterQueries = new ArrayList<String>();
for (String[] filter : appliedFilters)
{
appliedFilterQueries.add(filter[0] + "::" + filter[1] + "::"
+ filter[2]);
}
request.setAttribute("appliedFilterQueries", appliedFilterQueries);
List<DSpaceObject> scopes = new ArrayList<DSpaceObject>();
if (scope == null)
{
Community[] topCommunities;
try
{
topCommunities = Community.findAllTop(context);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
for (Community com : topCommunities)
{
scopes.add(com);
}
}
else
{
try
{
DSpaceObject pDso = scope.getParentObject();
while (pDso != null)
{
// add to the available scopes in reverse order
scopes.add(0, pDso);
pDso = pDso.getParentObject();
}
scopes.add(scope);
if (scope instanceof Community)
{
Community[] comms = ((Community) scope).getSubcommunities();
for (Community com : comms)
{
scopes.add(com);
}
Collection[] colls = ((Community) scope).getCollections();
for (Collection col : colls)
{
scopes.add(col);
}
}
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
}
request.setAttribute("scope", scope);
request.setAttribute("scopes", scopes);
// Perform the search
DiscoverResult qResults = null;
try
{
qResults = SearchUtils.getSearchService().search(context, scope,
queryArgs);
List<Community> resultsListComm = new ArrayList<Community>();
List<Collection> resultsListColl = new ArrayList<Collection>();
List<Item> resultsListItem = new ArrayList<Item>();
for (DSpaceObject dso : qResults.getDspaceObjects())
{
if (dso instanceof Item)
{
resultsListItem.add((Item) dso);
}
else if (dso instanceof Collection)
{
resultsListColl.add((Collection) dso);
}
else if (dso instanceof Community)
{
resultsListComm.add((Community) dso);
}
}
// Make objects from the handles - make arrays, fill them out
resultsCommunities = new Community[resultsListComm.size()];
resultsCollections = new Collection[resultsListColl.size()];
resultsItems = new Item[resultsListItem.size()];
resultsCommunities = resultsListComm.toArray(resultsCommunities);
resultsCollections = resultsListColl.toArray(resultsCollections);
resultsItems = resultsListItem.toArray(resultsItems);
// Log
log.info(LogManager.getHeader(context, "search", "scope=" + scope
+ ",query=\"" + query + "\",results=("
+ resultsCommunities.length + ","
+ resultsCollections.length + "," + resultsItems.length
+ ")"));
// Pass in some page qualities
// total number of pages
long pageTotal = 1 + ((qResults.getTotalSearchResults() - 1) / qResults
.getMaxResults());
// current page being displayed
long pageCurrent = 1 + (qResults.getStart() / qResults
.getMaxResults());
// pageLast = min(pageCurrent+3,pageTotal)
long pageLast = ((pageCurrent + 3) > pageTotal) ? pageTotal
: (pageCurrent + 3);
// pageFirst = max(1,pageCurrent-3)
long pageFirst = ((pageCurrent - 3) > 1) ? (pageCurrent - 3) : 1;
// Pass the results to the display JSP
request.setAttribute("items", resultsItems);
request.setAttribute("communities", resultsCommunities);
request.setAttribute("collections", resultsCollections);
request.setAttribute("pagetotal", new Long(pageTotal));
request.setAttribute("pagecurrent", new Long(pageCurrent));
request.setAttribute("pagelast", new Long(pageLast));
request.setAttribute("pagefirst", new Long(pageFirst));
request.setAttribute("queryresults", qResults);
try
{
if (AuthorizeManager.isAdmin(context))
{
// Set a variable to create admin buttons
request.setAttribute("admin_button", new Boolean(true));
}
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e); }
if ("submit_export_metadata".equals(UIUtil.getSubmitButton(request,
"submit")))
{
exportMetadata(context, response, resultsItems);
}
}
catch (SearchServiceException e)
{
log.error(
LogManager.getHeader(context, "search", "query="
+ queryArgs.getQuery() + ",scope=" + scope
+ ",error=" + e.getMessage()), e);
request.setAttribute("search.error", true);
request.setAttribute("search.error.message", e.getMessage());
}
JSPManager.showJSP(request, response, "/search/discovery.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;
}
/**
* Method for constructing the discovery advanced search form
*
* @author Andrea Bollini
*/
@Override
public void doAdvancedSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException
{
// just redirect to the simple search servlet.
// The advanced form is always displayed with Discovery togheter with
// the search result
// the first access to the advanced form performs a search for
// "anythings" (SOLR *:*)
response.sendRedirect(request.getContextPath() + "/simple-search");
}
}

View File

@@ -0,0 +1,90 @@
package org.dspace.app.webui.discovery;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.plugin.CollectionHomeProcessor;
import org.dspace.plugin.CommunityHomeProcessor;
import org.dspace.plugin.PluginException;
import org.dspace.plugin.SiteHomeProcessor;
public class SideBarFacetProcessor implements CollectionHomeProcessor,
CommunityHomeProcessor, SiteHomeProcessor
{
/** log4j category */
private static Logger log = Logger.getLogger(SideBarFacetProcessor.class);
@Override
public void process(Context context, HttpServletRequest request,
HttpServletResponse response, Community community)
throws PluginException, AuthorizeException
{
process(context, request, response, (DSpaceObject) community);
}
@Override
public void process(Context context, HttpServletRequest request,
HttpServletResponse response, Collection collection)
throws PluginException, AuthorizeException
{
process(context, request, response, (DSpaceObject) collection);
}
@Override
public void process(Context context, HttpServletRequest request,
HttpServletResponse response) throws PluginException,
AuthorizeException
{
process(context, request, response, (DSpaceObject) null);
}
private void process(Context context, HttpServletRequest request,
HttpServletResponse response, DSpaceObject scope)
{
DiscoverQuery queryArgs = DiscoverUtility.getDiscoverQuery(context,
request, scope, true);
queryArgs.setMaxResults(0);
DiscoverResult qResults;
try
{
qResults = SearchUtils.getSearchService().search(context, scope,
queryArgs);
request.setAttribute("discovery.fresults",
qResults.getFacetResults());
DiscoveryConfiguration discoveryConfiguration = SearchUtils
.getDiscoveryConfiguration(scope);
List<DiscoverySearchFilterFacet> availableFacet = discoveryConfiguration
.getSidebarFacets();
request.setAttribute("facetsConfig",
availableFacet != null ? availableFacet
: new ArrayList<DiscoverySearchFilterFacet>());
if (scope !=null)
{
request.setAttribute("discovery.searchScope",
"/handle/" + scope.getHandle());
}
}
catch (SearchServiceException e)
{
log.error(LogManager.getHeader(context,
"discovery-process-sidebar", "scope=" + scope));
}
}
}

View File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<artifactId>dspace-discovery-jspui-webapp</artifactId>
<name>DSpace Discovery :: Discovery JSPUI Webapp</name>
<parent>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery</artifactId>
<version>3.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-jspui-api</artifactId>
<exclusions>
<exclusion>
<artifactId>solr-solrj</artifactId>
<groupId>org.apache.solr</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery-jspui-api</artifactId>
<version>3.0-SNAPSHOT</version>
</dependency>
<!-- external -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archiveClasses>false</archiveClasses>
<attachClasses>true</attachClasses>
<classesClassifier>classes</classesClassifier>
<failOnMissingWebXml>false</failOnMissingWebXml>
<packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
<warSourceExcludes>WEB-INF/lib/*.jar</warSourceExcludes>
<webResources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/webapp</directory>
<includes>
<include>WEB-INF/web.xml</include>
</includes>
</resource>
</webResources>
</configuration>
<executions>
<execution>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mycila.maven-license-plugin</groupId>
<artifactId>maven-license-plugin</artifactId>
<configuration>
<!--Exclude license check for Discovery files which don't need it-->
<excludes>
<exclude>**/*.LICENSE</exclude>
<exclude>**/jquery*</exclude>
</excludes>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<index>true</index>
<manifestEntries>
<Cocoon-Block-Name>discovery-xmlui-block</Cocoon-Block-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
-->
</plugins>
</build>
</project>

View File

@@ -0,0 +1,27 @@
h3.facets {margin-left:0px;}
div.facetsBox {margin:2px;min-width: 180px;width: 180px;}
div.facetsBox ul {list-style: none; list-style-position: inside; padding:0px;}
div.facet {margin-left:0px;margin-right:0px;border: 1px solid #CCCCCC; padding: 5px;}
li.facet-next, li.facet-previous {margin-bottom:10px; margin-top:10px;font-weight: bold;}
li.facet-next {text-align: right;}
.facetName {font-weight: bold;}
div.discovery-query {border: 1px solid #CCCCCC;background-color: #EEEEEE;padding:10px;white-space: nowrap;}
div.discovery-query a {font-size: smaller;display: block;margin:2px;margin-left:5px;}
div.discovery-search-appliedFilters {margin-top: 10px; background-color: #FFFFFF; border: 1px solid #CCCCCC;padding:10px;}
div.discovery-search-appliedFilters span {font-weight: bold;display:block;margin-bottom:5px;}
div.discovery-query label {font-weight: bold;margin:5px;}
div.discovery-query select {margin-bottom:5px;}
div.discovery-search-filters{border: 1px solid #CCCCCC;padding:10px;}
div.discovery-search-filters span {display:block;margin:5px;}
div.discovery-search-filters span.discovery-search-filters-heading {font-weight: bold};
div.discovery-search-filters select {margin:5px;}
div.discovery-pagination-controls {margin-top: 10px; background-color: #EEEEEE; border: 1px solid #CCCCCC;padding:10px;}
.clearfix:after {clear: both;content: ".";display: block;height: 0;visibility: hidden;}
.pagination-masked.top {margin-top: 5px;}
div.discovery-result-pagination {margin: 20px;margin-bottom:0px;line-height: 1em;padding: 10px;vertical-align: middle;}
div.discovery-result-pagination h2.info, div.discovery-result-pagination p.info {float: left;margin:0px;}
div.discovery-result-pagination ul.links {float: right;margin:0px;list-style: none outside none;}
div.discovery-result-pagination ul.links li {display: inline; padding-left: 2px; padding-right: 2px;}
.current-page-link {color: #CCCCCC;font-weight: bold;}
div.discovery-result-results {padding:10px;}

View File

@@ -0,0 +1,123 @@
<%--
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/
--%>
<%--
- fragment JSP to be included in site, community or collection home to show discovery facets
-
- Attributes required:
- discovery.fresults - the facets result to show
- discovery.facetsConf - the facets configuration
- discovery.searchScope - the search scope
--%>
<%@page import="org.dspace.discovery.configuration.DiscoverySearchFilterFacet"%>
<%@ page import="java.util.HashMap"%>
<%@ page import="java.util.Set"%>
<%@ page import="java.util.Map"%>
<%@ page import="org.dspace.discovery.DiscoverResult.FacetResult"%>
<%@ page import="java.util.List"%>
<%@ page import="java.net.URLEncoder"%>
<%@ page import="org.apache.commons.lang.StringUtils"%>
<%
boolean brefine = false;
Map<String, List<FacetResult>> mapFacetes = (Map<String, List<FacetResult>>) request.getAttribute("discovery.fresults");
List<DiscoverySearchFilterFacet> facetsConf = (List<DiscoverySearchFilterFacet>) request.getAttribute("facetsConfig");
String searchScope = (String) request.getAttribute("discovery.searchScope");
if (searchScope == null)
{
searchScope = "";
}
if (mapFacetes != null)
{
for (DiscoverySearchFilterFacet facetConf : facetsConf)
{
String f = facetConf.getIndexFieldName();
List<FacetResult> facet = mapFacetes.get(f);
if (facet != null && facet.size() > 0)
{
brefine = true;
break;
}
else
{
facet = mapFacetes.get(f+".year");
if (facet != null && facet.size() > 0)
{
brefine = true;
break;
}
}
}
}
if (brefine) {
%>
<h3 class="facets"><fmt:message key="jsp.search.facet.refine" /></h3>
<div id="facets" class="facetsBox">
<%
for (DiscoverySearchFilterFacet facetConf : facetsConf)
{
String f = facetConf.getIndexFieldName();
List<FacetResult> facet = mapFacetes.get(f);
if (facet == null)
{
facet = mapFacetes.get(f+".year");
}
if (facet == null)
{
continue;
}
String fkey = "jsp.search.facet.refine."+f;
int limit = facetConf.getFacetLimit()+1;
%><div id="facet_<%= f %>" class="facet">
<span class="facetName"><fmt:message key="<%= fkey %>" /></span>
<ul><%
int idx = 1;
int currFp = UIUtil.getIntParameter(request, f+"_page");
if (currFp < 0)
{
currFp = 0;
}
if (currFp > 0)
{
%><li class="facet-previous"><a href="<%= request.getContextPath()
+ searchScope
+ "?"+f+"_page="+(currFp-1) %>"><fmt:message key="jsp.search.facet.refine.previous" /></a></li>
<%
}
if (facet != null)
{
for (FacetResult fvalue : facet)
{
if (idx == limit)
{
%><li class="facet-next"><a href="<%= request.getContextPath()
+ searchScope
+ "?"+f+"_page="+(currFp+1) %>"><fmt:message key="jsp.search.facet.refine.next" /></a></li>
<%
}
else
{
%><li><a href="<%= request.getContextPath()
+ searchScope
+ "/simple-search?filterquery="+URLEncoder.encode(fvalue.getAsFilterQuery(),"UTF-8")
+ "&amp;filtername="+URLEncoder.encode(f,"UTF-8")
+ "&amp;filtertype="+URLEncoder.encode(fvalue.getFilterType(),"UTF-8") %>"
title="<fmt:message key="jsp.search.facet.narrow"><fmt:param><%=fvalue.getDisplayedValue() %></fmt:param></fmt:message>">
<%= StringUtils.abbreviate(fvalue.getDisplayedValue(),32) + " (" + fvalue.getCount()+")" %></a></li><%
}
idx++;
}
}
%></ul></div><%
}
}
%>

View File

@@ -0,0 +1,715 @@
<%--
The contents of this file are subject to the license and copyright
detailed in the LICENSE and NOTICE files at the root of the source
tree and available online at
http://www.dspace.org/license/
--%>
<%--
- Display the form to refine the simple-search and dispaly the results of the search
-
- Attributes to pass in:
-
- scope - pass in if the scope of the search was a community
- or a collection
- scopes - the list of available scopes where limit the search
- sortOptions - the list of available sort options
- availableFilters - the list of filters available to the user
-
- query - The original query
- queryArgs - The query configuration parameters (rpp, sort, etc.)
- appliedFilters - The list of applied filters (user input or facet)
-
- search.error - a flag to say that an error has occurred
- qResults - the discovery results
- items - the results. An array of Items, most relevant first
- communities - results, Community[]
- collections - results, Collection[]
-
- admin_button - If the user is an admin
--%>
<%@page import="org.dspace.discovery.configuration.DiscoverySearchFilterFacet"%>
<%@page import="org.dspace.app.webui.util.UIUtil"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.ArrayList"%>
<%@page import="org.dspace.discovery.DiscoverFacetField"%>
<%@page import="org.dspace.discovery.configuration.DiscoverySearchFilter"%>
<%@page import="org.dspace.discovery.DiscoverFilterQuery"%>
<%@page import="org.dspace.discovery.DiscoverQuery"%>
<%@page import="org.apache.commons.lang.StringUtils"%>
<%@page import="java.util.Map"%>
<%@page import="org.dspace.discovery.DiscoverResult.FacetResult"%>
<%@page import="org.dspace.discovery.DiscoverResult"%>
<%@page import="org.dspace.content.DSpaceObject"%>
<%@page import="java.util.List"%>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"
prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"
prefix="c" %>
<%@ taglib uri="http://www.dspace.org/dspace-tags.tld" prefix="dspace" %>
<%@ page import="org.apache.commons.lang.StringEscapeUtils" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page import="org.dspace.content.Community" %>
<%@ page import="org.dspace.content.Collection" %>
<%@ page import="org.dspace.content.Item" %>
<%@ page import="org.dspace.search.QueryResults" %>
<%@ page import="org.dspace.sort.SortOption" %>
<%@ page import="java.util.Enumeration" %>
<%@ page import="java.util.Set" %>
<%
// Get the attributes
DSpaceObject scope = (DSpaceObject) request.getAttribute("scope" );
String searchScope = scope!=null?scope.getHandle():"";
List<DSpaceObject> scopes = (List<DSpaceObject>) request.getAttribute("scopes");
List<String> sortOptions = (List<String>) request.getAttribute("sortOptions");
String query = (String) request.getAttribute("query");
if (query == null)
{
query = "";
}
Boolean error_b = (Boolean)request.getAttribute("search.error");
boolean error = (error_b == null ? false : error_b.booleanValue());
DiscoverQuery qArgs = (DiscoverQuery) request.getAttribute("queryArgs");
String sortedBy = qArgs.getSortField();
String order = qArgs.getSortOrder().toString();
String ascSelected = (SortOption.ASCENDING.equalsIgnoreCase(order) ? "selected=\"selected\"" : "");
String descSelected = (SortOption.DESCENDING.equalsIgnoreCase(order) ? "selected=\"selected\"" : "");
String httpFilters ="";
List<DiscoverySearchFilter> availableFilters = (List<DiscoverySearchFilter>) request.getAttribute("availableFilters");
List<String[]> appliedFilters = (List<String[]>) request.getAttribute("appliedFilters");
List<String> appliedFilterQueries = (List<String>) request.getAttribute("appliedFilterQueries");
if (appliedFilters != null && appliedFilters.size() >0 )
{
int idx = 1;
for (String[] filter : appliedFilters)
{
httpFilters += "&amp;filter_field_"+idx+"="+URLEncoder.encode(filter[0],"UTF-8");
httpFilters += "&amp;filter_type_"+idx+"="+URLEncoder.encode(filter[1],"UTF-8");
httpFilters += "&amp;filter_value_"+idx+"="+URLEncoder.encode(filter[2],"UTF-8");
idx++;
}
}
int rpp = qArgs.getMaxResults();
int etAl = ((Integer) request.getAttribute("etal")).intValue();
String[] options = new String[]{"equals","contains","authority","notequals","notcontains","notauthority"};
// Admin user or not
Boolean admin_b = (Boolean)request.getAttribute("admin_button");
boolean admin_button = (admin_b == null ? false : admin_b.booleanValue());
%>
<c:set var="dspace.layout.head" scope="request">
<script type="text/javascript">
var jQ = jQuery.noConflict();
jQ(document).ready(function() {
jQ( "#filterquery" )
.autocomplete({
source: function( request, response ) {
jQ.ajax({
url: "<%= request.getContextPath() %>/json/discovery/autocomplete?query=<%= URLEncoder.encode(query,"UTF-8")%><%= httpFilters.replaceAll("&amp;","&") %>",
dataType: "json",
cache: false,
data: {
auto_idx: jQ("#filtername").val(),
auto_query: request.term,
auto_sort: 'count',
auto_type: jQ("#filtertype").val(),
location: '<%= searchScope %>'
},
success: function( data ) {
response( jQ.map( data.autocomplete, function( item ) {
var tmp_val = item.authorityKey;
if (tmp_val == null || tmp_val == '')
{
tmp_val = item.displayedValue;
}
return {
label: item.displayedValue + " (" + item.count + ")",
value: tmp_val
};
}))
}
})
}
});
});
</script>
</c:set>
<dspace:layout titlekey="jsp.search.title">
<%-- <h1>Search Results</h1> --%>
<h1><fmt:message key="jsp.search.title"/></h1>
<div class="discovery-search-form">
<%-- Controls for a repeat search --%>
<div class="discovery-query">
<form action="simple-search" method="get">
<label for="tlocation">
<fmt:message key="jsp.search.results.searchin"/>
</label>
<select name="location" id="tlocation">
<%
if (scope == null)
{
// Scope of the search was all of DSpace. The scope control will list
// "all of DSpace" and the communities.
%>
<%-- <option selected value="/">All of DSpace</option> --%>
<option selected="selected" value="/"><fmt:message key="jsp.general.genericScope"/></option>
<% }
else
{
%>
<option value="/"><fmt:message key="jsp.general.genericScope"/></option>
<% }
for (DSpaceObject dso : scopes)
{
%>
<option value="<%= dso.getHandle() %>" <%=dso.getHandle().equals(searchScope)?"selected=\"selected\"":"" %>>
<%= dso.getName() %></option>
<%
}
%> </select><br/>
<label for="query"><fmt:message key="jsp.search.results.searchfor"/></label>
<input type="text" size="50" name="query" value="<%= (query==null ? "" : StringEscapeUtils.escapeHtml(query)) %>"/>
<input type="submit" value="<fmt:message key="jsp.general.go"/>" />
<input type="hidden" value="<%= rpp %>" name="rpp" />
<input type="hidden" value="<%= sortedBy %>" name="sort_by" />
<input type="hidden" value="<%= order %>" name="order" />
<% if (appliedFilters.size() > 0 ) { %>
<div class="discovery-search-appliedFilters">
<span><fmt:message key="jsp.search.filter.applied" /></span>
<%
int idx = 1;
for (String[] filter : appliedFilters)
{
boolean found = false;
%>
<select id="filter_field_<%=idx %>" name="filter_field_<%=idx %>">
<%
for (DiscoverySearchFilter searchFilter : availableFilters)
{
String fkey = "jsp.search.filter."+searchFilter.getIndexFieldName();
%><option value="<%= searchFilter.getIndexFieldName() %>"<%
if (filter[0].equals(searchFilter.getIndexFieldName()))
{
%> selected="selected"<%
found = true;
}
%>><fmt:message key="<%= fkey %>"/></option><%
}
if (!found)
{
String fkey = "jsp.search.filter."+filter[0];
%><option value="<%= filter[0] %>" selected="selected"><fmt:message key="<%= fkey %>"/></option><%
}
%>
</select>
<select id="filter_type_<%=idx %>" name="filter_type_<%=idx %>">
<%
for (String opt : options)
{
String fkey = "jsp.search.filter.op."+opt;
%><option value="<%= opt %>"<%= opt.equals(filter[1])?" selected=\"selected\"":"" %>><fmt:message key="<%= fkey %>"/></option><%
}
%>
</select>
<input type="text" id="filter_value_<%=idx %>" name="filter_value_<%=idx %>" value="<%= StringEscapeUtils.escapeHtml(filter[2]) %>" size="45"/>
<input type="submit" id="submit_filter_remove_<%=idx %>" name="submit_filter_remove_<%=idx %>" value="X" />
<br/>
<%
idx++;
}
%>
</div>
<% } %>
<a href="<%= request.getContextPath()+"/simple-search" %>"><fmt:message key="jsp.search.general.new-search" /></a>
</form>
</div>
<% if (availableFilters.size() > 0) { %>
<div class="discovery-search-filters">
<form action="simple-search" method="get">
<input type="hidden" value="<%= StringEscapeUtils.escapeHtml(searchScope) %>" name="location" />
<input type="hidden" value="<%= StringEscapeUtils.escapeHtml(query) %>" name="query" />
<% if (appliedFilterQueries.size() > 0 ) {
int idx = 1;
for (String[] filter : appliedFilters)
{
boolean found = false;
%>
<input type="hidden" id="filter_field_<%=idx %>" name="filter_field_<%=idx %>" value="<%= filter[0] %>" />
<input type="hidden" id="filter_type_<%=idx %>" name="filter_type_<%=idx %>" value="<%= filter[1] %>" />
<input type="hidden" id="filter_value_<%=idx %>" name="filter_value_<%=idx %>" value="<%= StringEscapeUtils.escapeHtml(filter[2]) %>" />
<%
idx++;
}
} %>
<span class="discovery-search-filters-heading"><fmt:message key="jsp.search.filter.heading" /></span>
<span class="discovery-search-filters-hint"><fmt:message key="jsp.search.filter.hint" /></span>
<select id="filtername" name="filtername">
<%
for (DiscoverySearchFilter searchFilter : availableFilters)
{
String fkey = "jsp.search.filter."+searchFilter.getIndexFieldName();
%><option value="<%= searchFilter.getIndexFieldName() %>"><fmt:message key="<%= fkey %>"/></option><%
}
%>
</select>
<select id="filtertype" name="filtertype">
<%
for (String opt : options)
{
String fkey = "jsp.search.filter.op."+opt;
%><option value="<%= opt %>"><fmt:message key="<%= fkey %>"/></option><%
}
%>
</select>
<input type="text" id="filterquery" name="filterquery" size="45"/>
<input type="hidden" value="<%= rpp %>" name="rpp" />
<input type="hidden" value="<%= sortedBy %>" name="sort_by" />
<input type="hidden" value="<%= order %>" name="order" />
<input type="submit" value="<fmt:message key="jsp.search.filter.add"/>" />
</form>
</div>
<% } %>
<%-- Include a component for modifying sort by, order, results per page, and et-al limit --%>
<div class="discovery-pagination-controls">
<form action="simple-search" method="get">
<input type="hidden" value="<%= StringEscapeUtils.escapeHtml(searchScope) %>" name="location" />
<input type="hidden" value="<%= StringEscapeUtils.escapeHtml(query) %>" name="query" />
<% if (appliedFilterQueries.size() > 0 ) {
int idx = 1;
for (String[] filter : appliedFilters)
{
boolean found = false;
%>
<input type="hidden" id="filter_field_<%=idx %>" name="filter_field_<%=idx %>" value="<%= filter[0] %>" />
<input type="hidden" id="filter_type_<%=idx %>" name="filter_type_<%=idx %>" value="<%= filter[1] %>" />
<input type="hidden" id="filter_value_<%=idx %>" name="filter_value_<%=idx %>" value="<%= StringEscapeUtils.escapeHtml(filter[2]) %>" />
<%
idx++;
}
} %>
<label for="rpp"><fmt:message key="search.results.perpage"/></label>
<select name="rpp">
<%
for (int i = 5; i <= 100 ; i += 5)
{
String selected = (i == rpp ? "selected=\"selected\"" : "");
%>
<option value="<%= i %>" <%= selected %>><%= i %></option>
<%
}
%>
</select>
&nbsp;|&nbsp;
<%
if (sortOptions.size() > 0)
{
%>
<label for="sort_by"><fmt:message key="search.results.sort-by"/></label>
<select name="sort_by">
<option value="score"><fmt:message key="search.sort-by.relevance"/></option>
<%
for (String sortBy : sortOptions)
{
String selected = (sortBy.equals(sortedBy) ? "selected=\"selected\"" : "");
String mKey = "search.sort-by." + sortBy;
%> <option value="<%= sortBy %>" <%= selected %>><fmt:message key="<%= mKey %>"/></option><%
}
%>
</select>
<%
}
%>
<label for="order"><fmt:message key="search.results.order"/></label>
<select name="order">
<option value="ASC" <%= ascSelected %>><fmt:message key="search.order.asc" /></option>
<option value="DESC" <%= descSelected %>><fmt:message key="search.order.desc" /></option>
</select>
<label for="etal"><fmt:message key="search.results.etal" /></label>
<select name="etal">
<%
String unlimitedSelect = "";
if (etAl < 1)
{
unlimitedSelect = "selected=\"selected\"";
}
%>
<option value="0" <%= unlimitedSelect %>><fmt:message key="browse.full.etal.unlimited"/></option>
<%
boolean insertedCurrent = false;
for (int i = 0; i <= 50 ; i += 5)
{
// for the first one, we want 1 author, not 0
if (i == 0)
{
String sel = (i + 1 == etAl ? "selected=\"selected\"" : "");
%><option value="1" <%= sel %>>1</option><%
}
// if the current i is greated than that configured by the user,
// insert the one specified in the right place in the list
if (i > etAl && !insertedCurrent && etAl > 1)
{
%><option value="<%= etAl %>" selected="selected"><%= etAl %></option><%
insertedCurrent = true;
}
// determine if the current not-special case is selected
String selected = (i == etAl ? "selected=\"selected\"" : "");
// do this for all other cases than the first and the current
if (i != 0 && i != etAl)
{
%>
<option value="<%= i %>" <%= selected %>><%= i %></option>
<%
}
}
%>
</select>
<input type="submit" name="submit_search" value="<fmt:message key="search.update" />" />
<%
if (admin_button)
{
%><input type="submit" name="submit_export_metadata" value="<fmt:message key="jsp.general.metadataexport.button"/>" /><%
}
%>
</form>
</div>
</div>
<%
DiscoverResult qResults = (DiscoverResult)request.getAttribute("queryresults");
Item [] items = (Item[] )request.getAttribute("items");
Community [] communities = (Community[] )request.getAttribute("communities");
Collection[] collections = (Collection[])request.getAttribute("collections");
if( error )
{
%>
<p align="center" class="submitFormWarn">
<fmt:message key="jsp.search.error.discovery" />
</p>
<%
}
else if( qResults != null && qResults.getTotalSearchResults() == 0 )
{
%>
<%-- <p align="center">Search produced no results.</p> --%>
<p align="center"><fmt:message key="jsp.search.general.noresults"/></p>
<%
}
else if( qResults != null)
{
long pageTotal = ((Long)request.getAttribute("pagetotal" )).longValue();
long pageCurrent = ((Long)request.getAttribute("pagecurrent")).longValue();
long pageLast = ((Long)request.getAttribute("pagelast" )).longValue();
long pageFirst = ((Long)request.getAttribute("pagefirst" )).longValue();
// create the URLs accessing the previous and next search result pages
String baseURL = request.getContextPath()
+ searchScope
+ "/simple-search?query="
+ URLEncoder.encode(query,"UTF-8")
+ httpFilters
+ "&amp;sort_by=" + sortedBy
+ "&amp;order=" + order
+ "&amp;rpp=" + rpp
+ "&amp;etal=" + etAl
+ "&amp;start=";
String nextURL = baseURL;
String firstURL = baseURL;
String lastURL = baseURL;
String prevURL = baseURL
+ (pageCurrent-2) * qResults.getMaxResults();
nextURL = nextURL
+ (pageCurrent) * qResults.getMaxResults();
firstURL = firstURL +"0";
lastURL = lastURL + (pageTotal-1) * qResults.getMaxResults();
%>
<hr/>
<div class="discovery-result-pagination">
<%
long lastHint = qResults.getStart()+qResults.getMaxResults() <= qResults.getTotalSearchResults()?
qResults.getStart()+qResults.getMaxResults():qResults.getTotalSearchResults();
%>
<%-- <p align="center">Results <//%=qResults.getStart()+1%>-<//%=qResults.getStart()+qResults.getHitHandles().size()%> of --%>
<h2 class="info"><fmt:message key="jsp.search.results.results">
<fmt:param><%=qResults.getStart()+1%></fmt:param>
<fmt:param><%=lastHint%></fmt:param>
<fmt:param><%=qResults.getTotalSearchResults()%></fmt:param>
<fmt:param><%=(float) qResults.getSearchTime() / 1000%></fmt:param>
</fmt:message></h2>
<ul class="links">
<%
if (pageFirst != pageCurrent)
{
%><li><a href="<%= prevURL %>"><fmt:message key="jsp.search.general.previous" /></a></li><%
}
if (pageFirst != 1)
{
%><li><a href="<%= firstURL %>">1</a></li><li>...</li><%
}
for( long q = pageFirst; q <= pageLast; q++ )
{
String myLink = "<li><a href=\""
+ baseURL;
if( q == pageCurrent )
{
myLink = "<li class=\"current-page-link\">" + q + "</li>";
}
else
{
myLink = myLink
+ (q-1) * qResults.getMaxResults()
+ "\">"
+ q
+ "</a></li>";
}
%>
<%= myLink %>
<%
}
if (pageTotal > pageLast)
{
%><li>...</li><li><a href="<%= lastURL %>"><%= pageTotal %></a></li><%
}
if (pageTotal > pageCurrent)
{
%><li><a href="<%= nextURL %>"><fmt:message key="jsp.search.general.next" /></a></li><%
}
%>
</ul>
<!-- give a content to the div -->
</div>
<div class="discovery-result-results">
<% if (communities.length > 0 ) { %>
<%-- <h3>Community Hits:</h3> --%>
<h3><fmt:message key="jsp.search.results.comhits"/></h3>
<dspace:communitylist communities="<%= communities %>" />
<% } %>
<% if (collections.length > 0 ) { %>
<%-- <h3>Collection hits:</h3> --%>
<h3><fmt:message key="jsp.search.results.colhits"/></h3>
<dspace:collectionlist collections="<%= collections %>" />
<% } %>
<% if (items.length > 0) { %>
<%-- <h3>Item hits:</h3> --%>
<h3><fmt:message key="jsp.search.results.itemhits"/></h3>
<dspace:itemlist items="<%= items %>" authorLimit="<%= etAl %>" />
<% } %>
</div>
<%-- if the result page is enought long... --%>
<% if ((communities.length + collections.length + items.length) > 10) {%>
<%-- show again the navigation info/links --%>
<div class="discovery-result-pagination">
<%-- <p align="center">Results <//%=qResults.getStart()+1%>-<//%=qResults.getStart()+qResults.getHitHandles().size()%> of --%>
<p class="info"><fmt:message key="jsp.search.results.results">
<fmt:param><%=qResults.getStart()+1%></fmt:param>
<fmt:param><%=lastHint%></fmt:param>
<fmt:param><%=qResults.getTotalSearchResults()%></fmt:param>
<fmt:param><%=(float) qResults.getSearchTime() / 1000 %></fmt:param>
</fmt:message></p>
<ul class="links">
<%
if (pageFirst != pageCurrent)
{
%><li><a href="<%= prevURL %>"><fmt:message key="jsp.search.general.previous" /></a></li><%
}
if (pageFirst != 1)
{
%><li><a href="<%= firstURL %>">1</a></li><li>...</li><%
}
for( long q = pageFirst; q <= pageLast; q++ )
{
String myLink = "<li><a href=\""
+ baseURL;
if( q == pageCurrent )
{
myLink = "<li class=\"current-page-link\">" + q + "</li>";
}
else
{
myLink = myLink
+ (q-1) * qResults.getMaxResults()
+ "\">"
+ q
+ "</a></li>";
}
%>
<%= myLink %>
<%
}
if (pageTotal > pageLast)
{
%><li>...</li><li><a href="<%= lastURL %>"><%= pageTotal %></a></li><%
}
if (pageTotal > pageCurrent)
{
%><li><a href="<%= nextURL %>"><fmt:message key="jsp.search.general.next" /></a></li><%
}
%>
</ul>
<!-- give a content to the div -->
</div>
<% } %>
</div>
<% } %>
<dspace:sidebar>
<%
boolean brefine = false;
List<DiscoverySearchFilterFacet> facetsConf = (List<DiscoverySearchFilterFacet>) request.getAttribute("facetsConfig");
Map<String, Boolean> showFacets = new HashMap<String, Boolean>();
for (DiscoverySearchFilterFacet facetConf : facetsConf)
{
String f = facetConf.getIndexFieldName();
List<FacetResult> facet = qResults.getFacetResult(f);
if (facet.size() == 0)
{
facet = qResults.getFacetResult(f+".year");
if (facet.size() == 0)
{
showFacets.put(f, false);
continue;
}
}
boolean showFacet = false;
for (FacetResult fvalue : facet)
{
if(!appliedFilterQueries.contains(f+"::"+fvalue.getFilterType()+"::"+fvalue.getAsFilterQuery()))
{
showFacet = true;
break;
}
}
showFacets.put(f, showFacet);
brefine = brefine || showFacet;
}
if (brefine) {
%>
<h3 class="facets"><fmt:message key="jsp.search.facet.refine" /></h3>
<div id="facets" class="facetsBox">
<%
for (DiscoverySearchFilterFacet facetConf : facetsConf)
{
String f = facetConf.getIndexFieldName();
if (!showFacets.get(f))
continue;
List<FacetResult> facet = qResults.getFacetResult(f);
if (facet.size() == 0)
{
facet = qResults.getFacetResult(f+".year");
}
int limit = facetConf.getFacetLimit()+1;
String fkey = "jsp.search.facet.refine."+f;
%><div id="facet_<%= f %>" class="facet">
<span class="facetName"><fmt:message key="<%= fkey %>" /></span>
<ul><%
int idx = 1;
int currFp = UIUtil.getIntParameter(request, f+"_page");
if (currFp < 0)
{
currFp = 0;
}
if (currFp > 0)
{
%><li class="facet-previous"><a href="<%= request.getContextPath()
+ (searchScope!=""?"/handle/"+searchScope:"")
+ "/simple-search?query="
+ URLEncoder.encode(query,"UTF-8")
+ "&amp;sort_by=" + sortedBy
+ "&amp;order=" + order
+ "&amp;rpp=" + rpp
+ httpFilters
+ "&amp;etal=" + etAl
+ "&amp;"+f+"_page="+(currFp-1) %>"><fmt:message key="jsp.search.facet.refine.previous" /></a></li>
<%
}
for (FacetResult fvalue : facet)
{
if (idx == limit)
{
%><li class="facet-next"><a href="<%= request.getContextPath()
+ (searchScope!=""?"/handle/"+searchScope:"")
+ "/simple-search?query="
+ URLEncoder.encode(query,"UTF-8")
+ "&amp;sort_by=" + sortedBy
+ "&amp;order=" + order
+ "&amp;rpp=" + rpp
+ httpFilters
+ "&amp;etal=" + etAl
+ "&amp;"+f+"_page="+(currFp+1) %>"><fmt:message key="jsp.search.facet.refine.next" /></a></li>
<%
}
else if(!appliedFilterQueries.contains(f+"::"+fvalue.getFilterType()+"::"+fvalue.getAsFilterQuery()))
{
%><li><a href="<%= request.getContextPath()
+ (searchScope!=""?"/handle/"+searchScope:"")
+ "/simple-search?query="
+ URLEncoder.encode(query,"UTF-8")
+ "&amp;sort_by=" + sortedBy
+ "&amp;order=" + order
+ "&amp;rpp=" + rpp
+ httpFilters
+ "&amp;etal=" + etAl
+ "&amp;filtername="+URLEncoder.encode(f,"UTF-8")
+ "&amp;filterquery="+URLEncoder.encode(fvalue.getAsFilterQuery(),"UTF-8")
+ "&amp;filtertype="+URLEncoder.encode(fvalue.getFilterType(),"UTF-8") %>"
title="<fmt:message key="jsp.search.facet.narrow"><fmt:param><%=fvalue.getDisplayedValue() %></fmt:param></fmt:message>">
<%= StringUtils.abbreviate(fvalue.getDisplayedValue(),32) + " (" + fvalue.getCount()+")" %></a></li><%
}
idx++;
}
%></ul></div><%
}
%>
</div>
<% } %>
</dspace:sidebar>
</dspace:layout>

View File

@@ -17,12 +17,12 @@ import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
public class DiscoverFacetField {
private String field;
private int limit;
private int offset=-1;
/* The facet prefix, all facet values will have to start with the given prefix */
private String prefix;
private String type;
private DiscoveryConfigurationParameters.SORT sortOrder;
public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder) {
this.field = field;
this.type = type;
@@ -30,6 +30,14 @@ public class DiscoverFacetField {
this.sortOrder = sortOrder;
}
public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, int offset) {
this.field = field;
this.type = type;
this.limit = limit;
this.sortOrder = sortOrder;
this.offset = offset;
}
public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, String prefix) {
this.prefix = prefix;
this.limit = limit;
@@ -38,7 +46,14 @@ public class DiscoverFacetField {
this.field = field;
}
public DiscoverFacetField(String field, String type, int limit, DiscoveryConfigurationParameters.SORT sortOrder, String prefix, int offset) {
this.prefix = prefix;
this.limit = limit;
this.type = type;
this.sortOrder = sortOrder;
this.field = field;
this.offset = offset;
}
public String getField() {
return field;
}
@@ -58,4 +73,14 @@ public class DiscoverFacetField {
public DiscoveryConfigurationParameters.SORT getSortOrder() {
return sortOrder;
}
public int getOffset()
{
return offset;
}
public void setOffset(int offset)
{
this.offset = offset;
}
}

View File

@@ -143,6 +143,11 @@ public class DiscoverResult {
{
return authorityKey;
}
public String getFilterType()
{
return authorityKey != null?"authority":"equals";
}
}
public static final class DSpaceObjectHighlightResult

View File

@@ -28,9 +28,15 @@ public interface IndexingService {
void indexContent(Context context, DSpaceObject dso,
boolean force) throws SQLException;
void indexContent(Context context, DSpaceObject dso,
boolean force, boolean commit) throws SQLException, SearchServiceException;
void unIndexContent(Context context, DSpaceObject dso)
throws SQLException, IOException;
void unIndexContent(Context context, DSpaceObject dso, boolean commit)
throws SQLException, IOException;
void unIndexContent(Context context, String handle)
throws SQLException, IOException;
@@ -49,5 +55,7 @@ public interface IndexingService {
void cleanIndex(boolean force) throws IOException,
SQLException, SearchServiceException;
void optimize();
void commit() throws SearchServiceException;
void optimize() throws SearchServiceException;
}

View File

@@ -34,6 +34,8 @@ public class DiscoveryConfiguration implements InitializingBean{
private DiscoverySortConfiguration searchSortConfiguration;
private int defaultRpp = 10;
private String id;
private DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration;
private DiscoveryMoreLikeThisConfiguration moreLikeThisConfiguration;
@@ -93,6 +95,16 @@ public class DiscoveryConfiguration implements InitializingBean{
public void setSearchSortConfiguration(DiscoverySortConfiguration searchSortConfiguration) {
this.searchSortConfiguration = searchSortConfiguration;
}
public void setDefaultRpp(int defaultRpp)
{
this.defaultRpp = defaultRpp;
}
public int getDefaultRpp()
{
return defaultRpp;
}
public void setHitHighlightingConfiguration(DiscoveryHitHighlightingConfiguration hitHighlightingConfiguration) {
this.hitHighlightingConfiguration = hitHighlightingConfiguration;
@@ -134,5 +146,5 @@ public class DiscoveryConfiguration implements InitializingBean{
throw new DiscoveryConfigurationException(error.toString());
}
}
}
}

View File

@@ -18,6 +18,8 @@ public class DiscoveryConfigurationParameters {
public static final String TYPE_DATE = "date";
public static final String TYPE_HIERARCHICAL = "hierarchical";
public static final String TYPE_AC = "ac";
public static final String TYPE_AUTHORITY = "authority";
public static final String TYPE_STANDARD = "standard";
public static enum SORT {VALUE, COUNT}

View File

@@ -77,11 +77,11 @@ public class SolrServiceImpl implements SearchService, IndexingService {
public static final String FILTER_SEPARATOR = "\n|||\n";
public static final String AUTHORITY_SEPARATOR = "\n§§§\n";
public static final String AUTHORITY_SEPARATOR = "###";
public static final String STORE_SEPARATOR = "\n|||\n";
public static final String VARIANTS_STORE_SEPARATOR = "\n§§§\n";
public static final String VARIANTS_STORE_SEPARATOR = "###";
/**
* Non-Static CommonsHttpSolrServer for processing indexing events.
@@ -193,8 +193,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
/**
* unIndex removes an Item, Collection, or Community only works if the
* DSpaceObject has a handle (uses the handle for its unique ID)
* unIndex removes an Item, Collection, or Community
*
* @param context
* @param dso DSpace Object, can be Community, Item, or Collection
@@ -203,10 +202,32 @@ public class SolrServiceImpl implements SearchService, IndexingService {
*/
public void unIndexContent(Context context, DSpaceObject dso)
throws SQLException, IOException {
unIndexContent(context, dso, false);
}
/**
* unIndex removes an Item, Collection, or Community
*
* @param context
* @param dso DSpace Object, can be Community, Item, or Collection
* @param commit if <code>true</code> force an immediate commit on SOLR
* @throws SQLException
* @throws IOException
*/
public void unIndexContent(Context context, DSpaceObject dso, boolean commit)
throws SQLException, IOException {
try {
unIndexContent(context, dso.getHandle());
} catch (Exception exception)
{
if (dso == null)
{
return;
}
String uniqueID = dso.getType()+"-"+dso.getID();
getSolr().deleteById(uniqueID);
if(commit)
{
getSolr().commit();
}
} catch (Exception exception) {
log.error(exception.getMessage(), exception);
emailException(exception);
}
@@ -234,7 +255,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
throws SQLException, IOException {
try {
getSolr().deleteById(handle);
getSolr().deleteByQuery("handle:\""+handle+"\"");
if(commit)
{
getSolr().commit();
@@ -305,7 +326,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
try {
ItemIterator items = null;
try {
for (items = Item.findAll(context); items.hasNext();)
for (items = Item.findAllUnfiltered(context); items.hasNext();)
{
Item item = items.next();
indexContent(context, item, force);
@@ -360,10 +381,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
{
if (force)
{
getSolr().deleteByQuery("*:*");
getSolr().deleteByQuery("search.resourcetype:[2 TO 4]");
} else {
SolrQuery query = new SolrQuery();
query.setQuery("*:*");
query.setQuery("search.resourcetype:[2 TO 4]");
QueryResponse rsp = getSolr().query(query);
SolrDocumentList docs = rsp.getResults();
@@ -935,6 +956,11 @@ public class SolrServiceImpl implements SearchService, IndexingService {
for (DiscoverySearchFilter searchFilter : searchFilterConfigs)
{
Date date = null;
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
if(separator == null)
{
separator = FILTER_SEPARATOR;
}
if(searchFilter.getType().equals(DiscoveryConfigurationParameters.TYPE_DATE))
{
//For our search filters that are dates we format them properly
@@ -948,29 +974,63 @@ public class SolrServiceImpl implements SearchService, IndexingService {
doc.addField(searchFilter.getIndexFieldName(), value);
doc.addField(searchFilter.getIndexFieldName() + "_keyword", value);
if (authority != null && preferedLabel == null)
{
doc.addField(searchFilter.getIndexFieldName()
+ "_keyword", value + AUTHORITY_SEPARATOR
+ authority);
doc.addField(searchFilter.getIndexFieldName()
+ "_authority", authority);
doc.addField(searchFilter.getIndexFieldName()
+ "_acid", value.toLowerCase()
+ separator + value
+ AUTHORITY_SEPARATOR + authority);
}
if (preferedLabel != null)
{
doc.addField(searchFilter.getIndexFieldName(), preferedLabel);
doc.addField(searchFilter.getIndexFieldName(),
preferedLabel);
doc.addField(searchFilter.getIndexFieldName()
+ "_keyword", preferedLabel);
doc.addField(searchFilter.getIndexFieldName()
+ "_keyword", preferedLabel
+ AUTHORITY_SEPARATOR + authority);
doc.addField(searchFilter.getIndexFieldName()
+ "_authority", authority);
doc.addField(searchFilter.getIndexFieldName()
+ "_acid", preferedLabel.toLowerCase()
+ separator + preferedLabel
+ AUTHORITY_SEPARATOR + authority);
}
if (variants != null)
{
for (String var : variants)
{
doc.addField(searchFilter.getIndexFieldName(), var);
doc.addField(searchFilter.getIndexFieldName() + "_keyword", var);
doc.addField(searchFilter.getIndexFieldName()
+ "_acid", var.toLowerCase()
+ separator + var
+ AUTHORITY_SEPARATOR + authority);
}
}
//Add a dynamic fields for auto complete in search
doc.addField(searchFilter.getIndexFieldName() + "_keyword", value);
doc.addField(searchFilter.getIndexFieldName() + "_ac",
value.toLowerCase() + separator + value);
if (preferedLabel != null)
{
doc.addField(searchFilter.getIndexFieldName() + "_keyword", preferedLabel);
doc.addField(searchFilter.getIndexFieldName()
+ "_ac", preferedLabel.toLowerCase()
+ separator + preferedLabel);
}
if (variants != null)
{
for (String var : variants)
{
doc.addField(searchFilter.getIndexFieldName() + "_ac", var);
doc.addField(searchFilter.getIndexFieldName()
+ "_ac", var.toLowerCase() + separator
+ var);
}
}
@@ -981,11 +1041,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
//Add a special filter
//We use a separator to split up the lowercase and regular case, this is needed to get our filters in regular case
//Solr has issues with facet prefix and cases
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
if(separator == null)
{
separator = FILTER_SEPARATOR;
}
if (authority != null)
{
String facetValue = preferedLabel != null?preferedLabel:value;
@@ -1032,12 +1087,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
}
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
if(separator == null)
{
separator = FILTER_SEPARATOR;
}
String indexValue = valueBuilder.toString().trim();
doc.addField(searchFilter.getIndexFieldName() + "_tax_" + i + "_filter", indexValue.toLowerCase() + separator + indexValue);
//We add the field x times that it has occurred
@@ -1206,6 +1255,16 @@ public class SolrServiceImpl implements SearchService, IndexingService {
{
log.error(e.getMessage(), e);
}
finally {
Iterator<InputStreamReader> itr = readers.iterator();
while (itr.hasNext()) {
InputStreamReader reader = itr.next();
if (reader != null) {
reader.close();
}
}
log.debug("closed " + readers.size() + " readers");
}
//Do any additional indexing, depends on the plugins
List<SolrServiceIndexPlugin> solrServiceIndexPlugins = new DSpace().getServiceManager().getServicesByType(SolrServiceIndexPlugin.class);
@@ -1221,18 +1280,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} catch (RuntimeException e)
{
log.error("Error while writing item to discovery index: " + handle + " message:"+ e.getMessage(), e);
} finally {
Iterator<InputStreamReader> itr = readers.iterator();
while (itr.hasNext())
{
InputStreamReader reader = itr.next();
if (reader != null)
{
reader.close();
}
}
log.debug("closed " + readers.size() + " readers");
}
}
}
/**
@@ -1254,6 +1302,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
// New fields to weaken the dependence on handles, and allow for faster
// list display
doc.addField("search.uniqueid", type+"-"+id);
doc.addField("search.resourcetype", Integer.toString(type));
doc.addField("search.resourceid", Integer.toString(id));
@@ -1372,7 +1421,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
DiscoverQuery query)
throws SearchServiceException
{
return search(context, dso, query);
return search(context, dso, query, false);
}
public DiscoverResult search(Context context, DSpaceObject dso, DiscoverQuery discoveryQuery, boolean includeWithdrawn) throws SearchServiceException {
@@ -1485,7 +1534,12 @@ public class SolrServiceImpl implements SearchService, IndexingService {
facetSort = FacetParams.FACET_SORT_INDEX;
}
solrQuery.add("f." + field + "." + FacetParams.FACET_SORT, facetSort);
if (facetFieldConfig.getOffset() != -1)
{
solrQuery.setParam("f." + field + "."
+ FacetParams.FACET_OFFSET,
String.valueOf(facetFieldConfig.getOffset()));
}
if(facetFieldConfig.getPrefix() != null)
{
solrQuery.setFacetPrefix(field, facetFieldConfig.getPrefix());
@@ -1646,10 +1700,14 @@ public class SolrServiceImpl implements SearchService, IndexingService {
String field = transformFacetField(facetFieldConfig, facetField.getName(), true);
String authorityValue = transformAuthorityValue(context, facetField.getName(), facetValue.getName());
String sortValue = transformSortValue(context, facetField.getName(), facetValue.getName());
String filterValue = displayedValue;
if (StringUtils.isNotBlank(authorityValue))
{
filterValue = authorityValue;
}
result.addFacetResult(
field,
new DiscoverResult.FacetResult(facetValue
.getAsFilterQuery(),
new DiscoverResult.FacetResult(filterValue,
displayedValue, authorityValue,
sortValue, facetValue.getCount()));
}
@@ -1784,6 +1842,17 @@ public class SolrServiceImpl implements SearchService, IndexingService {
//Query the keyword indexed field !
filterQuery.append("_keyword");
}
else if ("authority".equals(operator))
{
//Query the authority indexed field !
filterQuery.append("_authority");
}
else if ("notequals".equals(operator)
|| "notcontains".equals(operator)
|| "notauthority".equals(operator))
{
filterQuery.insert(0, "-");
}
filterQuery.append(":");
if("equals".equals(operator))
{
@@ -1794,7 +1863,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
filterQuery.append(value);
}else{
}
else{
//DO NOT ESCAPE RANGE QUERIES !
if(!value.matches("\\[.*TO.*\\]"))
{
@@ -1910,7 +1980,17 @@ public class SolrServiceImpl implements SearchService, IndexingService {
//Only display top level filters !
return field + "_tax_0_filter";
}
}else if(facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_AUTHORITY))
{
if(removePostfix)
{
return field.substring(0, field.lastIndexOf("_acid"));
}else{
return field + "_acid";
}
}else if(facetFieldConfig.getType().equals(DiscoveryConfigurationParameters.TYPE_STANDARD))
{
return field;
}else{
return field;
}
@@ -1920,8 +2000,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
if(field.equals("location.comm") || field.equals("location.coll"))
{
value = locationToName(context, field, value);
}else
if(field.endsWith("_filter"))
}
else if (field.endsWith("_filter") || field.endsWith("_ac")
|| field.endsWith("_acid"))
{
//We have a filter make sure we split !
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
@@ -1949,7 +2030,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
protected String transformAuthorityValue(Context context, String field, String value) throws SQLException {
if(field.endsWith("_filter"))
if (field.endsWith("_filter") || field.endsWith("_ac")
|| field.endsWith("_acid"))
{
//We have a filter make sure we split !
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
@@ -1982,8 +2064,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
if(field.equals("location.comm") || field.equals("location.coll"))
{
value = locationToName(context, field, value);
}else
if(field.endsWith("_filter"))
}
else if (field.endsWith("_filter") || field.endsWith("_ac")
|| field.endsWith("_acid"))
{
//We have a filter make sure we split !
String separator = new DSpace().getConfigurationService().getProperty("discovery.solr.facets.split.char");
@@ -2008,4 +2091,23 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
return value;
}
@Override
public void indexContent(Context context, DSpaceObject dso, boolean force,
boolean commit) throws SearchServiceException, SQLException {
indexContent(context, dso, force);
if (commit)
{
commit();
}
}
@Override
public void commit() throws SearchServiceException {
try {
getSolr().commit();
} catch (Exception e) {
throw new SearchServiceException(e.getMessage(), e);
}
}
}

View File

@@ -399,7 +399,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
Cell cell = singleTable.addRow().addCell();
//No use in selecting the same filter twice
if(filterQueries.contains(searchService.toFilterQuery(context, facetField, "equals", displayedValue).getFilterQuery())){
if(filterQueries.contains(searchService.toFilterQuery(context, facetField, value.getFilterType(), value.getAsFilterQuery()).getFilterQuery())){
cell.addContent(displayedValue + " (" + value.getCount() + ")");
} else {
//Add the basics
@@ -410,7 +410,7 @@ public class SearchFacetFilter extends AbstractDSpaceTransformer implements Cach
url = addFilterQueriesToUrl(url);
//Last add the current filter query
url += "&filtertype=" + facetField;
url += "&filter_relational_operator=equals";
url += "&filter_relational_operator="+value.getFilterType();
url += "&filter=" + URLEncoder.encode(displayedValue, "UTF-8");
cell.addXref(url, displayedValue + " (" + value.getCount() + ")"
);

View File

@@ -231,7 +231,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
if (i < shownFacets - 1) {
String displayedValue = value.getDisplayedValue();
String filterQuery = value.getAsFilterQuery();
String filterType = value.getFilterType();
if (fqs.contains(getSearchService().toFilterQuery(context, field.getIndexFieldName(), "equals", value.getDisplayedValue()).getFilterQuery())) {
filterValsList.addItem(Math.random() + "", "selected").addContent(displayedValue + " (" + value.getCount() + ")");
} else {
@@ -243,7 +243,7 @@ public class SidebarFacetsTransformer extends AbstractDSpaceTransformer implemen
"/discover?" +
paramsQuery +
"filtertype=" + field.getIndexFieldName() +
"&filter_relational_operator=equals" +
"&filter_relational_operator="+ filterType +
"&filter=" + encodeForURL(filterQuery),
displayedValue + " (" + value.getCount() + ")"
);

View File

@@ -72,6 +72,10 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
private static final Message T_filters_show = message("xmlui.Discovery.AbstractSearch.filters.display");
private static final Message T_filter_contain = message("xmlui.Discovery.SimpleSearch.filter.contains");
private static final Message T_filter_equals = message("xmlui.Discovery.SimpleSearch.filter.equals");
private static final Message T_filter_notcontain = message("xmlui.Discovery.SimpleSearch.filter.notcontains");
private static final Message T_filter_notequals = message("xmlui.Discovery.SimpleSearch.filter.notequals");
private static final Message T_filter_authority = message("xmlui.Discovery.SimpleSearch.filter.authority");
private static final Message T_filter_notauthority = message("xmlui.Discovery.SimpleSearch.filter.notauthority");
private SearchService searchService = null;
@@ -228,6 +232,11 @@ public class SimpleSearch extends AbstractSearch implements CacheableProcessingC
Select typeSelect = row.addCell("", Cell.ROLE_DATA, "selection").addSelect("filter_relational_operator_" + index);
typeSelect.addOption(StringUtils.equals(relationalOperator, "contains"), "contains", T_filter_contain);
typeSelect.addOption(StringUtils.equals(relationalOperator, "equals"), "equals", T_filter_equals);
typeSelect.addOption(StringUtils.equals(relationalOperator, "authority"), "authority", T_filter_authority);
typeSelect.addOption(StringUtils.equals(relationalOperator, "notcontains"), "notcontains", T_filter_notcontain);
typeSelect.addOption(StringUtils.equals(relationalOperator, "notequals"), "notequals", T_filter_notequals);
typeSelect.addOption(StringUtils.equals(relationalOperator, "notauthority"), "notauthority", T_filter_notauthority);

View File

@@ -132,7 +132,11 @@
<message key="xmlui.Discovery.SimpleSearch.filter.contains">Contains</message>
<message key="xmlui.Discovery.SimpleSearch.filter.equals">Equals</message>
<message key="xmlui.Discovery.SimpleSearch.filter.authority">ID</message>
<message key="xmlui.Discovery.SimpleSearch.filter.notcontains">Not Contains</message>
<message key="xmlui.Discovery.SimpleSearch.filter.notequals">Not Equals</message>
<message key="xmlui.Discovery.SimpleSearch.filter.notauthority">Not ID</message>
<message key="xmlui.Discovery.RelatedItems.head">Related items</message>
<message key="xmlui.Discovery.RelatedItems.help">Showing items related by title, author, creator and subject.</message>

View File

@@ -20,6 +20,8 @@
<module>dspace-discovery-solr</module>
<module>dspace-discovery-xmlui-api</module>
<module>dspace-discovery-xmlui-webapp</module>
<module>dspace-discovery-jspui-api</module>
<module>dspace-discovery-jspui-webapp</module>
</modules>
<build>

View File

@@ -0,0 +1,31 @@
package org.dspace.app.webui.json;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
public abstract class JSONRequest
{
private String subPath;
public abstract void doJSONRequest(Context context, HttpServletRequest req,
HttpServletResponse resp) throws AuthorizeException, IOException;
public String getSubPath()
{
return subPath;
}
/**
* Set the subPath that this plugin-instance will serve
* @param subPath
*/
public void setSubPath(String subPath)
{
this.subPath = subPath;
}
}

View File

@@ -0,0 +1,679 @@
package org.dspace.app.webui.search;
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.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.log4j.Logger;
import org.dspace.app.bulkedit.DSpaceCSV;
import org.dspace.app.bulkedit.MetadataExport;
import org.dspace.app.util.OpenSearch;
import org.dspace.app.util.SyndicationFeed;
import org.dspace.app.util.Util;
import org.dspace.app.webui.servlet.SimpleSearchServlet;
import org.dspace.app.webui.util.JSPManager;
import org.dspace.app.webui.util.UIUtil;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
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.w3c.dom.Document;
public class LuceneSearchProcessor implements SearchRequestProcessor
{
/** log4j category */
private static Logger log = Logger.getLogger(SimpleSearchServlet.class);
// locale-sensitive metadata labels
private Map<String, Map<String, String>> localeLabels = new HashMap<String, Map<String, String>>();
private static String msgKey = "org.dspace.app.webui.servlet.FeedServlet";
/**
* <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
*/
@Override
public void doSimpleSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException, IOException, ServletException
{
try
{
// 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 = "";
// 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");
// 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 = 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 = qResults.getHitIds().get(i);
String myHandle = qResults.getHitHandles().get(i);
Integer myType = 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", Integer.valueOf(pageTotal));
request.setAttribute("pagecurrent", Integer.valueOf(pageCurrent));
request.setAttribute("pagelast", Integer.valueOf(pageLast));
request.setAttribute("pagefirst", Integer.valueOf(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", 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");
Map<String, String> queryHash = qArgs.buildQueryMap(request);
if (queryHash != null)
{
for (Map.Entry<String, String> entry : queryHash.entrySet())
{
request.setAttribute(entry.getKey(), entry.getValue());
}
}
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");
}
}
catch (IllegalStateException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
}
/**
* Method for constructing the advanced search form
*
* @author gam
*/
@Override
public void doAdvancedSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException, ServletException, IOException
{
// just build a list of top-level communities and pass along to the jsp
Community[] communities;
try
{
communities = Community.findAllTop(context);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
request.setAttribute("communities", communities);
JSPManager.showJSP(request, response, "/search/advanced.jsp");
}
/**
* Method for producing OpenSearch-compliant search results, and the
* OpenSearch description document.
* <p>
* The value of the "scope" parameter should be absent (which means no scope
* restriction), or the handle of a community or collection, otherwise
* parameters exactly match those of the SearchServlet.
* </p>
*
* @author Richard Rodgers
*/
@Override
public void doOpenSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException, IOException, ServletException
{
// dispense with simple service document requests
String scope = request.getParameter("scope");
if (scope !=null && "".equals(scope))
{
scope = null;
}
String path = request.getPathInfo();
if (path != null && path.endsWith("description.xml"))
{
String svcDescrip = OpenSearch.getDescription(scope);
response.setContentType(OpenSearch.getContentType("opensearchdescription"));
response.setContentLength(svcDescrip.length());
response.getWriter().write(svcDescrip);
return;
}
// get enough request parameters to decide on action to take
String format = request.getParameter("format");
if (format == null || "".equals(format))
{
// default to atom
format = "atom";
}
// do some sanity checking
if (! OpenSearch.getFormats().contains(format))
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// then the rest - we are processing the query
String query = request.getParameter("query");
int start = Util.getIntParameter(request, "start");
int rpp = Util.getIntParameter(request, "rpp");
int sort = Util.getIntParameter(request, "sort_by");
String order = request.getParameter("order");
String sortOrder = (order == null || order.length() == 0 || order.toLowerCase().startsWith("asc")) ?
SortOption.ASCENDING : SortOption.DESCENDING;
QueryArgs qArgs = new QueryArgs();
// can't start earlier than 0 in the results!
if (start < 0)
{
start = 0;
}
qArgs.setStart(start);
if (rpp > 0)
{
qArgs.setPageSize(rpp);
}
qArgs.setSortOrder(sortOrder);
if (sort > 0)
{
try
{
qArgs.setSortOption(SortOption.getSortOption(sort));
}
catch(Exception e)
{
// invalid sort id - do nothing
}
}
qArgs.setSortOrder(sortOrder);
// Ensure the query is non-null
if (query == null)
{
query = "";
}
// If there is a scope parameter, attempt to dereference it
// failure will only result in its being ignored
DSpaceObject container;
try
{
container = (scope != null) ? HandleManager.resolveToObject(context, scope) : null;
}
catch (IllegalStateException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
// Build log information
String logInfo = "";
// get the start of the query results page
qArgs.setQuery(query);
// Perform the search
QueryResults qResults = null;
if (container == null)
{
qResults = DSQuery.doQuery(context, qArgs);
}
else if (container instanceof Collection)
{
logInfo = "collection_id=" + container.getID() + ",";
qResults = DSQuery.doQuery(context, qArgs, (Collection)container);
}
else if (container instanceof Community)
{
logInfo = "community_id=" + container.getID() + ",";
qResults = DSQuery.doQuery(context, qArgs, (Community)container);
}
else
{
throw new IllegalStateException("Invalid container for search context");
}
// now instantiate the results
DSpaceObject[] results = new DSpaceObject[qResults.getHitHandles().size()];
for (int i = 0; i < qResults.getHitHandles().size(); i++)
{
String myHandle = qResults.getHitHandles().get(i);
DSpaceObject dso;
try
{
dso = HandleManager.resolveToObject(context, myHandle);
}
catch (IllegalStateException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
catch (SQLException e)
{
throw new SearchProcessorException(e.getMessage(), e);
}
if (dso == null)
{
throw new SearchProcessorException("Query \"" + query
+ "\" returned unresolvable handle: " + myHandle);
}
results[i] = dso;
}
// Log
log.info(LogManager.getHeader(context, "search", logInfo + "query=\"" + query + "\",results=(" + results.length + ")"));
// format and return results
Map<String, String> labelMap = getLabels(request);
Document resultsDoc = OpenSearch.getResultsDoc(format, query, qResults, container, results, labelMap);
try
{
Transformer xf = TransformerFactory.newInstance().newTransformer();
response.setContentType(OpenSearch.getContentType(format));
xf.transform(new DOMSource(resultsDoc), new StreamResult(response.getWriter()));
}
catch (TransformerException e)
{
log.error(e);
throw new ServletException(e.toString(), e);
}
}
/**
* 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
List<Integer> iids = new ArrayList<Integer>();
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;
}
private Map<String, String> getLabels(HttpServletRequest request)
{
// Get access to the localized resource bundle
Locale locale = request.getLocale();
Map<String, String> labelMap = localeLabels.get(locale.toString());
if (labelMap == null)
{
labelMap = getLocaleLabels(locale);
localeLabels.put(locale.toString(), labelMap);
}
return labelMap;
}
private Map<String, String> getLocaleLabels(Locale locale)
{
Map<String, String> labelMap = new HashMap<String, String>();
ResourceBundle labels = ResourceBundle.getBundle("Messages", locale);
labelMap.put(SyndicationFeed.MSG_UNTITLED, labels.getString(msgKey + ".notitle"));
labelMap.put(SyndicationFeed.MSG_LOGO_TITLE, labels.getString(msgKey + ".logo.title"));
labelMap.put(SyndicationFeed.MSG_FEED_DESCRIPTION, labels.getString(msgKey + ".general-feed.description"));
labelMap.put(SyndicationFeed.MSG_UITYPE, SyndicationFeed.UITYPE_JSPUI);
for (String selector : SyndicationFeed.getDescriptionSelectors())
{
labelMap.put("metadata." + selector, labels.getString(SyndicationFeed.MSG_METADATA + selector));
}
return labelMap;
}
}

View File

@@ -0,0 +1,29 @@
package org.dspace.app.webui.search;
public class SearchProcessorException extends Exception
{
public SearchProcessorException()
{
super();
// TODO Auto-generated constructor stub
}
public SearchProcessorException(String message)
{
super(message);
// TODO Auto-generated constructor stub
}
public SearchProcessorException(String message, Throwable cause)
{
super(message, cause);
// TODO Auto-generated constructor stub
}
public SearchProcessorException(Throwable cause)
{
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@@ -0,0 +1,25 @@
package org.dspace.app.webui.search;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.core.Context;
public interface SearchRequestProcessor
{
public void doSimpleSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException;
public void doAdvancedSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException;
public void doOpenSearch(Context context, HttpServletRequest request,
HttpServletResponse response) throws SearchProcessorException,
IOException, ServletException;
}

View File

@@ -14,28 +14,56 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.webui.util.JSPManager;
import org.apache.log4j.Logger;
import org.dspace.app.webui.search.LuceneSearchProcessor;
import org.dspace.app.webui.search.SearchProcessorException;
import org.dspace.app.webui.search.SearchRequestProcessor;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.core.Context;
import org.dspace.core.PluginConfigurationError;
import org.dspace.core.PluginManager;
/**
* Servlet for constructing the advanced search form
* Servlet for constructing/processing an advanced search form
*
* @author gam
* @version $Revision$
*/
public class AdvancedSearchServlet extends DSpaceServlet
{
private SearchRequestProcessor internalLogic;
/** log4j category */
private static Logger log = Logger.getLogger(AdvancedSearchServlet.class);
public void init()
{
try
{
internalLogic = (SearchRequestProcessor) PluginManager
.getSinglePlugin(SearchRequestProcessor.class);
}
catch (PluginConfigurationError e)
{
log.warn(
"AdvancedSearchServlet not properly configurated, please configure the SearchRequestProcessor plugin",
e);
}
if (internalLogic == null)
{ // backward compatibility
internalLogic = new LuceneSearchProcessor();
}
}
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException
{
// just build a list of top-level communities and pass along to the jsp
Community[] communities = Community.findAllTop(context);
request.setAttribute("communities", communities);
JSPManager.showJSP(request, response, "/search/advanced.jsp");
try
{
internalLogic.doAdvancedSearch(context, request, response);
}
catch (SearchProcessorException e)
{
throw new ServletException(e.getMessage(), e);
}
}
}

View File

@@ -43,6 +43,7 @@ import org.dspace.eperson.Subscribe;
import org.dspace.handle.HandleManager;
import org.dspace.plugin.CollectionHomeProcessor;
import org.dspace.plugin.CommunityHomeProcessor;
import org.dspace.plugin.ItemHomeProcessor;
import org.dspace.usage.UsageEvent;
import org.dspace.utils.DSpace;
import org.jdom.Element;
@@ -290,6 +291,9 @@ public class HandleServlet extends DSpaceServlet
throws ServletException, IOException, SQLException,
AuthorizeException
{
// perform any necessary pre-processing
preProcessItemHome(context, request, response, item);
// Tombstone?
if (item.isWithdrawn())
{
@@ -415,6 +419,25 @@ public class HandleServlet extends DSpaceServlet
request.setAttribute("dspace.layout.head", headMetadata);
JSPManager.showJSP(request, response, "/display-item.jsp");
}
private void preProcessItemHome(Context context, HttpServletRequest request,
HttpServletResponse response, Item item)
throws ServletException, IOException, SQLException
{
try
{
ItemHomeProcessor[] chp = (ItemHomeProcessor[]) PluginManager.getPluginSequence(ItemHomeProcessor.class);
for (int i = 0; i < chp.length; i++)
{
chp[i].process(context, request, response, item);
}
}
catch (Exception e)
{
log.error("caught exception: ", e);
throw new ServletException(e);
}
}
/**
* Show a community home page, or deal with button press on home page

View File

@@ -0,0 +1,72 @@
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.json.JSONRequest;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.core.PluginManager;
public class JSONServlet extends DSpaceServlet
{
private static Logger log = Logger.getLogger(JSONServlet.class);
@Override
protected void doDSPost(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException
{
doDSGet(context, request, response);
}
@Override
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws IOException,
AuthorizeException
{
String pluginName = request.getPathInfo();
if (pluginName == null)
{
pluginName = "";
}
if (pluginName.startsWith("/"))
{
pluginName = pluginName.substring(1);
pluginName = pluginName.split("/")[0];
}
JSONRequest jsonReq = (JSONRequest) PluginManager.getNamedPlugin(JSONRequest.class,
pluginName);
if (jsonReq == null)
{
log.error(LogManager.getHeader(context, "jsonrequest",
"No plugin found for manage the path " + pluginName));
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
jsonReq.setSubPath(pluginName);
try
{
response.setContentType("application/json; charset=UTF-8");
jsonReq.doJSONRequest(context, request, response);
}
catch (Exception e)
{
// no need to log, logging is already done by the
// InternalErrorServlet
// log.error(LogManager.getHeader(context, "jsonrequest",
// pluginName),
// e);
throw new RuntimeException(e.getMessage(), e);
}
}
}

View File

@@ -9,237 +9,71 @@ package org.dspace.app.webui.servlet;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.TransformerException;
import org.w3c.dom.Document;
import org.apache.log4j.Logger;
import org.dspace.app.util.OpenSearch;
import org.dspace.app.util.SyndicationFeed;
import org.dspace.app.util.Util;
import org.dspace.app.webui.search.LuceneSearchProcessor;
import org.dspace.app.webui.search.SearchProcessorException;
import org.dspace.app.webui.search.SearchRequestProcessor;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
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.core.PluginConfigurationError;
import org.dspace.core.PluginManager;
/**
* Servlet for producing OpenSearch-compliant search results, and the
* OpenSearch description document.
* Servlet for producing OpenSearch-compliant search results, and the OpenSearch
* description document.
* <p>
* OpenSearch is a specification for describing and advertising search-engines
* and their result formats. Commonly, RSS and Atom formats are used, which
* the current implementation supports, as is HTML (used directly in browsers).
* NB: this is baseline OpenSearch, no extensions currently supported.
* and their result formats. Commonly, RSS and Atom formats are used, which the
* current implementation supports, as is HTML (used directly in browsers). NB:
* this is baseline OpenSearch, no extensions currently supported.
* </p>
* <p>
* The value of the "scope" parameter should be absent (which means no
* scope restriction), or the handle of a community or collection, otherwise
* parameters exactly match those of the SearchServlet.
* </p>
*
* @author Richard Rodgers
*
*
*/
public class OpenSearchServlet extends DSpaceServlet
{
private static final long serialVersionUID = 1L;
private static String msgKey = "org.dspace.app.webui.servlet.FeedServlet";
/** log4j category */
private static Logger log = Logger.getLogger(OpenSearchServlet.class);
// locale-sensitive metadata labels
private Map<String, Map<String, String>> localeLabels = null;
private static final long serialVersionUID = 1L;
private SearchRequestProcessor internalLogic;
/** log4j category */
private static Logger log = Logger.getLogger(OpenSearchServlet.class);
public void init()
{
localeLabels = new HashMap<String, Map<String, String>>();
try
{
internalLogic = (SearchRequestProcessor) PluginManager
.getSinglePlugin(SearchRequestProcessor.class);
}
catch (PluginConfigurationError e)
{
log.warn(
"OpenSearchServlet not properly configurated, please configure the SearchRequestProcessor plugin",
e);
}
if (internalLogic == null)
{ // backward compatibility
internalLogic = new LuceneSearchProcessor();
}
}
protected void doDSGet(Context context, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException,
SQLException, AuthorizeException
{
// dispense with simple service document requests
String scope = request.getParameter("scope");
if (scope !=null && "".equals(scope))
{
scope = null;
}
String path = request.getPathInfo();
if (path != null && path.endsWith("description.xml"))
{
String svcDescrip = OpenSearch.getDescription(scope);
response.setContentType(OpenSearch.getContentType("opensearchdescription"));
response.setContentLength(svcDescrip.length());
response.getWriter().write(svcDescrip);
return;
}
// get enough request parameters to decide on action to take
String format = request.getParameter("format");
if (format == null || "".equals(format))
{
// default to atom
format = "atom";
}
// do some sanity checking
if (! OpenSearch.getFormats().contains(format))
{
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// then the rest - we are processing the query
String query = request.getParameter("query");
int start = Util.getIntParameter(request, "start");
int rpp = Util.getIntParameter(request, "rpp");
int sort = Util.getIntParameter(request, "sort_by");
String order = request.getParameter("order");
String sortOrder = (order == null || order.length() == 0 || order.toLowerCase().startsWith("asc")) ?
SortOption.ASCENDING : SortOption.DESCENDING;
QueryArgs qArgs = new QueryArgs();
// can't start earlier than 0 in the results!
if (start < 0)
{
start = 0;
}
qArgs.setStart(start);
if (rpp > 0)
{
qArgs.setPageSize(rpp);
}
qArgs.setSortOrder(sortOrder);
if (sort > 0)
{
try
{
qArgs.setSortOption(SortOption.getSortOption(sort));
}
catch(Exception e)
{
// invalid sort id - do nothing
}
}
qArgs.setSortOrder(sortOrder);
// Ensure the query is non-null
if (query == null)
{
query = "";
}
// If there is a scope parameter, attempt to dereference it
// failure will only result in its being ignored
DSpaceObject container = (scope != null) ? HandleManager.resolveToObject(context, scope) : null;
// Build log information
String logInfo = "";
// get the start of the query results page
qArgs.setQuery(query);
// Perform the search
QueryResults qResults = null;
if (container == null)
{
qResults = DSQuery.doQuery(context, qArgs);
}
else if (container instanceof Collection)
{
logInfo = "collection_id=" + container.getID() + ",";
qResults = DSQuery.doQuery(context, qArgs, (Collection)container);
}
else if (container instanceof Community)
{
logInfo = "community_id=" + container.getID() + ",";
qResults = DSQuery.doQuery(context, qArgs, (Community)container);
}
else
{
throw new IllegalStateException("Invalid container for search context");
}
// now instantiate the results
DSpaceObject[] results = new DSpaceObject[qResults.getHitHandles().size()];
for (int i = 0; i < qResults.getHitHandles().size(); i++)
{
String myHandle = qResults.getHitHandles().get(i);
DSpaceObject dso = HandleManager.resolveToObject(context, myHandle);
if (dso == null)
{
throw new SQLException("Query \"" + query
+ "\" returned unresolvable handle: " + myHandle);
}
results[i] = dso;
}
// Log
log.info(LogManager.getHeader(context, "search", logInfo + "query=\"" + query + "\",results=(" + results.length + ")"));
// format and return results
Map<String, String> labelMap = getLabels(request);
Document resultsDoc = OpenSearch.getResultsDoc(format, query, qResults, container, results, labelMap);
try
{
Transformer xf = TransformerFactory.newInstance().newTransformer();
response.setContentType(OpenSearch.getContentType(format));
xf.transform(new DOMSource(resultsDoc), new StreamResult(response.getWriter()));
internalLogic.doOpenSearch(context, request, response);
}
catch (TransformerException e)
catch (SearchProcessorException e)
{
log.error(e);
throw new ServletException(e.toString(), e);
throw new ServletException(e.getMessage(), e);
}
}
private Map<String, String> getLabels(HttpServletRequest request)
{
// Get access to the localized resource bundle
Locale locale = request.getLocale();
Map<String, String> labelMap = localeLabels.get(locale.toString());
if (labelMap == null)
{
labelMap = getLocaleLabels(locale);
localeLabels.put(locale.toString(), labelMap);
}
return labelMap;
}
private Map<String, String> getLocaleLabels(Locale locale)
{
Map<String, String> labelMap = new HashMap<String, String>();
ResourceBundle labels = ResourceBundle.getBundle("Messages", locale);
labelMap.put(SyndicationFeed.MSG_UNTITLED, labels.getString(msgKey + ".notitle"));
labelMap.put(SyndicationFeed.MSG_LOGO_TITLE, labels.getString(msgKey + ".logo.title"));
labelMap.put(SyndicationFeed.MSG_FEED_DESCRIPTION, labels.getString(msgKey + ".general-feed.description"));
labelMap.put(SyndicationFeed.MSG_UITYPE, SyndicationFeed.UITYPE_JSPUI);
for (String selector : SyndicationFeed.getDescriptionSelectors())
{
labelMap.put("metadata." + selector, labels.getString(SyndicationFeed.MSG_METADATA + selector));
}
return labelMap;
}
}

View File

@@ -8,423 +8,62 @@
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.List;
import java.util.Map;
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.app.webui.search.LuceneSearchProcessor;
import org.dspace.app.webui.search.SearchProcessorException;
import org.dspace.app.webui.search.SearchRequestProcessor;
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.core.PluginConfigurationError;
import org.dspace.core.PluginManager;
/**
* 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
{
private SearchRequestProcessor internalLogic;
/** log4j category */
private static Logger log = Logger.getLogger(SimpleSearchServlet.class);
public void init()
{
try
{
internalLogic = (SearchRequestProcessor) PluginManager
.getSinglePlugin(SearchRequestProcessor.class);
}
catch (PluginConfigurationError e)
{
log.warn(
"SimpleSearchServlet not properly configurated, please configure the SearchRequestProcessor plugin",
e);
}
if (internalLogic == null)
{ // backward compatibility
internalLogic = new LuceneSearchProcessor();
}
}
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 = "";
// 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);
}
internalLogic.doSimpleSearch(context, request, response);
}
catch (Exception e)
catch (SearchProcessorException e)
{
throw new ServletException(e.getMessage(), 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");
// 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 = 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 = qResults.getHitIds().get(i);
String myHandle = qResults.getHitHandles().get(i);
Integer myType = 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", Integer.valueOf(pageTotal));
request.setAttribute("pagecurrent", Integer.valueOf(pageCurrent));
request.setAttribute("pagelast", Integer.valueOf(pageLast));
request.setAttribute("pagefirst", Integer.valueOf(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", 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");
Map<String, String> queryHash = qArgs.buildQueryMap(request);
if (queryHash != null)
{
for (Map.Entry<String, String> entry : queryHash.entrySet())
{
request.setAttribute(entry.getKey(), entry.getValue());
}
}
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
List<Integer> iids = new ArrayList<Integer>();
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;
}
}

View File

@@ -433,7 +433,12 @@
<servlet-name>shibboleth-login</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.ShibbolethServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>json</servlet-name>
<servlet-class>org.dspace.app.webui.servlet.JSONServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>shibboleth-login</servlet-name>
<url-pattern>/shibboleth-login</url-pattern>
@@ -711,6 +716,11 @@
<servlet-name>AuthorityChooseServlet</servlet-name>
<url-pattern>/choices/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>json</servlet-name>
<url-pattern>/json/*</url-pattern>
</servlet-mapping>
<!-- Icon MIME type -->
<mime-mapping>

View File

@@ -362,6 +362,8 @@
}
%>
<%= sidebar %>
<%@ include file="discovery/static-sidebar-facet.jsp" %>
</dspace:sidebar>
</dspace:layout>

View File

@@ -403,7 +403,7 @@
%>
<%= sidebar %>
<%@ include file="discovery/static-sidebar-facet.jsp" %>
</dspace:sidebar>
<div align="center">

View File

@@ -172,5 +172,6 @@ for (int i = supportedLocales.length-1; i >= 0; i--)
<%
}
%>
<%@ include file="discovery/static-sidebar-facet.jsp" %>
</dspace:sidebar>
</dspace:layout>

View File

@@ -37,6 +37,8 @@
<%@ page import="org.dspace.content.Community" %>
<%@ page import="org.dspace.core.Context" %>
<%@ page import="org.dspace.core.LogManager" %>
<%@ page import="org.dspace.core.PluginManager" %>
<%@ page import="org.dspace.plugin.SiteHomeProcessor" %>
<%
Context context = null;
@@ -49,6 +51,21 @@
// Obtain a context so that the location bar can display log in status
context = UIUtil.obtainContext(request);
try
{
SiteHomeProcessor[] chp = (SiteHomeProcessor[]) PluginManager.getPluginSequence(SiteHomeProcessor.class);
for (int i = 0; i < chp.length; i++)
{
chp[i].process(context, request, response);
}
}
catch (Exception e)
{
Logger log = Logger.getLogger("org.dspace.jsp");
log.error("caught exception: ", e);
throw new ServletException(e);
}
// Home page shows community list
Community[] communities = Community.findAllTop(context);
request.setAttribute("communities", communities);

View File

@@ -50,6 +50,8 @@
<link rel="stylesheet" href="<%= request.getContextPath() %>/styles.css" type="text/css" />
<link rel="stylesheet" href="<%= request.getContextPath() %>/print.css" media="print" type="text/css" />
<link rel="shortcut icon" href="<%= request.getContextPath() %>/favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/discovery.css" type="text/css" />
<link rel="stylesheet" href="<%= request.getContextPath() %>/static/css/jquery-ui-1.8.22.custom/redmond/jquery-ui-1.8.22.custom.css" type="text/css" />
<%
if (!"NONE".equals(feedRef))
{
@@ -81,7 +83,8 @@
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/builder.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/scriptaculous/controls.js"> </script>
<script type="text/javascript" src="<%= request.getContextPath() %>/static/js/choice-support.js"> </script>
<script type='text/javascript' src='<%= request.getContextPath() %>/static/js/jquery/jquery-1.7.2.min.js'></script>
<script type='text/javascript' src='<%= request.getContextPath() %>/static/js/jquery/jquery-ui-1.8.22.custom.min.js'></script>
<%--Gooogle Analytics recording.--%>
<%
if (analyticsKey != null && analyticsKey.length() > 0)

View File

@@ -185,6 +185,7 @@ else
<fmt:param><%=qResults.getStart()+1%></fmt:param>
<fmt:param><%=qResults.getStart()+qResults.getHitHandles().size()%></fmt:param>
<fmt:param><%=qResults.getHitCount()%></fmt:param>
<fmt:param><%=(float) qResults.getQueryTime() / 1000 %></fmt:param>
</fmt:message></p>
<% } %>

View File

@@ -0,0 +1,563 @@
/*!
* jQuery UI CSS Framework 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*/
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
.ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/*!
* jQuery UI CSS Framework 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande,%20Lucida%20Sans,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande, Lucida Sans, Arial, sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*!
* jQuery UI Resizable 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*!
* jQuery UI Selectable 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Selectable#theming
*/
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
/*!
* jQuery UI Accordion 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Accordion#theming
*/
/* IE/Win - Fix animation bug - #4615 */
.ui-accordion { width: 100%; }
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
.ui-accordion .ui-accordion-li-fix { display: inline; }
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
.ui-accordion .ui-accordion-content-active { display: block; }
/*!
* jQuery UI Autocomplete 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Autocomplete#theming
*/
.ui-autocomplete { position: absolute; cursor: default; }
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
/*
* jQuery UI Menu 1.8.22
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Menu#theming
*/
.ui-menu {
list-style:none;
padding: 2px;
margin: 0;
display:block;
float: left;
}
.ui-menu .ui-menu {
margin-top: -3px;
}
.ui-menu .ui-menu-item {
margin:0;
padding: 0;
zoom: 1;
float: left;
clear: left;
width: 100%;
}
.ui-menu .ui-menu-item a {
text-decoration:none;
display:block;
padding:.2em .4em;
line-height:1.5;
zoom:1;
}
.ui-menu .ui-menu-item a.ui-state-hover,
.ui-menu .ui-menu-item a.ui-state-active {
font-weight: normal;
margin: -1px;
}
/*!
* jQuery UI Button 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Button#theming
*/
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*!
* jQuery UI Dialog 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
/*!
* jQuery UI Slider 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Slider#theming
*/
.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }/*!
* jQuery UI Tabs 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Tabs#theming
*/
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tabs .ui-tabs-hide { display: none !important; }
/*!
* jQuery UI Datepicker 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Datepicker#theming
*/
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}/*!
* jQuery UI Progressbar 1.8.22
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Progressbar#theming
*/
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1078,6 +1078,37 @@ plugin.sequence.org.dspace.plugin.CommunityHomeProcessor = \
plugin.sequence.org.dspace.plugin.CollectionHomeProcessor = \
org.dspace.app.webui.components.RecentCollectionSubmissions
#### JSPUI Discovery (extra Discovery setting that apply only to the JSPUI) ####
# uncomment the following configuration if you want use Discovery with JSPUI
# plugin.single.org.dspace.app.webui.search.SearchRequestProcessor = \
# org.dspace.app.webui.discovery.DiscoverySearchRequestProcessor
#
# default is to use the Legacy Lucene search engine
plugin.single.org.dspace.app.webui.search.SearchRequestProcessor = \
org.dspace.app.webui.search.LuceneSearchRequestProcessor
#### Sidebar Facets ####
# to show facets on the site home page, community, collection
# uncomments the following lines
#plugin.sequence.org.dspace.plugin.CommunityHomeProcessor = \
# org.dspace.app.webui.components.RecentCommunitySubmissions,\
# org.dspace.app.webui.discovery.SideBarFacetProcessor
#
#plugin.sequence.org.dspace.plugin.CollectionHomeProcessor = \
# org.dspace.app.webui.components.RecentCollectionSubmissions,\
# org.dspace.app.webui.discovery.SideBarFacetProcessor
#
#plugin.sequence.org.dspace.plugin.SiteHomeProcessor = \
# org.dspace.app.webui.discovery.SideBarFacetProcessor
#### JSON JSPUI Request Handler ####
# define here any json handler
#
# comment this line if you disable discovery
plugin.named.org.dspace.app.webui.json,JSONRequest = \
org.dspace.app.webui.discovery.DiscoveryJSONRequest = discovery
#### Submission License substitution variables ####
# it is possible include contextual information in the submission license using substitution variables
# the text substitution is driven by a plugin implementation

View File

@@ -16,3 +16,8 @@ index.ignore=dc.description.provenance
# index.ignore-variants = false
# index.ignore-authority = false
index.projection=dc.title,dc.contributor.*,dc.date.issued
# ONLY-FOR-JSPUI:
# 1) you need to set the DiscoverySearchRequestProcessor in the dspace.cfg
# 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection
# Processors plugin in the dspace.cfg

View File

@@ -85,6 +85,8 @@
<property name="max" value="5"/>
</bean>
</property>
<!--Default result per page -->
<property name="defaultRpp" value="10" />
<property name="hitHighlightingConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration">
<property name="metadataFields">

View File

@@ -44,9 +44,7 @@
</dependency>
</dependencies>
</profile>
</profiles>
</profiles>
<build>
<filters>
<filter>${basedir}/../../../${filters.file}</filter>
@@ -68,6 +66,19 @@
</includes>
</resource>
</webResources>
<overlays>
<overlay></overlay>
<overlay>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery-jspui-webapp</artifactId>
<type>war</type>
</overlay>
<overlay>
<groupId>org.dspace</groupId>
<artifactId>dspace-jspui-webapp</artifactId>
<type>war</type>
</overlay>
</overlays>
</configuration>
<executions>
<execution>
@@ -79,11 +90,11 @@
</build>
<dependencies>
<dependency>
<groupId>org.dspace.modules</groupId>
<artifactId>additions</artifactId>
</dependency>
<dependency>
<groupId>org.dspace.modules</groupId>
<artifactId>additions</artifactId>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
@@ -91,6 +102,19 @@
<type>war</type>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery-jspui-api</artifactId>
<version>3.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-discovery-jspui-webapp</artifactId>
<version>3.0-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-jspui-api</artifactId>

View File

@@ -498,8 +498,11 @@
<!-- Internal DSpaceObject Type ID -->
<field name="search.resourcetype" type="sint" indexed="true" stored="true" required="true" omitNorms="true" />
<!-- All Items/Communities/Collections placed in Discovery must have a unique handle -->
<field name="handle" type="string" indexed="true" stored="true" required="true" omitNorms="true" />
<!-- All object placed in Discovery must have an unique id (for standard DSpaceObject it is resourceID-resourceTypeID) -->
<field name="search.uniqueid" type="string" indexed="true" stored="true" required="true" omitNorms="true" />
<!-- All Items/Communities/Collections placed in Discovery should have an handle -->
<field name="handle" type="string" indexed="true" stored="true" omitNorms="true" />
<field name="withdrawn" type="string" indexed="true" stored="true" omitNorms="true" />
@@ -526,10 +529,12 @@
<dynamicField name="*_stored" type="dspaceMetadataProjection" indexed="false" stored="true" multiValued="true"/>
<!--Dynamic field used for search autocompletion-->
<dynamicField name="*_ac" type="dspaceAutoComplete" indexed="true" stored="true" omitNorms="true" multiValued="true"/>
<dynamicField name="*_ac" type="keywordFilter" indexed="true" stored="true" omitNorms="true" multiValued="true"/>
<dynamicField name="*_acid" type="keywordFilter" indexed="true" stored="true" omitNorms="true" multiValued="true"/>
<!--Dynamic field used for sidebar filters & SOLR browse by value -->
<dynamicField name="*_filter" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
<dynamicField name="*_filter" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
<dynamicField name="*_authority" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
<dynamicField name="*_keyword" type="keywordFilter" indexed="true" stored="true" multiValued="true" omitNorms="true" />
<!--Dynamic field used for SOLR browse by partial value -->
@@ -589,7 +594,7 @@
<!-- Field to use to determine and enforce document uniqueness.
Unless this field is marked with required="false", it will be a required field
-->
<uniqueKey>handle</uniqueKey>
<uniqueKey>search.uniqueid</uniqueKey>
<!-- field for the QueryParser to use when an explicit fieldname is absent -->
<defaultSearchField>text</defaultSearchField>