/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/search/trunk/search-impl/impl/src/java/org/sakaiproject/search/component/Messages.java $ * $Id: Messages.java 59685 2009-04-03 23:36:24Z arwhyte@umich.edu $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Aaron Zeckoski (azeckoski @ gmail.com) (aaronz @ vt.edu) (azeckoski @ unicon.net) **********************************************************************************/ package org.sakaiproject.search.entitybroker; import org.sakaiproject.entitybroker.EntityReference; import org.sakaiproject.entitybroker.EntityView; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction; import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable; import org.sakaiproject.entitybroker.entityprovider.extension.Formats; import org.sakaiproject.entitybroker.entityprovider.search.Restriction; import org.sakaiproject.entitybroker.entityprovider.search.Search; import org.sakaiproject.entitybroker.util.AbstractEntityProvider; import org.sakaiproject.search.api.*; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.user.api.UserDirectoryService; import java.util.*; /** * Entity provider for Entity broker giving access to search services through a an HTTP method * * @author Adrian Fish (a.fish@lancaster.ac.uk) * @author Colin Hebert */ public class SearchEntityProvider extends AbstractEntityProvider implements ActionsExecutable, Outputable, Describeable { private static final int DEFAULT_RESULT_COUNT = 10; private UserDirectoryService userDirectoryService; private SearchService searchService; private SearchIndexBuilder searchIndexBuilder; private SiteService siteService; /** * Name of the service, here "search" * * @return the constant name of this service */ @Override public String getEntityPrefix() { return "search"; } /** * Handled formats, such as JSon and XML * * @return formats supported */ @Override public String[] getHandledOutputFormats() { return new String[]{Formats.JSON, Formats.XML}; } /** * Simple search method * * @param ref * @param search * @return a list of SearchResults */ @EntityCustomAction(action = "search", viewKey = EntityView.VIEW_LIST) public List<SearchResultEntity> search(EntityReference ref, Search search) { try { //Get the query sent by the client String query = extractQuery(search.getRestrictionByProperty("searchTerms")); //Get the list of contexts (sites) used for this search, or every accessible site if the user hasn't provided a context list List<String> contexts = extractContexts(search.getRestrictionByProperty("contexts")); //Set the limit if it hasn't been set already if (search.getLimit() < 0) search.setLimit(DEFAULT_RESULT_COUNT); //Actual search SearchList searchResults = searchService.search(query, contexts, (int) search.getStart(), (int) search.getLimit()); //Transforms SearchResult in a SearchResultEntity to avoid conflicts with the getId() method (see SRCH-85) List<SearchResultEntity> results = new ArrayList<SearchResultEntity>(searchResults.size()); for (SearchResult result : searchResults) { results.add(new SearchResultEntity(result)); } return results; } catch (InvalidSearchQueryException e) { throw new IllegalArgumentException(e); } } /** * Get the list of tools handled by the search engine. * * @return a list of supported tools */ @EntityCustomAction(action = "tools", viewKey = EntityView.VIEW_SHOW) public Set<String> getTools() { List<EntityContentProducer> entityContentProducers = searchIndexBuilder.getContentProducers(); Set<String> tools = new HashSet<String>(entityContentProducers.size()); for (EntityContentProducer entityContentProducer : entityContentProducers) { tools.add(entityContentProducer.getTool()); } return tools; } /** * Extract the query from users parameters * * @param searchTermsRestriction parameter given to EntityBroker * @return A search String * @throws IllegalArgumentException If no query has been provided */ private String extractQuery(Restriction searchTermsRestriction) { if (searchTermsRestriction == null) throw new IllegalArgumentException("No searchTerms supplied"); StringBuilder searchQuery = new StringBuilder(); for (String term : (String[]) searchTermsRestriction.getArrayValue()) { //Concatenate with spaces, if the user wants a coma separated value he can easily enter comas in his query. searchQuery.append(term).append(' '); } return searchQuery.toString(); } /** * Extract contexts from users parameters * * @param contextsRestriction parameter given to EntityBroker * @return A list of contexts (sites) where the search will be done */ private List<String> extractContexts(Restriction contextsRestriction) { List<String> contexts; if (contextsRestriction != null) contexts = Arrays.asList((String[]) contextsRestriction.getArrayValue()); else // No contexts supplied. Get all the sites the current user is a member of contexts = getAllSites(); return contexts; } /** * Get all sites available for the current user * * @return a list of contexts (sites IDs) available for the current user */ private List<String> getAllSites() { List<Site> sites = siteService.getSites(SiteService.SelectionType.ACCESS, null, null, null, null, null); List<String> siteIds = new ArrayList<String>(sites.size()); for (Site site : sites) { if (site != null && site.getId() != null) siteIds.add(site.getId()); } //Manually add the user's site siteIds.add(siteService.getUserSiteId(userDirectoryService.getCurrentUser().getId())); return siteIds; } //-------------------------- //Spring injected components //-------------------------- public void setSearchService(SearchService searchService) { this.searchService = searchService; } public void setSiteService(SiteService siteService) { this.siteService = siteService; } public void setUserDirectoryService(UserDirectoryService userDirectoryService) { this.userDirectoryService = userDirectoryService; } public void setSearchIndexBuilder(SearchIndexBuilder searchIndexBuilder) { this.searchIndexBuilder = searchIndexBuilder; } /** * A wrapper to customise the result sent through EntityBroker * <p> * Wraps a {@link SearchResult} to avoid issues with the {@link org.sakaiproject.search.api.SearchResult#getId()} * method and {@link EntityReference#checkPrefixId(String, String)}.<br /> * Can also filter which parts of the query are accessible to a remote user. * </p> */ public class SearchResultEntity { private final SearchResult searchResult; private SearchResultEntity(SearchResult searchResult) { this.searchResult = searchResult; } public String getReference() { return searchResult.getReference(); } public String getContentId() { return searchResult.getId(); } public float getScore() { return searchResult.getScore(); } public String getSearchResult() { return searchResult.getSearchResult(); } public String getTitle() { return searchResult.getTitle(); } public String getTool() { return searchResult.getTool(); } public String getUrl() { return searchResult.getUrl(); } } }