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.runtime.model.type.ModelItemTypeConstants; 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.SitemapElement; 044import org.ametys.web.repository.page.ZoneItem; 045import org.ametys.web.service.ServiceParameter; 046 047/** 048 * {@link SearchComponent} executing in two parts: opening 'search' tag and SAXing general data, then closing 'search' tag. 049 */ 050public class SaxGeneralDataSearchComponent implements SearchComponent, Configurable 051{ 052 private static final String __IS_AJAX_PARAMETER_NAME = "ajax"; 053 054 private int _part; 055 056 @Override 057 public void configure(Configuration configuration) throws ConfigurationException 058 { 059 _part = configuration.getChild("part").getValueAsInteger(); 060 } 061 062 @Override 063 public int priority() 064 { 065 return _part == 1 ? MAX_PRIORITY + 1000 : MIN_PRIORITY - 1000; 066 } 067 068 @Override 069 public boolean supports(SearchComponentArguments args) 070 { 071 return !args.generatorParameters().getParameterAsBoolean(DISABLE_DEFAULT_SAX_PARAMETER_NAME, false); 072 } 073 074 @Override 075 public void execute(SearchComponentArguments args) throws Exception 076 { 077 ContentHandler contentHandler = args.contentHandler(); 078 if (_part == 1) 079 { 080 String currentSiteName = args.currentSite().getName(); 081 String lang = args.currentLang(); 082 SitemapElement page = args.currentPage(); 083 084 AttributesImpl attrs = new AttributesImpl(); 085 attrs.addCDATAAttribute("site", currentSiteName); 086 attrs.addCDATAAttribute("lang", lang); 087 attrs.addCDATAAttribute("ajax", args.generatorParameters().getParameter(__IS_AJAX_PARAMETER_NAME, "false")); 088 089 XMLUtils.startElement(contentHandler, "search", attrs); 090 091 ZoneItem zoneItem = (ZoneItem) args.request().getAttribute(WebConstants.REQUEST_ATTR_ZONEITEM); 092 saxServiceIdentifiers(args, zoneItem); 093 saxCacheable(args, zoneItem); 094 saxAdditionalParameters(args); 095 saxAdditionalInfos(args); 096 097 // The search url 098 String url = lang + "/" + page.getPathInSitemap() + ".html"; 099 if (args.isDebug()) 100 { 101 url = DebugSearchComponent.appendDebugRequestParameters(url, args); 102 } 103 XMLUtils.createElement(contentHandler, "url", url); 104 105 SearchServiceInstance serviceInstance = args.serviceInstance(); 106 ResultDisplay resultDisplay = serviceInstance.getResultDisplay(); 107 // Display the form and results on same page? 108 ResultDisplayType resultDisplayType = resultDisplay.getType(); 109 XMLUtils.createElement(contentHandler, "result-display-type", resultDisplayType.name()); 110 111 XMLUtils.createElement(contentHandler, "header", serviceInstance.getTitle()); 112 XMLUtils.createElement(contentHandler, "result-page", resultDisplayType == ResultDisplayType.ON_PAGE ? resultDisplay.resultPage().get().getId() : ""); 113 XMLUtils.createElement(contentHandler, "compute-counts", Boolean.toString(serviceInstance.computeCriteriaCounts())); 114 XMLUtils.createElement(contentHandler, "launch-search-at-startup", Boolean.toString(resultDisplay.launchSearchAtStartup().orElse(false))); 115 saxRSSFeedURL(contentHandler, serviceInstance, zoneItem); 116 Link link = serviceInstance.getLink(); 117 Optional<Page> linkTarget = link.getTarget(); 118 if (linkTarget.isPresent()) 119 { 120 XMLUtils.startElement(contentHandler, "link"); 121 XMLUtils.createElement(contentHandler, "page", linkTarget.get().getId()); 122 XMLUtils.createElement(contentHandler, "title", link.getTitle()); 123 XMLUtils.endElement(contentHandler, "link"); 124 } 125 } 126 else 127 { 128 XMLUtils.endElement(contentHandler, "search"); 129 } 130 } 131 132 /** 133 * Generate the service identifiers: service group ID, ZoneItem ID, ... 134 * @param args The arguments 135 * @param zoneItem The zone item 136 * @throws SAXException if an error occurs SAXing data. 137 * @throws IOException if an error occurs SAXing data. 138 * @throws ProcessingException if a processing error occurs. 139 */ 140 protected void saxServiceIdentifiers(SearchComponentArguments args, ZoneItem zoneItem) throws SAXException, IOException, ProcessingException 141 { 142 ContentHandler contentHandler = args.contentHandler(); 143 144 String serviceGroupId = args.serviceInstance().getResultDisplay().serviceGroupId(); 145 146 // The service group ID. 147 if (StringUtils.isNotEmpty(serviceGroupId)) 148 { 149 XMLUtils.createElement(contentHandler, "group-id", serviceGroupId); 150 } 151 152 // Generate the ZoneItem ID if it exists. 153 if (zoneItem != null) 154 { 155 AttributesImpl atts = new AttributesImpl(); 156 atts.addCDATAAttribute("id", zoneItem.getId()); 157 XMLUtils.createElement(contentHandler, "zone-item", atts); 158 } 159 } 160 161 /** 162 * Generate the "cacheable" status of the service instance 163 * @param args The arguments 164 * @param zoneItem The zone item 165 * @throws SAXException if an error occurs SAXing data. 166 */ 167 protected void saxCacheable(SearchComponentArguments args, ZoneItem zoneItem) throws SAXException 168 { 169 boolean cacheable = zoneItem == null ? false : args.service().isCacheable(args.currentPage(), zoneItem); 170 XMLUtils.createElement(args.contentHandler(), "cacheable", Boolean.toString(cacheable)); 171 } 172 173 /** 174 * Generate the value of the {@link AdditionalSearchServiceParameter}s 175 * @param args The arguments 176 * @throws SAXException if an error occurs SAXing data. 177 */ 178 protected void saxAdditionalParameters(SearchComponentArguments args) throws SAXException 179 { 180 ContentHandler contentHandler = args.contentHandler(); 181 SearchServiceInstance serviceInstance = args.serviceInstance(); 182 Collection<AdditionalSearchServiceParameter> additionalParameters = serviceInstance.getAdditionalParameters(); 183 AdditionalParameterValueMap additionalParameterValues = serviceInstance.getAdditionalParameterValues(); 184 185 XMLUtils.startElement(contentHandler, "additionalParameters"); 186 for (AdditionalSearchServiceParameter additionalParameter : additionalParameters) 187 { 188 ServiceParameter serviceParameter = additionalParameter.getParameter(); 189 String name = serviceParameter.getName(); 190 if (ModelItemTypeConstants.PASSWORD_ELEMENT_TYPE_ID.equals(serviceParameter.getType().getId())) 191 { 192 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); 193 } 194 else 195 { 196 Object value = additionalParameterValues.getValue(name); 197 XMLUtils.createElement(contentHandler, name, String.valueOf(value)); 198 } 199 } 200 XMLUtils.endElement(contentHandler, "additionalParameters"); 201 } 202 203 /** 204 * Generate any additional information. 205 * @param args The arguments 206 * @throws SAXException if an error occurs SAXing data. 207 * @throws IOException if an error occurs SAXing data. 208 * @throws ProcessingException if a processing error occurs. 209 */ 210 protected void saxAdditionalInfos(SearchComponentArguments args) throws SAXException, IOException, ProcessingException 211 { 212 // Nothing to do here. 213 } 214 215 /** 216 * Generate the URL for RSS feed 217 * @param contentHandler The content handler 218 * @param serviceInstance The service instance 219 * @param zoneItem The zone item 220 * @throws SAXException if an error occurs SAXing data. 221 */ 222 protected void saxRSSFeedURL(ContentHandler contentHandler, SearchServiceInstance serviceInstance, ZoneItem zoneItem) throws SAXException 223 { 224 if (serviceInstance.handleRss() && zoneItem != null) 225 { 226 // Split protocol and id 227 String[] zoneItemId = zoneItem.getId().split("://"); 228 String url = "_plugins/web/" + zoneItemId[0] + "/" + zoneItemId[1] + "/search-rss.xml"; 229 230 XMLUtils.createElement(contentHandler, "RSSFeedURL", url); 231 } 232 } 233}