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.metamodel.impl;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.Collections;
021import java.util.List;
022import java.util.Optional;
023import java.util.function.Function;
024import java.util.stream.Collectors;
025
026import org.apache.avalon.framework.configuration.Configurable;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.avalon.framework.service.Serviceable;
032import org.apache.commons.collections4.CollectionUtils;
033
034import org.ametys.cms.content.ContentHelper;
035import org.ametys.cms.contenttype.ContentTypesHelper;
036import org.ametys.cms.contenttype.MetadataManager;
037import org.ametys.cms.search.query.AndQuery;
038import org.ametys.cms.search.query.ContentTypeQuery;
039import org.ametys.cms.search.query.DocumentTypeQuery;
040import org.ametys.cms.search.query.Query;
041import org.ametys.runtime.i18n.I18nizableText;
042import org.ametys.web.frontoffice.search.instance.model.SearchContext.LangQueryProducer;
043import org.ametys.web.frontoffice.search.metamodel.AdditionalParameterValueMap;
044import org.ametys.web.frontoffice.search.metamodel.FacetDefinition;
045import org.ametys.web.frontoffice.search.metamodel.Returnable;
046import org.ametys.web.frontoffice.search.metamodel.ReturnableExtensionPoint;
047import org.ametys.web.frontoffice.search.metamodel.ReturnableSaxer;
048import org.ametys.web.frontoffice.search.metamodel.SortDefinition;
049import org.ametys.web.frontoffice.search.metamodel.context.ContextQueriesWrapper;
050import org.ametys.web.indexing.solr.SolrWebFieldNames;
051import org.ametys.web.repository.page.Page;
052import org.ametys.web.repository.site.SiteManager;
053import org.ametys.web.search.query.PageContentQuery;
054import org.ametys.web.search.query.SitemapQuery;
055
056/**
057 * {@link Returnable} for {@link Page}s
058 */
059public class PageReturnable implements Returnable, Serviceable, Configurable
060{
061    /** Avalon Role */
062    public static final String ROLE = PageReturnable.class.getName();
063    
064    /** The prefix for the ids of facets and sorts */
065    protected static final String __PREFIX_ID = "PageReturnable$";
066    
067    /** The sites manager */
068    protected SiteManager _siteManager;
069    /** The content returnable */
070    protected Returnable _contentReturnable;
071    
072    /** The helper to handler content types */
073    protected ContentTypesHelper _contentTypesHelper;
074    /** The helper to handler contents */
075    protected ContentHelper _contentHelper;
076    /** Metadata manager. */
077    protected MetadataManager _metadataManager;
078    /** The service manager. */
079    protected ServiceManager _manager;
080    
081    /** The label */
082    protected I18nizableText _label;
083    /** The saxer */
084    protected ReturnableSaxer _saxer;
085    
086    
087    @Override
088    public void service(ServiceManager manager) throws ServiceException
089    {
090        _manager = manager;
091        _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE);
092        ReturnableExtensionPoint resultTypeEP = (ReturnableExtensionPoint) manager.lookup(ReturnableExtensionPoint.ROLE);
093        _contentReturnable = resultTypeEP.getExtension(ContentReturnable.ROLE);
094        
095        _contentTypesHelper = (ContentTypesHelper) manager.lookup(ContentTypesHelper.ROLE);
096        _contentHelper = (ContentHelper) manager.lookup(ContentHelper.ROLE);
097        _metadataManager = (MetadataManager) manager.lookup(MetadataManager.ROLE);
098    }
099    
100    @Override
101    public void configure(Configuration configuration) throws ConfigurationException
102    {
103        _label = I18nizableText.parseI18nizableText(configuration.getChild("label"), "plugin.web");
104    }
105    
106    @Override
107    public String getId()
108    {
109        return ROLE;
110    }
111    
112    @Override
113    public I18nizableText getLabel()
114    {
115        return _label;
116    }
117    
118    @Override
119    public boolean selectedByDefault()
120    {
121        return true;
122    }
123    
124    @Override
125    public Query filterReturnedDocumentQuery(Collection<ContextQueriesWrapper> contextQueriesWrappers, AdditionalParameterValueMap additionalParameterValues)
126    {
127        Collection<String> contentTypes = additionalParameterValues.getValue(ContentSearchable.PARAMETER_CONTENT_TYPES);
128        
129        // site property is indexed on page documents
130        Function<Query, Query> siteQueryJoiner = Function.identity();
131        // A SitemapQuery is on pages
132        Function<Query, Query> sitemapQueryJoiner = Function.identity();
133        // lang query
134        LangQueryProducer langQueryProducer = new LangQueryProducer(SitemapQuery.class, false);
135        // tag query is on contents => ignore it by passing an empty optional
136        Query pageContextQuery = ContextQueriesWrapper.getQuery(contextQueriesWrappers, Optional.of(siteQueryJoiner), Optional.of(sitemapQueryJoiner), Optional.of(langQueryProducer), Optional.empty());
137        
138        List<Query> queries = new ArrayList<>();
139        queries.add(new DocumentTypeQuery(SolrWebFieldNames.TYPE_PAGE));
140        if (CollectionUtils.isNotEmpty(contentTypes))
141        {
142            queries.add(new PageContentQuery(new ContentTypeQuery(contentTypes)));
143        }
144        queries.add(pageContextQuery);
145        return new AndQuery(queries);
146    }
147    
148    @Override
149    public ReturnableSaxer getSaxer(Collection<Returnable> allReturnables, AdditionalParameterValueMap additionalParameterValues)
150    {
151        if (_saxer == null)
152        {
153            _saxer = new PageSaxer(this);
154        }
155        return _saxer;
156    }
157    
158    @Override
159    public Collection<FacetDefinition> getFacets(AdditionalParameterValueMap additionalParameterValues)
160    {
161        Collection<FacetDefinition> contentFacets = _contentReturnable.getFacets(additionalParameterValues);
162        Collection<FacetDefinition> facetDefs = contentFacets.stream()
163                .filter(ContentFacetDefinition.class::isInstance)
164                .map(ContentFacetDefinition.class::cast)
165                .map(contentFacetDefinition -> new PageContentFacetDefinition(contentFacetDefinition, this))
166                .collect(Collectors.toList());
167        
168        return facetDefs;
169    }
170    
171    @Override
172    public Collection<SortDefinition> getSorts(AdditionalParameterValueMap additionalParameterValues)
173    {
174        return Collections.emptySet();
175    }
176}