Package org.dspace.app.xmlui.aspect.discovery

Source Code of org.dspace.app.xmlui.aspect.discovery.AbstractSearch

/**
* $Id: AbstractSearch.java 5144 2010-06-22 12:02:05Z benbosman $
* $URL: http://scm.dspace.org/svn/repo/modules/dspace-discovery/trunk/block/src/main/java/org/dspace/app/xmlui/aspect/discovery/AbstractSearch.java $
* *************************************************************************
* Copyright (c) 2002-2009, DuraSpace.  All rights reserved
* Licensed under the DuraSpace License.
*
* A copy of the DuraSpace License has been included in this
* distribution and is available at: http://scm.dspace.org/svn/repo/licenses/LICENSE.txt
*/
package org.dspace.app.xmlui.aspect.discovery;

import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.FieldCollapseResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.dspace.app.xmlui.utils.DSpaceValidity;
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.authorize.AuthorizeException;
import org.dspace.content.*;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.LogManager;
import org.dspace.discovery.*;
import org.dspace.handle.HandleManager;
import org.dspace.sort.SortException;
import org.dspace.sort.SortOption;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.*;
import java.util.List;

/**
* This is an abstract search page. It is a collection of search methods that
* are common between diffrent search implementation. An implementer must
* implement at least three methods: addBody(), getQuery(), and generateURL().
* <p/>
* See the two implementors: SimpleSearch and AdvancedSearch.
*
* @author Scott Phillips
* @author Mark Diggory (mdiggory at atmire.com)
*/
public abstract class AbstractSearch extends AbstractFiltersTransformer {

    private static final Logger log = Logger.getLogger(AbstractSearch.class);


    /**
     * Language strings
     */
    private static final Message T_result_query =
            message("xmlui.ArtifactBrowser.AbstractSearch.result_query");

    private static final Message T_result_empty_query =
            message("xmlui.ArtifactBrowser.AbstractSearch.result_empty_query");

    private static final Message T_head1_community =
            message("xmlui.ArtifactBrowser.AbstractSearch.head1_community");

    private static final Message T_head1_collection =
            message("xmlui.ArtifactBrowser.AbstractSearch.head1_collection");

    private static final Message T_head1_none =
            message("xmlui.ArtifactBrowser.AbstractSearch.head1_none");

    private static final Message T_head2 =
            message("xmlui.ArtifactBrowser.AbstractSearch.head2");

    private static final Message T_head3 =
            message("xmlui.ArtifactBrowser.AbstractSearch.head3");

    private static final Message T_no_results =
            message("xmlui.ArtifactBrowser.AbstractSearch.no_results");

    private static final Message T_all_of_dspace =
            message("xmlui.ArtifactBrowser.AbstractSearch.all_of_dspace");

    private static final Message T_sort_by_relevance =
            message("xmlui.ArtifactBrowser.AbstractSearch.sort_by.relevance");

    private final static Message T_sort_by = message("xmlui.ArtifactBrowser.AbstractSearch.sort_by");

    private final static Message T_order = message("xmlui.ArtifactBrowser.AbstractSearch.order");
    private final static Message T_order_asc = message("xmlui.ArtifactBrowser.AbstractSearch.order.asc");
    private final static Message T_order_desc = message("xmlui.ArtifactBrowser.AbstractSearch.order.desc");

    private final static Message T_rpp = message("xmlui.ArtifactBrowser.AbstractSearch.rpp");

    private final static Message T_group_by = message("xmlui.ArtifactBrowser.AbstractSearch.group_by");

    private static final Message T_group_by_none =
            message("xmlui.ArtifactBrowser.AbstractSearch.group_by.none");

    private final static Message T_view = message("xmlui.ArtifactBrowser.AbstractSearch.view");


    /**
     * The options for results per page
     */
    private static final int[] RESULTS_PER_PAGE_PROGRESSION = {5, 10, 20, 40, 60, 80, 100};

    /**
     * The types of view
     */
    private static final String[] VIEW_TYPES = {"listing", "grid"};

    /**
     * Cached validity object
     */
    private SourceValidity validity;

    /**
     * Generate the unique caching key.
     * This key must be unique inside the space of this component.
     */
    public Serializable getKey() {
        try {
            String key = "";

            // Page Parameter
            Request request = ObjectModelHelper.getRequest(objectModel);
            key += "-" + getParameterPage();
            key += "-" + getParameterView();
            key += "-" + getParameterRpp();
            key += "-" + getParameterSortBy();
            key += "-" + getParameterOrder();
            key += "-" + getParameterEtAl();

            // What scope the search is at
            DSpaceObject scope = getScope();
            if (scope != null)
                key += "-" + scope.getHandle();

            // The actual search query.
            key += "-" + getQuery();

            return HashUtil.hash(key);
        }
        catch (Exception e) {
            // Ignore all errors and just don't cache.
            return "0";
        }
    }

    /**
     * Generate the cache validity object.
     * <p/>
     * This validity object should never "over cache" because it will
     * perform the search, and serialize the results using the
     * DSpaceValidity object.
     */
    public SourceValidity getValidity() {
        if (this.validity == null) {
            try {
                DSpaceValidity validity = new DSpaceValidity();

                DSpaceObject scope = getScope();
                validity.add(scope);

                performSearch(scope);

                SolrDocumentList results = this.queryResults.getResults();

                if (results != null) {
                    validity.add("size:" + results.size());

                    for (SolrDocument result : results) {
                        validity.add(result.toString());
                    }
                }

                this.validity = validity.complete();
            }
            catch (Exception e) {
                // Just ignore all errors and return an invalid cache.
            }

            // add log message that we are viewing the item
            // done here, as the serialization may not occur if the cache is valid
            logSearch();
        }
        return this.validity;
    }


    /**
     * Build the resulting search DRI document.
     */
    @Override
    public abstract void addBody(Body body) throws SAXException, WingException,
            UIException, SQLException, IOException, AuthorizeException;

    /**
     * Attach a division to the given search division named "search-results"
     * which contains results for this search query.
     *
     * @param search The search division to contain the search-results division.
     */
    protected void buildSearchResultsDivision(Division search)
            throws IOException, SQLException, WingException, SearchServiceException {

        try {
            if (queryResults == null || queryResults.getResults() == null) {

                DSpaceObject scope = getScope();
                this.performSearch(scope);
            }
        }
        catch (Throwable t) {
            log.error(t.getMessage(), t);
            queryResults = null;
        }

        if (queryResults != null) {
            if (getQuery().length() > 0) {
                search.addPara("result-query", "result-query").addContent(T_result_query.parameterize(getQuery(), queryResults.getResults().getNumFound()));
            } else {
                search.addPara("result-query", "result-query").addContent(T_result_empty_query.parameterize(queryResults.getResults().getNumFound()));
            }
        }

        // Adding different types of listing (e.g. list, grid).
        String view = this.getParameterView();

        Division results = search.addDivision("search-results", view);

        DSpaceObject searchScope = getScope();

        if (searchScope instanceof Community) {
            Community community = (Community) searchScope;
            String communityName = community.getMetadata("name");
            results.setHead(T_head1_community.parameterize(communityName));
        } else if (searchScope instanceof Collection) {
            Collection collection = (Collection) searchScope;
            String collectionName = collection.getMetadata("name");
            results.setHead(T_head1_collection.parameterize(collectionName));
        } else {
            results.setHead(T_head1_none);
        }

        if (queryResults != null &&
                queryResults.getResults().getNumFound() > 0) {

            SolrDocumentList solrResults = queryResults.getResults();

            // Pagination variables.
            int itemsTotal = (int) solrResults.getNumFound();
            int firstItemIndex = (int) solrResults.getStart() + 1;
            int lastItemIndex = (int) solrResults.getStart() + solrResults.size();

            //if (itemsTotal < lastItemIndex)
            //    lastItemIndex = itemsTotal;
            int currentPage = (int) (solrResults.getStart() / this.queryArgs.getRows()) + 1;
            int pagesTotal = (int) ((solrResults.getNumFound() - 1) / this.queryArgs.getRows()) + 1;
            Map<String, String> parameters = new HashMap<String, String>();
            parameters.put("page", "{pageNum}");
            String pageURLMask = generateURL(parameters);
            //Check for facet queries ? If we have any add them
            String[] fqs = getParameterFacetQueries();
            if(fqs != null){
                for (String fq : fqs) {
                    pageURLMask += "&fq=" + fq;
                }
            }

            results.setMaskedPagination(itemsTotal, firstItemIndex,
                    lastItemIndex, currentPage, pagesTotal, pageURLMask);

            // Look for any communities or collections in the mix
            // UPDATE: mix everything. It's what is expected from a search.
            // UPDATE 2: actually not. Comm/coll should appear separated.
            ReferenceSet referenceSet = null;
            //*
            boolean resultsContainsBothContainersAndItems = false;
            for (SolrDocument doc : solrResults) {
                DSpaceObject resultDSO = SearchUtils.findDSpaceObject(context, doc);

                if (resultDSO instanceof Community || resultDSO instanceof Collection) {
                    if (referenceSet == null) {
                        referenceSet = results.addReferenceSet("search-results-repository",
                                ReferenceSet.TYPE_SUMMARY_LIST, null, "repository-search-results");
                        // Set a heading showing that we will be listing containers that matched:
                        referenceSet.setHead(T_head2);
                        resultsContainsBothContainersAndItems = true;
                    }
                    referenceSet.addReference(resultDSO);
                }
            } //*/

            // Put in palce top level referenceset
            referenceSet = results.addReferenceSet("search-results-repository",
                    ReferenceSet.TYPE_SUMMARY_LIST, null, "repository-search-results");

            for (SolrDocument doc : solrResults) {
                DSpaceObject resultDSO = SearchUtils.findDSpaceObject(context, doc);

                //
                if (resultDSO instanceof Item) {

                    String group_by = this.getParameterGroup();
                    // If we are grouping, attempt to acquire the dc.isPartOf parent of the Item and group on it.
                    // Otherwise, Group on the current Item.
                    // TODO: this is a hack to always make sure any subItem is grouped under its parent
                    if (!group_by.equals("none")) {
                        Item parent = getParent((Item) resultDSO);
                        // if parent not null, use parent otherwise use existing item.
                        if (parent != null) {
                            Reference parentRef = referenceSet.addReference(parent);
                            addCollapsedDocuments(parentRef, parent, doc);
                    } else {
                        referenceSet.addReference(resultDSO);
                        }
                    } else {
                        referenceSet.addReference(resultDSO);
                    }
                //
                }
            }

            // Add hit highlighting information
//            <dri:referenceSet type="hitHighlighting">
//                <dri:reference>
//            </dri:referenceSet>
            /*
            Map<String, Map<String, java.util.List<String>>> hl = queryResults.getHighlighting();
           
            referenceSet = results.addReferenceSet("search-results-repository",
                    ReferenceSet.TYPE_SUMMARY_LIST, null, "repository-hit-highlighting");

             Reference ref = referenceSet.addReference(null);
             */

        } else {
            results.addPara(T_no_results);
        }
        //}// Empty query
    }

    private void addCollapsedDocuments( Reference parentReference, DSpaceObject parent, SolrDocument doc) throws WingException {

        ReferenceSet referenceSet = null;

        // Attach any collapsed groups...
        FieldCollapseResponse.CollapseGroup grp = getCollapseGroup((String) doc.getFieldValue("handle"));

        if (grp != null) {

            for (SolrDocument childDoc : grp.getCollapsedDocuments()) {

                DSpaceObject child = null;
                try {
                    child = SearchUtils.findDSpaceObject(context, childDoc);
                } catch (SQLException e) {
                    log.error(e.getMessage(),e);
                    // TODO:maybe instead of using existing Items, we can use the existing solr record
                    /**
                     * would need to swich reference model to be attribute based rather than element based.
                     *
                     * <referenceSet
                     *      rend="repository-search-results"
                     *      type="summaryList"
                     *      n="search-results-repository"
                     *      id="aspect.artifactbrowser.SimpleSearch.referenceSet.search-results-repository">
                     *      <head>Items matching your query</head>
                     *      <reference repositoryID="123456789" type="DSpace Item" url="/metadata/handle/123456789/53/mets.xml"/>

                     * <list
                     *      rend="repository-search-results"
                     *      type="summaryList"
                     *      n="search-results-repository"
                     *      id="aspect.artifactbrowser.SimpleSearch.referenceSet.search-results-repository">
                     *      <head>Items matching your query</head>
                     *      <item
                     *          repositoryID="123456789"
                     *          type="DSpace Item"
                     *          url="/metadata/handle/123456789/53/mets.xml">
                     *          <xref target="/xmlui/handle/123456789/53">DSUG09 Programme</xref>
                     *          ...
                     *      </item>
                     *
                     * A backward compatable approach would be to loosen the reference and referenceSet classes
                     * to supported nested item list content,
                     *
                     * <referenceSet
                     *      rend="repository-search-results"
                     *      type="summaryList"
                     *      n="search-results-repository"
                     *      id="aspect.artifactbrowser.SimpleSearch.referenceSet.search-results-repository">
                     *      <head>Items matching your query</head>
                     *      <reference repositoryID="123456789" type="DSpace Community" url="/metadata/handle/123456789/53/mets.xml">
                     *          <xref target="/xmlui/handle/123456789/53">DSUG09 Programme</xref>
                     *          ...
                     *      </reference>
                     *
                     * Final objective, to use the the Solr search results to present search result contents rather than
                     * pulling DSpace Item/Community or Item into memory just to render the search results.
                     *
                     */

                }

                // TODO: This is a hack to pull out the parent from the collapsed subItems.
                if (child != null && !child.equals(parent)){
                    if(referenceSet == null)
                        referenceSet = parentReference.addReferenceSet(ReferenceSet.TYPE_SUMMARY_LIST);

                    referenceSet.addReference(child);
                }
            }
        }

    }

    private FieldCollapseResponse.CollapseGroup getCollapseGroup(String field) {


        FieldCollapseResponse cResp = this.queryResults.getFieldCollapseResponse();
        /** make lookup map */
        for (FieldCollapseResponse.CollapseGroup grp : cResp.getCollapseGroups()) {

            String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix");
            if (handlePrefix == null || handlePrefix.length() == 0)
            {
                handlePrefix = "http://hdl.handle.net/";
            }

            String key = grp.getCollapseGroupId().replaceFirst(handlePrefix, "");

            if (key.equals(field)) {
                return grp;
            }

        }

        return null;
    }


    private Item getParent(Item item) {

        String value = getSingleValue(item, "dc.relation.ispartof");

        if (value == null)
            return null;

        try {
            String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix");
            if (handlePrefix == null || handlePrefix.length() == 0)
            {
                handlePrefix = "http://hdl.handle.net/";
            }
           
            DSpaceObject obj = HandleManager.resolveToObject(context, value.replaceFirst(handlePrefix, ""));

            if (obj != null && obj instanceof Item)
                return (Item) obj;
        }
        catch (Exception e) {

        }

        return null;

    }


    private String getSingleValue(Item item, String field) {
        DCValue[] type = item.getMetadata(field);
        if (type != null && type.length > 0 && type[0] != null) {
            return type[0].value;
        }
        return null;
    }


    /**
     * Add options to the search scope field. This field determines in what
     * communities or collections to search for the query.
     * <p/>
     * The scope list will depend upon the current search scope. There are three
     * cases:
     * <p/>
     * No current scope: All top level communities are listed.
     * <p/>
     * The current scope is a community: All collections contained within the
     * community are listed.
     * <p/>
     * The current scope is a collection: All parent communities are listed.
     *
     * @param scope The current scope field.
     */
    protected void buildScopeList(Select scope) throws SQLException,
            WingException {

        DSpaceObject scopeDSO = getScope();
        if (scopeDSO == null) {
            // No scope, display all root level communities
            scope.addOption("/", T_all_of_dspace);
            scope.setOptionSelected("/");
            for (Community community : Community.findAllTop(context)) {
                scope.addOption(community.getHandle(), community.getMetadata("name"));
            }
        } else if (scopeDSO instanceof Community) {
            // The scope is a community, display all collections contained
            // within
            Community community = (Community) scopeDSO;
            scope.addOption("/", T_all_of_dspace);
            scope.addOption(community.getHandle(), community.getMetadata("name"));
            scope.setOptionSelected(community.getHandle());

            for (Collection collection : community.getCollections()) {
                scope.addOption(collection.getHandle(), collection.getMetadata("name"));
            }
        } else if (scopeDSO instanceof Collection) {
            // The scope is a collection, display all parent collections.
            Collection collection = (Collection) scopeDSO;
            scope.addOption("/", T_all_of_dspace);
            scope.addOption(collection.getHandle(), collection.getMetadata("name"));
            scope.setOptionSelected(collection.getHandle());

            Community[] communities = collection.getCommunities()[0]
                    .getAllParents();
            for (Community community : communities) {
                scope.addOption(community.getHandle(), community.getMetadata("name"));
            }
        }
    }

    /**
     * Query DSpace for a list of all items / collections / or communities that
     * match the given search query.
     *
     * @return The associated query results.
     */
    public void performSearch(DSpaceObject scope) throws UIException, SearchServiceException {

        if (queryResults != null)
            return;
       

        String query = getQuery();

        //DSpaceObject scope = getScope();

        int page = getParameterPage();

        queryArgs = this.prepareDefaultFilters("search");


        queryArgs.setRows(getParameterRpp());

        String sortBy = ObjectModelHelper.getRequest(objectModel).getParameter("sort_by");

        String sortOrder = ObjectModelHelper.getRequest(objectModel).getParameter("order");


        //webui.itemlist.sort-option.1 = title:dc.title:title
        //webui.itemlist.sort-option.2 = dateissued:dc.date.issued:date
        //webui.itemlist.sort-option.3 = dateaccessioned:dc.date.accessioned:date
        //webui.itemlist.sort-option.4 = ispartof:dc.relation.ispartof:text

        if (sortBy != null) {
            if (sortOrder == null || sortOrder.equals("DESC"))
                queryArgs.addSortField(sortBy, SolrQuery.ORDER.desc);
            else
                queryArgs.addSortField(sortBy, SolrQuery.ORDER.asc);
        } else {
            queryArgs.addSortField("score", SolrQuery.ORDER.asc);
        }


        String groupBy = ObjectModelHelper.getRequest(objectModel).getParameter("group_by");


        // Enable groupBy collapsing if designated
        if (groupBy != null && !groupBy.equalsIgnoreCase("none")) {
            /** Construct a Collapse Field Query */
            queryArgs.add("collapse.field", groupBy);
            queryArgs.add("collapse.threshold", "1");
            queryArgs.add("collapse.includeCollapsedDocs.fl", "handle");
            queryArgs.add("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.addSortField("dc.type", SolrQuery.ORDER.asc);

        }


        queryArgs.setQuery(query != null && !query.trim().equals("") ? query : "*:*");

        if (page > 1)
            queryArgs.setStart((page - 1) * queryArgs.getRows());
        else
            queryArgs.setStart(0);


        List<String> filterQueries = new ArrayList<String>();

        String[] fqs = getParameterFacetQueries();
        if (fqs != null)
            filterQueries.addAll(Arrays.asList(fqs));

        queryArgs.add("f.location.facet.mincount", "0");
        queryArgs.add("f.location.facet.limit", "-1");

        if (scope instanceof Community) {
            filterQueries.add("{!tag=loc}location:m" + scope.getID());
        } else if (scope instanceof Collection) {
            filterQueries.add("{!tag=loc}location:l" + scope.getID());
        }

        if (filterQueries.size() > 0) {
            queryArgs.addFilterQuery(filterQueries.toArray(new String[filterQueries.size()]));
        }


        // Use mlt
        /*
         queryArgs.add("mlt", "true");

        // The fields to use for similarity. NOTE: if possible, these should have a stored TermVector
         queryArgs.add("mlt.fl", "author");

        // Minimum Term Frequency - the frequency below which terms will be ignored in the source doc.
         queryArgs.add("mlt.mintf", "1");

        // Minimum Document Frequency - the frequency at which words will be ignored which do not occur in at least this many docs.
         queryArgs.add("mlt.mindf", "1");

        queryArgs.add("mlt.q", "");
        */

        // mlt.minwl
        // minimum word length below which words will be ignored.

        // mlt.maxwl
        // maximum word length above which words will be ignored.

        // mlt.maxqt
        // maximum number of query terms that will be included in any generated query.

        // mlt.maxntp
        // maximum number of tokens to parse in each example doc field that is not stored with TermVector support.

        // mlt.boost
        // [true/false] set if the query will be boosted by the interesting term relevance.

        // mlt.qf
        // Query fields and their boosts using the same format as that used in DisMaxRequestHandler. These fields must also be specified in mlt.fl.


        //filePost.addParameter("fl", "handle, "search.resourcetype")");
        //filePost.addParameter("field", "search.resourcetype");

        //Set the default limit to 11
        /*
        ClientUtils.escapeQueryChars(location)
        //f.category.facet.limit=5

        for(Enumeration en = request.getParameterNames(); en.hasMoreElements();)
        {
          String key = (String)en.nextElement();
          if(key.endsWith(".facet.limit"))
          {
            filePost.addParameter(key, request.getParameter(key));
          }
        }
        */

        log.debug("queryArgs: " + queryArgs.toString());
        this.queryResults = getSearchService().search(queryArgs);
    }

    /**
     * Determine the current scope. This may be derived from the current url
     * handle if present or the scope parameter is given. If no scope is
     * specified then null is returned.
     *
     * @return The current scope.
     */
    protected DSpaceObject getScope() throws SQLException {
        Request request = ObjectModelHelper.getRequest(objectModel);
        String scopeString = request.getParameter("scope");

        // Are we in a community or collection?
        DSpaceObject dso;
        if (scopeString == null || "".equals(scopeString))
            // get the search scope from the url handle
            dso = HandleUtil.obtainHandle(objectModel);
        else
            // Get the search scope from the location parameter
            dso = HandleManager.resolveToObject(context, scopeString);

        return dso;
    }

    protected String[] getParameterFacetQueries() {
        try {
            return ObjectModelHelper.getRequest(objectModel).getParameterValues("fq");
        }
        catch (Exception e) {
            return null;
        }
    }

    protected String[] getFacetsList() {
        try {
            return ObjectModelHelper.getRequest(objectModel).getParameterValues("fl");
        }
        catch (Exception e) {
            return null;
        }
    }

    protected int getParameterPage() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("page"));
        }
        catch (Exception e) {
            return 1;
        }
    }

    protected String getParameterView() {
        String s = ObjectModelHelper.getRequest(objectModel).getParameter("view");
        return s != null ? s : VIEW_TYPES[0];
    }

    protected int getParameterRpp() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("rpp"));
        }
        catch (Exception e) {
            return 10;
        }
    }

    protected String getParameterSortBy() {
        String s = ObjectModelHelper.getRequest(objectModel).getParameter("sort_by");
        return s != null ? s : "score";
    }

    protected String getParameterGroup() {
        String s = ObjectModelHelper.getRequest(objectModel).getParameter("group_by");
        return s != null ? s : "none";
    }

    protected String getParameterOrder() {
        String s = ObjectModelHelper.getRequest(objectModel).getParameter("order");
        return s != null ? s : "DESC";
    }

    protected int getParameterEtAl() {
        try {
            return Integer.parseInt(ObjectModelHelper.getRequest(objectModel).getParameter("etal"));
        }
        catch (Exception e) {
            return 0;
        }
    }

    /**
     * Determine if the scope of the search should fixed or is changeable by the
     * user.
     * <p/>
     * The search scope when preformed by url, i.e. they are at the url handle/xxxx/xx/search
     * then it is fixed. However at the global level the search is variable.
     *
     * @return true if the scope is variable, false otherwise.
     */
    protected boolean variableScope() throws SQLException {
        if (HandleUtil.obtainHandle(objectModel) == null)
            return true;
        else
            return false;
    }

    /**
     * Extract the query string. Under most implementations this will be derived
     * from the url parameters.
     *
     * @return The query string.
     */
    abstract protected String getQuery() throws UIException;

    /**
     * Generate a url to the given search implementation with the associated
     * parameters included.
     *
     * @param parameters
     * @return The post URL
     */
    abstract protected String generateURL(Map<String, String> parameters)
            throws UIException;


    /**
     * Recycle
     */
    public void recycle() {
        this.validity = null;
        super.recycle();
    }


    protected void buildSearchControls(Division div)
            throws WingException {

        //Table controlsTable = div.addTable("search-controls", 1, 3);
        Table controlsTable = div.addTable("search-controls", 1, 4);
        Row controlsRow = controlsTable.addRow(Row.ROLE_DATA);

        // Create a control for the type of view to display
        Cell viewCell = controlsRow.addCell();
        try {
            viewCell.addContent(T_view);
            Select viewSelect = viewCell.addSelect("view");
            for (String v : VIEW_TYPES) {
                viewSelect.addOption((v.equals(getParameterView())), v, message("xmlui.ArtifactBrowser.AbstractSearch.view." + v));
            }
        }
        catch (Exception e) {
            throw new WingException("Unable to get view options", e);
        }

        // Create a control for the number of records to display
        Cell rppCell = controlsRow.addCell();
        rppCell.addContent(T_rpp);
        Select rppSelect = rppCell.addSelect("rpp");
        for (int i : RESULTS_PER_PAGE_PROGRESSION) {
            rppSelect.addOption((i == getParameterRpp()), i, Integer.toString(i));
        }

        /*
        Cell groupCell = controlsRow.addCell();
        try {
            // Create a drop down of the different sort columns available
            groupCell.addContent(T_group_by);
            Select groupSelect = groupCell.addSelect("group_by");
            groupSelect.addOption(false, "none", T_group_by_none);

           
            String[] groups = {"publication_grp"};
            for (String group : groups) {
                groupSelect.addOption(group.equals(getParameterGroup()), group,
                        message("xmlui.ArtifactBrowser.AbstractSearch.group_by." + group));
            }

        }
        catch (Exception se) {
            throw new WingException("Unable to get group options", se);
        }
        */
       
        Cell sortCell = controlsRow.addCell();
        try {
            // Create a drop down of the different sort columns available
            sortCell.addContent(T_sort_by);
            Select sortSelect = sortCell.addSelect("sort_by");
            sortSelect.addOption(false, "score", T_sort_by_relevance);
            for (SortOption so : SortOption.getSortOptions()) {
                if (so.isVisible()) {
                    sortSelect.addOption((so.getMetadata().equals(getParameterSortBy())), so.getMetadata(),
                            message("xmlui.ArtifactBrowser.AbstractSearch.sort_by." + so.getName()));
                }
            }
        }
        catch (SortException se) {
            throw new WingException("Unable to get sort options", se);
        }

        // Create a control to changing ascending / descending order
        Cell orderCell = controlsRow.addCell();
        orderCell.addContent(T_order);
        Select orderSelect = orderCell.addSelect("order");
        orderSelect.addOption(SortOption.ASCENDING.equals(getParameterOrder()), SortOption.ASCENDING, T_order_asc);
        orderSelect.addOption(SortOption.DESCENDING.equals(getParameterOrder()), SortOption.DESCENDING, T_order_desc);


        // Create a control for the number of authors per item to display
        // FIXME This is currently disabled, as the supporting functionality
        // is not currently present in xmlui
        //if (isItemBrowse(info))
        //{
        //    controlsForm.addContent(T_etal);
        //    Select etalSelect = controlsForm.addSelect(BrowseParams.ETAL);
        //
        //    etalSelect.addOption((info.getEtAl() < 0), 0, T_etal_all);
        //    etalSelect.addOption(1 == info.getEtAl(), 1, Integer.toString(1));
        //
        //    for (int i = 5; i <= 50; i += 5)
        //    {
        //        etalSelect.addOption(i == info.getEtAl(), i, Integer.toString(i));
        //    }
        //}
    }

    protected void logSearch() {
        int countCommunities = 0;
        int countCollections = 0;
        int countItems = 0;

        /**
         * TODO: Maybe we can create a default "type" facet for this
         * will give results for Items, Communities and Collection types
         * benefits... no iteration over results at all to sum types
         * leaves it upto solr...

         for (Object type : queryResults.getHitTypes())
         {
         if (type instanceof Integer)
         {
         switch (((Integer)type).intValue())
         {
         case Constants.ITEM:       countItems++;        break;
         case Constants.COLLECTION: countCollections++;  break;
         case Constants.COMMUNITY:  countCommunities++;  break;
         }
         }
         }
         */
        String logInfo = "";

        try {
            DSpaceObject dsoScope = getScope();

            if (dsoScope instanceof Collection) {
                logInfo = "collection_id=" + dsoScope.getID() + ",";
            } else if (dsoScope instanceof Community) {
                logInfo = "community_id=" + dsoScope.getID() + ",";
            }
        }
        catch (SQLException sqle) {
            // Ignore, as we are only trying to get the scope to add detail to the log message
        }

        log.info(LogManager.getHeader(context, "search", logInfo + "query=\""
                + queryArgs.getQuery() + "\",results=(" + countCommunities + ","
                + countCollections + "," + countItems + ")"));
    }
}
TOP

Related Classes of org.dspace.app.xmlui.aspect.discovery.AbstractSearch

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.