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