package nl.gertontenham.magnolia.templating.rendering.components.search; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import info.magnolia.context.MgnlContext; import info.magnolia.jcr.util.ContentMap; import info.magnolia.jcr.util.NodeUtil; import info.magnolia.rendering.model.ModelExecutionFilter; import info.magnolia.rendering.model.RenderingModel; import info.magnolia.rendering.template.RenderableDefinition; import nl.gertontenham.magnolia.templating.functions.FoundationTemplatingFunctions; import nl.gertontenham.magnolia.templating.rendering.ResultsRenderingModel; import nl.gertontenham.magnolia.templating.rendering.components.BaseComponentRenderableDefinition; import nl.gertontenham.magnolia.templating.utils.RenderingUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.servlet.ServletException; import java.util.Set; /** * Search results area renderable definition which can be used as the modelClass for presenting * separate search result components in freemarker template. */ public class ResultsAreaRenderableDefinition<RD extends RenderableDefinition> extends BaseComponentRenderableDefinition<RD> { private static final Logger log = LoggerFactory.getLogger(ResultsAreaRenderableDefinition.class); public static final String SEARCH_RESULT_ATTRIBUTE_PREFIX = ModelExecutionFilter.class.getName() + "-searchResult-"; private static final String QUERY_PARAM = "s"; private static final String PAGE_PARAM = "page"; private static final String CONTENT_PARAM = "content"; private static final String FILTER_PARAM = "filter"; private Multimap<String, String> paramFilter; private RenderingUtils renderingUtils; @Inject public ResultsAreaRenderableDefinition(Node content, RD definition, RenderingModel<?> parent, FoundationTemplatingFunctions templatingFunctions, RenderingUtils renderingUtils) { super(content, definition, parent, templatingFunctions); this.renderingUtils = renderingUtils; paramFilter = LinkedListMultimap.create(); Set<String> parameters = webContext.getParameters().keySet(); for (String parameterKey : parameters) { if (allowedParameters().contains(parameterKey)) { String[] parameterValues = webContext.getParameterValues(parameterKey); for (String parameterValue : parameterValues) { if (StringUtils.isNotEmpty(parameterValue)) { paramFilter.get(parameterKey).add(parameterValue); } } } webContext.remove(parameterKey); } } @Override public String execute() { // Do not cache this response! // More info: http://documentation.magnolia-cms.com/display/DOCS/Cache+module#Cachemodule-Cacheheadernegotiation webContext.getResponse().setHeader("Cache-Control", "no-cache"); return super.execute(); } /** * Get request parameter for search term. * * @return search term */ public String getSearchTerm() { if (paramFilter.containsKey(QUERY_PARAM)) { return paramFilter.get(QUERY_PARAM).iterator().next().replaceAll("'", "''"); } return StringUtils.EMPTY; } /** * Get request parameter for current page. * * @return pagenumber */ public int getPageNumber() { int pageNumber = 1; if (paramFilter.containsKey(PAGE_PARAM)) { pageNumber = Integer.parseInt(paramFilter.get(PAGE_PARAM).iterator().next()); } return pageNumber; } /** * Get total results count of all child components results count * * @return Total result count * @throws RepositoryException */ public int getTotalCount() throws RepositoryException { int grandTotal = 0; for (Node node : NodeUtil.getNodes(content,"mgnl:component")) { grandTotal += getComponentTotal(node); } return grandTotal; } /** * Get total results count for single component. * * @param node * @return total component results count */ public int getComponentTotal(Node node) { int total = 0; ResultsRenderableDefinition model = getComponentModel(node); if (model != null) { model.executeSearch(); try { MgnlContext.setAttribute(SEARCH_RESULT_ATTRIBUTE_PREFIX + node.getIdentifier(), model.getSearchResult()); } catch (RepositoryException e) { log.debug("Error getting node identifier during during set of MgnlContext attribute", e); } total = model.getTotalCount(); } return total; } /** * Get subtitle for single component. * * @param node * @return component subtitle */ public String getComponentSubtitle(Node node) { String subtitle = StringUtils.EMPTY; ResultsRenderableDefinition model = getComponentModel(node); if (model != null) { subtitle = model.getSubtitle(); } return subtitle; } /** * Get total results count for single component. * * @param content * @return total component results count */ public int getComponentTotal(ContentMap content) throws ServletException { return getComponentTotal(content.getJCRNode()); } /** * Get subtitle for single component. * * @param content * @return component subtitle */ public String getComponentSubtitle(ContentMap content) { return getComponentSubtitle(content.getJCRNode()); } /** * Provide whitelisted query-string parameters. * When not in this list, parameters will be ignored. * * @return Set of whitelisted query parameters */ private Set<String> allowedParameters() { return Sets.newHashSet(QUERY_PARAM, PAGE_PARAM, CONTENT_PARAM, FILTER_PARAM); } private ResultsRenderableDefinition getComponentModel(Node node) { ResultsRenderableDefinition model = null; RenderingModel renderingModel = null; try { renderingModel = renderingUtils.getRenderingModel(node); } catch (ServletException e) { log.debug("Error getting node renderingmodel", e); } if (renderingModel instanceof ResultsRenderingModel) { model = ((ResultsRenderableDefinition)renderingModel); } return model; } }