/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library 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 library 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. */ package com.liferay.portal.search.web.internal.search.results.portlet; import com.liferay.asset.kernel.service.AssetEntryLocalService; import com.liferay.portal.kernel.dao.search.DisplayTerms; import com.liferay.portal.kernel.dao.search.SearchContainer; import com.liferay.portal.kernel.language.Language; import com.liferay.portal.kernel.portlet.LiferayPortletRequest; import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet; import com.liferay.portal.kernel.search.Document; import com.liferay.portal.kernel.search.QueryConfig; import com.liferay.portal.kernel.security.permission.ResourceActions; import com.liferay.portal.kernel.theme.ThemeDisplay; import com.liferay.portal.kernel.util.Http; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.search.web.internal.display.context.PortletURLFactory; import com.liferay.portal.search.web.internal.display.context.PortletURLFactoryImpl; import com.liferay.portal.search.web.internal.display.context.SearchResultPreferences; import com.liferay.portal.search.web.internal.document.DocumentFormPermissionChecker; import com.liferay.portal.search.web.internal.document.DocumentFormPermissionCheckerImpl; import com.liferay.portal.search.web.internal.portlet.shared.search.NullPortletURL; import com.liferay.portal.search.web.internal.portlet.shared.task.PortletSharedRequestHelper; import com.liferay.portal.search.web.internal.result.display.builder.SearchResultSummaryDisplayBuilder; import com.liferay.portal.search.web.internal.result.display.context.SearchResultSummaryDisplayContext; import com.liferay.portal.search.web.internal.search.results.constants.SearchResultsPortletKeys; import com.liferay.portal.search.web.internal.search.results.constants.SearchResultsWebKeys; import com.liferay.portal.search.web.portlet.shared.search.PortletSharedSearchContributor; import com.liferay.portal.search.web.portlet.shared.search.PortletSharedSearchRequest; import com.liferay.portal.search.web.portlet.shared.search.PortletSharedSearchResponse; import com.liferay.portal.search.web.portlet.shared.search.PortletSharedSearchSettings; import com.liferay.portal.search.web.search.result.SearchResultImageContributor; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import javax.portlet.Portlet; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.servlet.http.HttpServletRequest; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; /** * @author André de Oliveira */ @Component( immediate = true, property = { "com.liferay.portlet.add-default-resource=true", "com.liferay.portlet.css-class-wrapper=portlet-search-results", "com.liferay.portlet.display-category=category.search", "com.liferay.portlet.icon=/icons/search.png", "com.liferay.portlet.instanceable=true", "com.liferay.portlet.layout-cacheable=true", "com.liferay.portlet.preferences-owned-by-group=true", "com.liferay.portlet.private-request-attributes=false", "com.liferay.portlet.private-session-attributes=false", "com.liferay.portlet.restore-current-view=false", "com.liferay.portlet.use-default-template=true", "javax.portlet.display-name=Search Results", "javax.portlet.expiration-cache=0", "javax.portlet.init-param.template-path=/", "javax.portlet.init-param.view-template=/search/results/view.jsp", "javax.portlet.name=" + SearchResultsPortletKeys.SEARCH_RESULTS, "javax.portlet.resource-bundle=content.Language", "javax.portlet.security-role-ref=guest,power-user,user", "javax.portlet.supports.mime-type=text/html" }, service = {Portlet.class, PortletSharedSearchContributor.class} ) public class SearchResultsPortlet extends MVCPortlet implements PortletSharedSearchContributor { @Override public void contribute( PortletSharedSearchSettings portletSharedSearchSettings) { SearchResultsPortletPreferences searchResultsPortletPreferences = new SearchResultsPortletPreferencesImpl( portletSharedSearchSettings.getPortletPreferences()); paginate(searchResultsPortletPreferences, portletSharedSearchSettings); highlight(searchResultsPortletPreferences, portletSharedSearchSettings); } @Override public void render( RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { PortletSharedSearchResponse portletSharedSearchResponse = portletSharedSearchRequest.search(renderRequest); SearchResultsPortletDisplayContext searchResultsPortletDisplayContext = buildDisplayContext( portletSharedSearchResponse, renderRequest, renderResponse); renderRequest.setAttribute( SearchResultsWebKeys.DISPLAY_CONTEXT, searchResultsPortletDisplayContext); super.render(renderRequest, renderResponse); } @Reference( cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC ) protected void addSearchResultImageContributor( SearchResultImageContributor searchResultImageContributor) { _searchResultImageContributors.add(searchResultImageContributor); } protected SearchResultsPortletDisplayContext buildDisplayContext( PortletSharedSearchResponse portletSharedSearchResponse, RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException { SearchResultsPortletDisplayContext searchResultsPortletDisplayContext = new SearchResultsPortletDisplayContext(); searchResultsPortletDisplayContext.setDocuments( portletSharedSearchResponse.getDocuments()); Optional<String> keywordsOptional = portletSharedSearchResponse.getKeywords(); searchResultsPortletDisplayContext.setKeywords( keywordsOptional.orElse(StringPool.BLANK)); boolean renderNothing = false; if (!keywordsOptional.isPresent()) { renderNothing = true; } searchResultsPortletDisplayContext.setRenderNothing(renderNothing); SearchResultsPortletPreferences searchResultsPortletPreferences = new SearchResultsPortletPreferencesImpl( portletSharedSearchResponse.getPortletPreferences( renderRequest)); searchResultsPortletDisplayContext.setSearchContainer( buildSearchContainer( portletSharedSearchResponse.getDocuments(), portletSharedSearchResponse.getTotalHits(), portletSharedSearchResponse.getPaginationStart(), searchResultsPortletPreferences. getPaginationStartParameterName(), portletSharedSearchResponse.getPaginationDelta(), searchResultsPortletPreferences. getPaginationDeltaParameterName(), renderRequest)); searchResultsPortletDisplayContext.setSearchResultsSummariesHolder( buildSummaries( portletSharedSearchResponse, renderRequest, renderResponse)); searchResultsPortletDisplayContext.setTotalHits( portletSharedSearchResponse.getTotalHits()); return searchResultsPortletDisplayContext; } protected SearchContainer<Document> buildSearchContainer( List<Document> documents, int totalHits, int paginationStart, String paginationStartParameterName, int paginationDelta, String paginationDeltaParameterName, RenderRequest renderRequest) throws PortletException { PortletRequest portletRequest = renderRequest; DisplayTerms displayTerms = null; DisplayTerms searchTerms = null; String curParam = paginationStartParameterName; int cur = paginationStart; int delta = paginationDelta; PortletURL portletURL = getPortletURL( renderRequest, paginationStartParameterName, paginationDeltaParameterName); List<String> headerNames = null; String emptyResultsMessage = null; String cssClass = null; SearchContainer<Document> searchContainer = new SearchContainer<>( portletRequest, displayTerms, searchTerms, curParam, cur, delta, portletURL, headerNames, emptyResultsMessage, cssClass); searchContainer.setDeltaParam(paginationDeltaParameterName); searchContainer.setResults(documents); searchContainer.setTotal(totalHits); return searchContainer; } protected SearchResultsSummariesHolder buildSummaries( PortletSharedSearchResponse portletSharedSearchResponse, RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException { try { return doBuildSummaries( portletSharedSearchResponse, renderRequest, renderResponse); } catch (PortletException pe) { throw pe; } catch (RuntimeException re) { throw re; } catch (Exception e) { throw new PortletException(e); } } protected SearchResultsSummariesHolder doBuildSummaries( PortletSharedSearchResponse portletSharedSearchResponse, RenderRequest renderRequest, RenderResponse renderResponse) throws Exception { SearchResultsPortletPreferences searchResultsPortletPreferences = new SearchResultsPortletPreferencesImpl( portletSharedSearchResponse.getPortletPreferences( renderRequest)); ThemeDisplay themeDisplay = portletSharedSearchResponse.getThemeDisplay( renderRequest); DocumentFormPermissionChecker documentFormPermissionChecker = new DocumentFormPermissionCheckerImpl(themeDisplay); List<Document> documents = portletSharedSearchResponse.getDocuments(); SearchResultsSummariesHolder searchResultsSummariesHolder = new SearchResultsSummariesHolder(documents.size()); PortletURLFactory portletURLFactory = new PortletURLFactoryImpl( renderRequest, renderResponse); SearchResultPreferences searchResultPreferences = new SearchResultPreferencesImpl( searchResultsPortletPreferences, documentFormPermissionChecker); for (Document document : documents) { SearchResultSummaryDisplayContext searchResultSummaryDisplayContext = doBuildSummary( document, portletSharedSearchResponse, renderRequest, renderResponse, themeDisplay, portletURLFactory, searchResultsPortletPreferences, searchResultPreferences); searchResultsSummariesHolder.put( document, searchResultSummaryDisplayContext); } return searchResultsSummariesHolder; } protected SearchResultSummaryDisplayContext doBuildSummary( Document document, PortletSharedSearchResponse portletSharedSearchResponse, RenderRequest renderRequest, RenderResponse renderResponse, ThemeDisplay themeDisplay, PortletURLFactory portletURLFactory, SearchResultsPortletPreferences searchResultsPortletPreferences, SearchResultPreferences searchResultPreferences) throws Exception { SearchResultSummaryDisplayBuilder searchResultSummaryDisplayBuilder = new SearchResultSummaryDisplayBuilder(); PortletURL portletURL = portletURLFactory.getPortletURL(); searchResultSummaryDisplayBuilder.setAssetEntryLocalService( assetEntryLocalService); searchResultSummaryDisplayBuilder.setCurrentURL(portletURL.toString()); searchResultSummaryDisplayBuilder.setDocument(document); searchResultSummaryDisplayBuilder.setHighlightEnabled( searchResultsPortletPreferences.isHighlightEnabled()); searchResultSummaryDisplayBuilder.setImageRequested(true); searchResultSummaryDisplayBuilder.setLanguage(language); searchResultSummaryDisplayBuilder.setLocale(themeDisplay.getLocale()); searchResultSummaryDisplayBuilder.setPortletURLFactory( portletURLFactory); searchResultSummaryDisplayBuilder.setQueryTerms( portletSharedSearchResponse.getHighlights()); searchResultSummaryDisplayBuilder.setRenderRequest(renderRequest); searchResultSummaryDisplayBuilder.setRenderResponse(renderResponse); searchResultSummaryDisplayBuilder.setRequest( getHttpServletRequest(renderRequest)); searchResultSummaryDisplayBuilder.setResourceActions(resourceActions); searchResultSummaryDisplayBuilder. setSearchResultImageContributorsStream( _searchResultImageContributors.stream()); searchResultSummaryDisplayBuilder.setSearchResultPreferences( searchResultPreferences); searchResultSummaryDisplayBuilder.setThemeDisplay(themeDisplay); return searchResultSummaryDisplayBuilder.build(); } protected HttpServletRequest getHttpServletRequest( RenderRequest renderRequest) { LiferayPortletRequest liferayPortletRequest = (LiferayPortletRequest)renderRequest; return liferayPortletRequest.getHttpServletRequest(); } protected PortletURL getPortletURL( RenderRequest renderRequest, String paginationStartParameterName, String paginationDeltaParameterName) { final String urlString = getURLString( renderRequest, paginationStartParameterName, paginationDeltaParameterName); return new NullPortletURL() { @Override public String toString() { return urlString; } }; } protected String getURLString( RenderRequest renderRequest, String paginationStartParameterName, String paginationDeltaParameterName) { String urlString = portletSharedRequestHelper.getCompleteURL( renderRequest); urlString = _http.removeParameter( urlString, paginationDeltaParameterName); urlString = _http.removeParameter( urlString, paginationStartParameterName); return urlString; } protected void highlight( SearchResultsPortletPreferences searchResultsPortletPreferences, PortletSharedSearchSettings portletSharedSearchSettings) { boolean highlightEnabled = searchResultsPortletPreferences.isHighlightEnabled(); QueryConfig queryConfig = portletSharedSearchSettings.getQueryConfig(); queryConfig.setHighlightEnabled(highlightEnabled); } protected void paginate( SearchResultsPortletPreferences searchResultsPortletPreferences, PortletSharedSearchSettings portletSharedSearchSettings) { String paginationStartParameterName = searchResultsPortletPreferences.getPaginationStartParameterName(); portletSharedSearchSettings.setPaginationStartParameterName( paginationStartParameterName); Optional<String> paginationStartParameterValueOptional = portletSharedSearchSettings.getParameter( paginationStartParameterName); Optional<Integer> paginationStartOptional = paginationStartParameterValueOptional.map(Integer::valueOf); paginationStartOptional.ifPresent( portletSharedSearchSettings::setPaginationStart); String paginationDeltaParameterName = searchResultsPortletPreferences.getPaginationDeltaParameterName(); Optional<String> paginationDeltaParameterValueOptional = portletSharedSearchSettings.getParameter( paginationDeltaParameterName); Optional<Integer> paginationDeltaOptional = paginationDeltaParameterValueOptional.map(Integer::valueOf); int paginationDelta = paginationDeltaOptional.orElse( searchResultsPortletPreferences.getPaginationDelta()); portletSharedSearchSettings.setPaginationDelta(paginationDelta); } protected void removeSearchResultImageContributor( SearchResultImageContributor searchResultImageContributor) { _searchResultImageContributors.remove(searchResultImageContributor); } @Reference protected AssetEntryLocalService assetEntryLocalService; @Reference protected Language language; @Reference protected PortletSharedRequestHelper portletSharedRequestHelper; @Reference protected PortletSharedSearchRequest portletSharedSearchRequest; @Reference protected ResourceActions resourceActions; @Reference private Http _http; private final Set<SearchResultImageContributor> _searchResultImageContributors = new HashSet<>(); }