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