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}