/** * 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.app.xmlui.aspect.discovery; import java.io.IOException; import java.sql.SQLException; import java.util.*; import org.apache.cocoon.caching.CacheableProcessingComponent; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.Request; import org.apache.commons.lang.StringUtils; import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer; import org.dspace.app.xmlui.utils.HandleUtil; import org.dspace.app.xmlui.utils.UIException; import org.dspace.app.xmlui.wing.Message; import org.dspace.app.xmlui.wing.WingException; import org.dspace.app.xmlui.wing.element.*; import org.dspace.app.xmlui.wing.element.Item; import org.dspace.app.xmlui.wing.element.List; import org.dspace.authorize.AuthorizeException; import org.dspace.content.*; import org.dspace.core.ConfigurationManager; import org.dspace.discovery.*; import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoverySearchFilter; import org.dspace.utils.DSpace; import org.xml.sax.SAXException; /** * Perform a simple search of the repository. The user provides a simple one * field query (the url parameter is named query) and the results are processed. * * @author Kevin Van de Velde (kevin at atmire dot com) * @author Mark Diggory (markd at atmire dot com) * @author Ben Bosman (ben at atmire dot com) * @author Adán Román Ruiz <aroman@arvo.es> (Bugfix) */ public class SimpleSearch extends AbstractSearch implements CacheableProcessingComponent { /** * Language Strings */ private static final Message T_title = message("xmlui.ArtifactBrowser.SimpleSearch.title"); private static final Message T_dspace_home = message("xmlui.general.dspace_home"); private static final Message T_trail = message("xmlui.ArtifactBrowser.SimpleSearch.trail"); private static final Message T_search_scope = message("xmlui.Discovery.SimpleSearch.search_scope"); private static final Message T_head = message("xmlui.ArtifactBrowser.SimpleSearch.head"); // private static final Message T_search_label = // message("xmlui.discovery.SimpleSearch.search_label"); private static final Message T_go = message("xmlui.general.go"); private static final Message T_filter_label = message("xmlui.Discovery.SimpleSearch.filter_head"); private static final Message T_filter_help = message("xmlui.Discovery.SimpleSearch.filter_help"); private static final Message T_filter_current_filters = message("xmlui.Discovery.AbstractSearch.filters.controls.current-filters.head"); private static final Message T_filter_new_filters = message("xmlui.Discovery.AbstractSearch.filters.controls.new-filters.head"); private static final Message T_filter_controls_apply = message("xmlui.Discovery.AbstractSearch.filters.controls.apply-filters"); private static final Message T_filter_controls_add = message("xmlui.Discovery.AbstractSearch.filters.controls.add-filter"); private static final Message T_filter_controls_remove = message("xmlui.Discovery.AbstractSearch.filters.controls.remove-filter"); 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 static final Message T_did_you_mean = message("xmlui.Discovery.SimpleSearch.did_you_mean"); private SearchService searchService = null; public SimpleSearch() { DSpace dspace = new DSpace(); searchService = dspace.getServiceManager().getServiceByName(SearchService.class.getName(),SearchService.class); } /** * Add Page metadata. */ public void addPageMeta(PageMeta pageMeta) throws WingException, SQLException { pageMeta.addMetadata("title").addContent(T_title); pageMeta.addTrailLink(contextPath + "/", T_dspace_home); DSpaceObject dso = HandleUtil.obtainHandle(objectModel); if ((dso instanceof org.dspace.content.Collection) || (dso instanceof Community)) { HandleUtil.buildHandleTrail(dso, pageMeta, contextPath, true); } pageMeta.addTrail().addContent(T_trail); } /** * build the DRI page representing the body of the search query. This * provides a widget to generate a new query and list of search results if * present. */ public void addBody(Body body) throws SAXException, WingException, SQLException, IOException, AuthorizeException { Request request = ObjectModelHelper.getRequest(objectModel); String queryString = getQuery(); // Build the DRI Body Division search = body.addDivision("search", "primary"); search.setHead(T_head); String searchUrl = ConfigurationManager.getProperty("dspace.url") + "/JSON/discovery/search"; search.addHidden("discovery-json-search-url").setValue(searchUrl); DSpaceObject currentScope = getScope(); if(currentScope != null){ search.addHidden("discovery-json-scope").setValue(currentScope.getHandle()); } search.addHidden("contextpath").setValue(contextPath); Map<String, String[]> fqs = getParameterFilterQueries(); Division searchBoxDivision = search.addDivision("discovery-search-box", "discoverySearchBox"); Division mainSearchDiv = searchBoxDivision.addInteractiveDivision("general-query", "discover", Division.METHOD_GET, "discover-search-box"); List searchList = mainSearchDiv.addList("primary-search", List.TYPE_FORM); // searchList.setHead(T_search_label); if (variableScope()) { Select scope = searchList.addItem().addSelect("scope"); scope.setLabel(T_search_scope); buildScopeList(scope); } Item searchBoxItem = searchList.addItem(); Text text = searchBoxItem.addText("query"); text.setValue(queryString); searchBoxItem.addButton("submit", "search-icon").setValue(T_go); if(queryResults != null && StringUtils.isNotBlank(queryResults.getSpellCheckQuery())) { Item didYouMeanItem = searchList.addItem("did-you-mean", "didYouMean"); didYouMeanItem.addContent(T_did_you_mean); didYouMeanItem.addXref(getSuggestUrl(queryResults.getSpellCheckQuery()), queryResults.getSpellCheckQuery(), "didYouMean"); } DSpaceObject dso = HandleUtil.obtainHandle(objectModel); DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(dso); java.util.List<DiscoverySearchFilter> filterFields = discoveryConfiguration.getSearchFilters(); java.util.List<String> filterTypes = DiscoveryUIUtils.getRepeatableParameters(request, "filtertype"); java.util.List<String> filterOperators = DiscoveryUIUtils.getRepeatableParameters(request, "filter_relational_operator"); java.util.List<String> filterValues = DiscoveryUIUtils.getRepeatableParameters(request, "filter"); if(0 < filterFields.size() && filterTypes.size() == 0) { //Display the add filters url ONLY if we have no filters selected & filters can be added searchList.addItem().addXref("display-filters", T_filters_show); } addHiddenFormFields("search", request, fqs, mainSearchDiv); if(0 < filterFields.size()) { Division searchFiltersDiv = searchBoxDivision.addInteractiveDivision("search-filters", "discover", Division.METHOD_GET, "discover-filters-box " + (0 < filterTypes.size() ? "" : "hidden")); Division filtersWrapper = searchFiltersDiv.addDivision("discovery-filters-wrapper"); filtersWrapper.setHead(T_filter_label); filtersWrapper.addPara(T_filter_help); Table filtersTable = filtersWrapper.addTable("discovery-filters", 1, 4, "discovery-filters"); //If we have any filters, show them if(filterTypes.size() > 0) { filtersTable.addRow(Row.ROLE_HEADER).addCell("", Cell.ROLE_HEADER, 1, 4, "new-filter-header").addContent(T_filter_current_filters); for (int i = 0; i < filterTypes.size(); i++) { String filterType = filterTypes.get(i); String filterValue = filterValues.get(i); String filterOperator = filterOperators.get(i); if(StringUtils.isNotBlank(filterValue)) { Row row = filtersTable.addRow("used-filters-" + i+1, Row.ROLE_DATA, "search-filter used-filter"); addFilterRow(filterFields, i+1, row, filterType, filterOperator, filterValue); } } filtersTable.addRow("filler-row", Row.ROLE_DATA, "search-filter filler").addCell(1, 4).addContent(""); filtersTable.addRow(Row.ROLE_HEADER).addCell("", Cell.ROLE_HEADER, 1, 4, "new-filter-header").addContent(T_filter_new_filters); } int index = filterTypes.size() + 1; Row row = filtersTable.addRow("filter-new-" + index, Row.ROLE_DATA, "search-filter"); addFilterRow(filterFields, index, row, null, null, null); Row filterControlsItem = filtersTable.addRow("filter-controls", Row.ROLE_DATA, "apply-filter"); // filterControlsItem.addCell(1, 3).addContent(""); filterControlsItem.addCell(1, 4).addButton("submit_apply_filter", "discovery-apply-filter-button").setValue(T_filter_controls_apply); addHiddenFormFields("filter", request, fqs, searchFiltersDiv); } // query.addPara(null, "button-list").addButton("submit").setValue(T_go); // Build the DRI Body //Division results = body.addDivision("results", "primary"); //results.setHead(T_head); buildMainForm(search); // Add the result division try { buildSearchResultsDivision(search); } catch (SearchServiceException e) { throw new UIException(e.getMessage(), e); } } protected void addFilterRow(java.util.List<DiscoverySearchFilter> filterFields, int index, Row row, String selectedFilterType, String relationalOperator, String value) throws WingException { Select select = row.addCell("", Cell.ROLE_DATA, "selection").addSelect("filtertype_" + index); //For each field found (at least one) add options for (DiscoverySearchFilter searchFilter : filterFields) { select.addOption(StringUtils.equals(searchFilter.getIndexFieldName(), selectedFilterType), searchFilter.getIndexFieldName(), message("xmlui.ArtifactBrowser.SimpleSearch.filter." + searchFilter.getIndexFieldName())); } 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); //Add a box so we can search for our value row.addCell("", Cell.ROLE_DATA, "discovery-filter-input-cell").addText("filter_" + index, "discovery-filter-input").setValue(value == null ? "" : value); //And last add an add button Cell buttonsCell = row.addCell("filter-controls_" + index, Cell.ROLE_DATA, "filter-controls"); buttonsCell.addButton("add-filter_" + index, "filter-control filter-add").setValue(T_filter_controls_add); buttonsCell.addButton("remove-filter_" + index, "filter-control filter-remove").setValue(T_filter_controls_remove); } @Override protected String getBasicUrl() throws SQLException { Request request = ObjectModelHelper.getRequest(objectModel); DSpaceObject dso = HandleUtil.obtainHandle(objectModel); return request.getContextPath() + (dso == null ? "" : "/handle/" + dso.getHandle()) + "/discover"; } protected Map<String, String[]> getParameterFilterQueries(){ return DiscoveryUIUtils.getParameterFilterQueries(ObjectModelHelper.getRequest(objectModel)); } /** * Returns all the filter queries for use by discovery * This method returns more expanded filter queries then the getParameterFilterQueries * @return an array containing the filter queries */ protected String[] getFilterQueries() { return DiscoveryUIUtils.getFilterQueries(ObjectModelHelper.getRequest(objectModel), context); } /** * Get the search query from the URL parameter, if none is found the empty * string is returned. */ protected String getQuery() throws UIException { Request request = ObjectModelHelper.getRequest(objectModel); String query = decodeFromURL(request.getParameter("query")); if (query == null) { return ""; } return query.trim(); } /** * Generate a url to the simple search url. */ protected String generateURL(Map<String, String> parameters) throws UIException { String query = getQuery(); if (!"".equals(query) && parameters.get("query") == null) { parameters.put("query", encodeForURL(query)); } if (parameters.get("page") == null) { parameters.put("page", String.valueOf(getParameterPage())); } if (parameters.get("rpp") == null) { parameters.put("rpp", String.valueOf(getParameterRpp())); } if (parameters.get("group_by") == null) { parameters.put("group_by", String.valueOf(this.getParameterGroup())); } if (parameters.get("sort_by") == null && getParameterSortBy() != null) { parameters.put("sort_by", String.valueOf(getParameterSortBy())); } if (parameters.get("order") == null && getParameterOrder() != null) { parameters.put("order", getParameterOrder()); } if (parameters.get("etal") == null) { parameters.put("etal", String.valueOf(getParameterEtAl())); } if(parameters.get("scope") == null && getParameterScope() != null) { parameters.put("scope", getParameterScope()); } return AbstractDSpaceTransformer.generateURL("discover", parameters); } /** * Since the layout is creating separate forms for each search part * this method will add hidden fields containing the values from other form parts * * @param type the type of our form * @param request the request * @param fqs the filter queries * @param division the division that requires the hidden fields * @throws WingException will never occur */ private void addHiddenFormFields(String type, Request request, Map<String, String[]> fqs, Division division) throws WingException { if(type.equals("filter") || type.equals("sort")){ if(request.getParameter("query") != null){ division.addHidden("query").setValue(request.getParameter("query")); } if(request.getParameter("scope") != null){ division.addHidden("scope").setValue(request.getParameter("scope")); } } //Add the filter queries, current search settings so these remain saved when performing a new search ! if(type.equals("search") || type.equals("sort")) { for (String parameter : fqs.keySet()) { String[] values = fqs.get(parameter); for (String value : values) { division.addHidden(parameter).setValue(value); } } } if(type.equals("search") || type.equals("filter")){ if(request.getParameter("rpp") != null){ division.addHidden("rpp").setValue(request.getParameter("rpp")); } if(request.getParameter("sort_by") != null){ division.addHidden("sort_by").setValue(request.getParameter("sort_by")); } if(request.getParameter("order") != null){ division.addHidden("order").setValue(request.getParameter("order")); } } } protected String getSuggestUrl(String newQuery) throws UIException { Map parameters = new HashMap(); parameters.put("query", newQuery); return addFilterQueriesToUrl(generateURL(parameters)); } }