org.xwiki.rest.resources.BaseSearchResult.java Source code

Java tutorial

Introduction

Here is the source code for org.xwiki.rest.resources.BaseSearchResult.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xwiki.rest.resources;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriBuilderException;

import org.apache.commons.lang3.StringUtils;
import org.xwiki.query.Query;
import org.xwiki.query.QueryException;
import org.xwiki.rest.Relations;
import org.xwiki.rest.Utils;
import org.xwiki.rest.XWikiResource;
import org.xwiki.rest.model.jaxb.Link;
import org.xwiki.rest.model.jaxb.SearchResult;
import org.xwiki.rest.resources.objects.ObjectResource;
import org.xwiki.rest.resources.pages.PageResource;
import org.xwiki.rest.resources.pages.PageTranslationResource;
import org.xwiki.rest.resources.spaces.SpaceResource;

import com.xpn.xwiki.XWikiException;

/**
 * @version $Id: de3a9f00a8a86615b2421b06770ca62e65ef3c93 $
 */
public class BaseSearchResult extends XWikiResource {
    protected static final String SEARCH_TEMPLATE_INFO = "q={keywords}(&scope={content|name|title|spaces|objects})*";

    protected static enum SearchScope {
        SPACES, NAME, CONTENT, TITLE, OBJECTS
    }

    /**
     * Search for keyword in the given scopes. See {@link SearchScope} for more information.
     * 
     * @param searchScopes
     * @param keywords
     * @param wikiName
     * @param space
     * @param hasProgrammingRights
     * @param number
     * @return
     * @throws IllegalArgumentException
     * @throws UriBuilderException
     * @throws QueryException
     * @throws XWikiException
     */
    protected List<SearchResult> search(List<SearchScope> searchScopes, String keywords, String wikiName,
            String space, boolean hasProgrammingRights, int number)
            throws IllegalArgumentException, UriBuilderException, QueryException, XWikiException {
        String database = Utils.getXWikiContext(componentManager).getDatabase();

        /* This try is just needed for executing the finally clause. */
        try {
            Utils.getXWikiContext(componentManager).setDatabase(wikiName);

            List<SearchResult> result = new ArrayList<SearchResult>();

            result.addAll(searchPages(searchScopes, keywords, wikiName, space, hasProgrammingRights, number));

            if (searchScopes.contains(SearchScope.SPACES)) {
                result.addAll(searchSpaces(keywords, wikiName, hasProgrammingRights, number));
            }

            if (searchScopes.contains(SearchScope.OBJECTS)) {
                result.addAll(searchObjects(keywords, wikiName, space, hasProgrammingRights, number));
            }

            return result;
        } finally {
            Utils.getXWikiContext(componentManager).setDatabase(database);
        }
    }

    /**
     * Search for keyword in the given scopes. Limit the search only to Pages. Search for keyword
     * 
     * @param searchScopes
     * @param keywords
     * @param wikiName
     * @param space
     * @param hasProgrammingRights
     * @param number
     * @return
     * @throws QueryException
     * @throws IllegalArgumentException
     * @throws UriBuilderException
     * @throws XWikiException
     */
    protected List<SearchResult> searchPages(List<SearchScope> searchScopes, String keywords, String wikiName,
            String space, boolean hasProgrammingRights, int number)
            throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException {
        String database = Utils.getXWikiContext(componentManager).getDatabase();

        /* This try is just needed for executing the finally clause. */
        try {
            List<SearchResult> result = new ArrayList<SearchResult>();

            if (keywords == null) {
                return result;
            }

            Formatter f = new Formatter();

            if (space != null) {
                f.format(
                        "select distinct doc.fullName, doc.space, doc.name, doc.language from XWikiDocument as doc where doc.space = :space and ( ");
            } else {
                f.format(
                        "select distinct doc.fullName, doc.space, doc.name, doc.language from XWikiDocument as doc where ( ");
            }

            /* Look for scopes related to pages */
            int acceptedScopes = 0;
            for (int i = 0; i < searchScopes.size(); i++) {
                SearchScope scope = searchScopes.get(i);

                switch (scope) {
                case CONTENT:
                    f.format("upper(doc.content) like :keywords ");
                    acceptedScopes++;
                    break;
                case NAME:
                    f.format("upper(doc.fullName) like :keywords ");
                    acceptedScopes++;
                    break;
                case TITLE:
                    f.format("upper(doc.title) like :keywords ");
                    acceptedScopes++;
                    break;
                }

                if (i != searchScopes.size() - 1) {
                    f.format(" or ");
                }
            }

            /* If we don't find any scope related to pages then return empty results */
            if (acceptedScopes == 0) {
                return result;
            }

            if (hasProgrammingRights) {
                f.format(") order by doc.fullName asc");
            } else {
                f.format(
                        ") and doc.space<>'XWiki' and doc.space<>'Admin' and doc.space<>'Panels' and doc.name<>'WebPreferences' order by doc.fullName asc");
            }

            String query = f.toString();

            List<Object> queryResult = null;

            /* This is needed because if the :space placeholder is not in the query, setting it would cause an exception */
            if (space != null) {
                queryResult = queryManager.createQuery(query, Query.XWQL)
                        .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase()))
                        .bindValue("space", space).setLimit(number).execute();
            } else {
                queryResult = queryManager.createQuery(query, Query.XWQL)
                        .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase())).setLimit(number)
                        .execute();
            }

            for (Object object : queryResult) {
                Object[] fields = (Object[]) object;

                String spaceName = (String) fields[1];
                String pageName = (String) fields[2];
                String language = (String) fields[3];

                String pageId = Utils.getPageId(wikiName, spaceName, pageName);

                if (Utils.getXWikiApi(componentManager).hasAccessLevel("view", pageId)) {
                    SearchResult searchResult = objectFactory.createSearchResult();
                    searchResult.setType("page");
                    searchResult.setId(pageId);
                    searchResult.setPageFullName(Utils.getPageFullName(wikiName, spaceName, pageName));
                    searchResult.setWiki(wikiName);
                    searchResult.setSpace(spaceName);
                    searchResult.setPageName(pageName);

                    String pageUri = null;
                    try {
                        if (StringUtils.isBlank(language)) {
                            pageUri = UriBuilder.fromUri(this.uriInfo.getBaseUri()).path(PageResource.class)
                                    .buildFromEncoded(URLEncoder.encode(wikiName, "UTF-8"),
                                            URLEncoder.encode(spaceName, "UTF-8"),
                                            URLEncoder.encode(pageName, "UTF-8"))
                                    .toString();
                        } else {
                            searchResult.setLanguage(language);
                            pageUri = UriBuilder.fromUri(this.uriInfo.getBaseUri())
                                    .path(PageTranslationResource.class)
                                    .buildFromEncoded(URLEncoder.encode(wikiName, "UTF-8"),
                                            URLEncoder.encode(spaceName, "UTF-8"),
                                            URLEncoder.encode(pageName, "UTF-8"), language)
                                    .toString();
                        }
                    } catch (UnsupportedEncodingException ex) {
                        // This should never happen, UTF-8 is always valid.
                    }

                    Link pageLink = new Link();
                    pageLink.setHref(pageUri);
                    pageLink.setRel(Relations.PAGE);
                    searchResult.getLinks().add(pageLink);

                    result.add(searchResult);
                }
            }

            return result;
        } finally {
            Utils.getXWikiContext(componentManager).setDatabase(database);
        }
    }

    /**
     * Search for keyword in the given scopes. Limit the search only to Pages. Search for keyword
     * 
     * @param searchScopes
     * @param keywords
     * @param wikiName
     * @param space
     * @param hasProgrammingRights
     * @param number
     * @return
     * @throws QueryException
     * @throws IllegalArgumentException
     * @throws UriBuilderException
     * @throws XWikiException
     */
    protected List<SearchResult> searchSpaces(String keywords, String wikiName, boolean hasProgrammingRights,
            int number) throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException {
        String database = Utils.getXWikiContext(componentManager).getDatabase();

        /* This try is just needed for executing the finally clause. */
        try {
            List<SearchResult> result = new ArrayList<SearchResult>();

            if (keywords == null) {
                return result;
            }

            Formatter f = new Formatter();

            f.format("select distinct doc.space from XWikiDocument as doc where upper(doc.space) like :keywords ");

            if (hasProgrammingRights) {
                f.format(" order by doc.space asc");
            } else {
                f.format(
                        " and doc.space<>'XWiki' and doc.space<>'Admin' and doc.space<>'Panels' order by doc.space asc");
            }

            String query = f.toString();

            List<Object> queryResult = null;
            queryResult = queryManager.createQuery(query, Query.XWQL)
                    .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase())).setLimit(number)
                    .execute();

            for (Object object : queryResult) {

                String spaceName = (String) object;

                SearchResult searchResult = objectFactory.createSearchResult();
                searchResult.setType("space");
                searchResult.setId(String.format("%s:%s", wikiName, spaceName));
                searchResult.setWiki(wikiName);
                searchResult.setSpace(spaceName);

                /* Add a link to the space information */
                Link spaceLink = new Link();
                spaceLink.setRel(Relations.SPACE);
                String spaceUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(SpaceResource.class)
                        .build(wikiName, spaceName).toString();
                spaceLink.setHref(spaceUri);
                searchResult.getLinks().add(spaceLink);

                /* Add a link to the webhome if it exists */
                String webHomePageId = Utils.getPageId(wikiName, spaceName, "WebHome");
                if (Utils.getXWikiApi(componentManager).exists(webHomePageId)
                        && Utils.getXWikiApi(componentManager).hasAccessLevel("view", webHomePageId)) {
                    String pageUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(PageResource.class)
                            .build(wikiName, spaceName, "WebHome").toString();

                    Link pageLink = new Link();
                    pageLink.setHref(pageUri);
                    pageLink.setRel(Relations.HOME);
                    searchResult.getLinks().add(pageLink);
                }

                result.add(searchResult);
            }

            return result;
        } finally {
            Utils.getXWikiContext(componentManager).setDatabase(database);
        }
    }

    /**
     * Search for keyword in the given scopes. Limit the search only to Objects.
     * 
     * @param keywords
     * @param wikiName
     * @param space
     * @param hasProgrammingRights
     * @param number
     * @return
     * @throws QueryException
     * @throws IllegalArgumentException
     * @throws UriBuilderException
     * @throws XWikiException
     */
    protected List<SearchResult> searchObjects(String keywords, String wikiName, String space,
            boolean hasProgrammingRights, int number)
            throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException {
        String database = Utils.getXWikiContext(componentManager).getDatabase();

        /* This try is just needed for executing the finally clause. */
        try {
            List<SearchResult> result = new ArrayList<SearchResult>();

            if (keywords == null) {
                return result;
            }

            Formatter f = new Formatter();

            if (space != null) {
                f.format(
                        "select distinct doc.fullName, doc.space, doc.name, obj.className, obj.number from XWikiDocument as doc, BaseObject as obj, StringProperty as sp, LargeStringProperty as lsp where doc.space = :space and obj.name=doc.fullName and sp.id.id = obj.id and lsp.id.id = obj.id and (upper(sp.value) like :keywords or upper(lsp.value) like :keywords) ");
            } else {
                f.format(
                        "select distinct doc.fullName, doc.space, doc.name, obj.className, obj.number from XWikiDocument as doc, BaseObject as obj, StringProperty as sp, LargeStringProperty as lsp where obj.name=doc.fullName and sp.id.id = obj.id and lsp.id.id = obj.id and (upper(sp.value) like :keywords or upper(lsp.value) like :keywords) ");
            }

            if (hasProgrammingRights) {
                f.format(" order by doc.fullName asc");
            } else {
                f.format(
                        " and doc.space<>'XWiki' and doc.space<>'Admin' and doc.space<>'Panels' and doc.name<>'WebPreferences' order by doc.fullName asc");
            }

            String query = f.toString();

            List<Object> queryResult = null;

            /* This is needed because if the :space placeholder is not in the query, setting it would cause an exception */
            if (space != null) {
                queryResult = queryManager.createQuery(query, Query.XWQL)
                        .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase()))
                        .bindValue("space", space).setLimit(number).execute();
            } else {
                queryResult = queryManager.createQuery(query, Query.XWQL)
                        .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase())).setLimit(number)
                        .execute();
            }

            for (Object object : queryResult) {
                Object[] fields = (Object[]) object;

                String spaceName = (String) fields[1];
                String pageName = (String) fields[2];
                String className = (String) fields[3];
                int objectNumber = (Integer) fields[4];

                String id = Utils.getObjectId(wikiName, spaceName, pageName, className, objectNumber);

                String pageId = Utils.getPageId(wikiName, spaceName, pageName);
                if (Utils.getXWikiApi(componentManager).hasAccessLevel("view", pageId)) {
                    SearchResult searchResult = objectFactory.createSearchResult();
                    searchResult.setType("object");
                    searchResult.setId(id);
                    searchResult.setPageFullName(Utils.getPageFullName(wikiName, spaceName, pageName));
                    searchResult.setWiki(wikiName);
                    searchResult.setSpace(spaceName);
                    searchResult.setPageName(pageName);
                    searchResult.setClassName(className);
                    searchResult.setObjectNumber(objectNumber);

                    String pageUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(PageResource.class)
                            .build(wikiName, spaceName, pageName).toString();
                    Link pageLink = new Link();
                    pageLink.setHref(pageUri);
                    pageLink.setRel(Relations.PAGE);
                    searchResult.getLinks().add(pageLink);

                    String objectUri = UriBuilder.fromUri(uriInfo.getBaseUri()).path(ObjectResource.class)
                            .build(wikiName, spaceName, pageName, className, objectNumber).toString();
                    Link objectLink = new Link();
                    objectLink.setHref(objectUri);
                    objectLink.setRel(Relations.OBJECT);
                    searchResult.getLinks().add(objectLink);

                    result.add(searchResult);
                }
            }

            return result;
        } finally {
            Utils.getXWikiContext(componentManager).setDatabase(database);
        }
    }

    /**
     * Return a list of {@link SearchScope} objects by parsing the strings provided in the search scope strings. If the
     * list doesn't contain any valid scope string, then CONTENT is added by default.
     * 
     * @param searchScopeStrings The list of string to be parsed.
     * @return The list of the parsed SearchScope elements.
     */
    protected List<SearchScope> parseSearchScopeStrings(List<String> searchScopeStrings) {
        List<SearchScope> searchScopes = new ArrayList<SearchScope>();
        for (String searchScopeString : searchScopeStrings) {
            if (searchScopeString != null && !searchScopes.contains(searchScopeString)) {
                try {
                    SearchScope searchScope = SearchScope.valueOf(searchScopeString.toUpperCase());
                    searchScopes.add(searchScope);
                } catch (IllegalArgumentException e) {
                    // Ignore unrecognized scopes
                }
            }
        }

        if (searchScopes.isEmpty()) {
            searchScopes.add(SearchScope.CONTENT);
        }

        return searchScopes;
    }

}