001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.web.frontoffice.search.requesttime.impl; 017 018import java.io.IOException; 019import java.util.Collection; 020import java.util.Optional; 021 022import org.apache.avalon.framework.configuration.Configurable; 023import org.apache.avalon.framework.configuration.Configuration; 024import org.apache.avalon.framework.configuration.ConfigurationException; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.xml.AttributesImpl; 027import org.apache.cocoon.xml.XMLUtils; 028import org.apache.commons.lang.StringUtils; 029import org.xml.sax.ContentHandler; 030import org.xml.sax.SAXException; 031 032import org.ametys.cms.data.type.impl.PasswordRepositoryElementType; 033import org.ametys.web.WebConstants; 034import org.ametys.web.frontoffice.search.instance.SearchServiceInstance; 035import org.ametys.web.frontoffice.search.instance.model.Link; 036import org.ametys.web.frontoffice.search.instance.model.ResultDisplay; 037import org.ametys.web.frontoffice.search.instance.model.ResultDisplayType; 038import org.ametys.web.frontoffice.search.metamodel.AdditionalParameterValueMap; 039import org.ametys.web.frontoffice.search.metamodel.AdditionalSearchServiceParameter; 040import org.ametys.web.frontoffice.search.requesttime.SearchComponent; 041import org.ametys.web.frontoffice.search.requesttime.SearchComponentArguments; 042import org.ametys.web.repository.page.Page; 043import org.ametys.web.repository.page.ZoneItem; 044import org.ametys.web.service.ServiceParameter; 045 046/** 047 * {@link SearchComponent} executing in two parts: opening 'search' tag and SAXing general data, then closing 'search' tag. 048 */ 049public class SaxGeneralDataSearchComponent implements SearchComponent, Configurable 050{ 051 private static final String __IS_AJAX_PARAMETER_NAME = "ajax"; 052 053 private int _part; 054 055 @Override 056 public void configure(Configuration configuration) throws ConfigurationException 057 { 058 _part = configuration.getChild("part").getValueAsInteger(); 059 } 060 061 @Override 062 public int priority() 063 { 064 return _part == 1 ? MAX_PRIORITY + 1000 : MIN_PRIORITY - 1000; 065 } 066 067 @Override 068 public boolean supports(SearchComponentArguments args) 069 { 070 return !args.generatorParameters().getParameterAsBoolean(DISABLE_DEFAULT_SAX_PARAMETER_NAME, false); 071 } 072 073 @Override 074 public void execute(SearchComponentArguments args) throws Exception 075 { 076 ContentHandler contentHandler = args.contentHandler(); 077 if (_part == 1) 078 { 079 String currentSiteName = args.currentSite().getName(); 080 String lang = args.currentLang(); 081 Page page = args.currentPage(); 082 083 AttributesImpl attrs = new AttributesImpl(); 084 attrs.addCDATAAttribute("site", currentSiteName); 085 attrs.addCDATAAttribute("lang", lang); 086 attrs.addCDATAAttribute("ajax", args.generatorParameters().getParameter(__IS_AJAX_PARAMETER_NAME, "false")); 087 088 XMLUtils.startElement(contentHandler, "search", attrs); 089 090 ZoneItem zoneItem = (ZoneItem) args.request().getAttribute(WebConstants.REQUEST_ATTR_ZONEITEM); 091 saxServiceIdentifiers(args, zoneItem); 092 saxCacheable(args, zoneItem); 093 saxAdditionalParameters(args); 094 saxAdditionalInfos(args); 095 096 // The search url 097 String url = lang + "/" + page.getPathInSitemap() + ".html"; 098 if (args.isDebug()) 099 { 100 url = DebugSearchComponent.appendDebugRequestParameters(url, args); 101 } 102 XMLUtils.createElement(contentHandler, "url", url); 103 104 SearchServiceInstance serviceInstance = args.serviceInstance(); 105 ResultDisplay resultDisplay = serviceInstance.getResultDisplay(); 106 // Display the form and results on same page? 107 ResultDisplayType resultDisplayType = resultDisplay.getType(); 108 XMLUtils.createElement(contentHandler, "result-display-type", resultDisplayType.name()); 109 110 XMLUtils.createElement(contentHandler, "header", serviceInstance.getTitle()); 111 XMLUtils.createElement(contentHandler, "result-page", resultDisplayType == ResultDisplayType.ON_PAGE ? resultDisplay.resultPage().get().getId() : ""); 112 XMLUtils.createElement(contentHandler, "compute-counts", Boolean.toString(serviceInstance.computeCriteriaCounts())); 113 XMLUtils.createElement(contentHandler, "launch-search-at-startup", Boolean.toString(resultDisplay.launchSearchAtStartup().orElse(false))); 114 saxRSSFeedURL(contentHandler, serviceInstance, zoneItem); 115 Link link = serviceInstance.getLink(); 116 Optional<Page> linkTarget = link.getTarget(); 117 if (linkTarget.isPresent()) 118 { 119 XMLUtils.startElement(contentHandler, "link"); 120 XMLUtils.createElement(contentHandler, "page", linkTarget.get().getId()); 121 XMLUtils.createElement(contentHandler, "title", link.getTitle()); 122 XMLUtils.endElement(contentHandler, "link"); 123 } 124 } 125 else 126 { 127 XMLUtils.endElement(contentHandler, "search"); 128 } 129 } 130 131 /** 132 * Generate the service identifiers: service group ID, ZoneItem ID, ... 133 * @param args The arguments 134 * @param zoneItem The zone item 135 * @throws SAXException if an error occurs SAXing data. 136 * @throws IOException if an error occurs SAXing data. 137 * @throws ProcessingException if a processing error occurs. 138 */ 139 protected void saxServiceIdentifiers(SearchComponentArguments args, ZoneItem zoneItem) throws SAXException, IOException, ProcessingException 140 { 141 ContentHandler contentHandler = args.contentHandler(); 142 143 String serviceGroupId = args.serviceInstance().getResultDisplay().serviceGroupId(); 144 145 // The service group ID. 146 if (StringUtils.isNotEmpty(serviceGroupId)) 147 { 148 XMLUtils.createElement(contentHandler, "group-id", serviceGroupId); 149 } 150 151 // Generate the ZoneItem ID if it exists. 152 if (zoneItem != null) 153 { 154 AttributesImpl atts = new AttributesImpl(); 155 atts.addCDATAAttribute("id", zoneItem.getId()); 156 XMLUtils.createElement(contentHandler, "zone-item", atts); 157 } 158 } 159 160 /** 161 * Generate the "cacheable" status of the service instance 162 * @param args The arguments 163 * @param zoneItem The zone item 164 * @throws SAXException if an error occurs SAXing data. 165 */ 166 protected void saxCacheable(SearchComponentArguments args, ZoneItem zoneItem) throws SAXException 167 { 168 boolean cacheable = zoneItem == null ? false : args.service().isCacheable(args.currentPage(), zoneItem); 169 XMLUtils.createElement(args.contentHandler(), "cacheable", Boolean.toString(cacheable)); 170 } 171 172 /** 173 * Generate the value of the {@link AdditionalSearchServiceParameter}s 174 * @param args The arguments 175 * @throws SAXException if an error occurs SAXing data. 176 */ 177 protected void saxAdditionalParameters(SearchComponentArguments args) throws SAXException 178 { 179 ContentHandler contentHandler = args.contentHandler(); 180 SearchServiceInstance serviceInstance = args.serviceInstance(); 181 Collection<AdditionalSearchServiceParameter> additionalParameters = serviceInstance.getAdditionalParameters(); 182 AdditionalParameterValueMap additionalParameterValues = serviceInstance.getAdditionalParameterValues(); 183 184 XMLUtils.startElement(contentHandler, "additionalParameters"); 185 for (AdditionalSearchServiceParameter additionalParameter : additionalParameters) 186 { 187 ServiceParameter serviceParameter = additionalParameter.getParameter(); 188 String name = serviceParameter.getName(); 189 if (PasswordRepositoryElementType.TYPE_ID.equals(serviceParameter.getType().getId())) 190 { 191 args.logger().info("Additional parameter value for '{}' will not be saxed because it is a password and it is probably not meant for the view.", name); 192 } 193 else 194 { 195 Object value = additionalParameterValues.getValue(name); 196 XMLUtils.createElement(contentHandler, name, String.valueOf(value)); 197 } 198 } 199 XMLUtils.endElement(contentHandler, "additionalParameters"); 200 } 201 202 /** 203 * Generate any additional information. 204 * @param args The arguments 205 * @throws SAXException if an error occurs SAXing data. 206 * @throws IOException if an error occurs SAXing data. 207 * @throws ProcessingException if a processing error occurs. 208 */ 209 protected void saxAdditionalInfos(SearchComponentArguments args) throws SAXException, IOException, ProcessingException 210 { 211 // Nothing to do here. 212 } 213 214 /** 215 * Generate the URL for RSS feed 216 * @param contentHandler The content handler 217 * @param serviceInstance The service instance 218 * @param zoneItem The zone item 219 * @throws SAXException if an error occurs SAXing data. 220 */ 221 protected void saxRSSFeedURL(ContentHandler contentHandler, SearchServiceInstance serviceInstance, ZoneItem zoneItem) throws SAXException 222 { 223 if (serviceInstance.handleRss() && zoneItem != null) 224 { 225 // Split protocol and id 226 String[] zoneItemId = zoneItem.getId().split("://"); 227 String url = "_plugins/web/" + zoneItemId[0] + "/" + zoneItemId[1] + "/search-rss.xml"; 228 229 XMLUtils.createElement(contentHandler, "RSSFeedURL", url); 230 } 231 } 232}