001/*
002 *  Copyright 2016 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.cms.search.solr;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.apache.avalon.framework.context.Context;
026import org.apache.avalon.framework.context.ContextException;
027import org.apache.avalon.framework.context.Contextualizable;
028import org.apache.avalon.framework.parameters.Parameters;
029import org.apache.avalon.framework.service.ServiceException;
030import org.apache.avalon.framework.service.ServiceManager;
031import org.apache.cocoon.ProcessingException;
032import org.apache.cocoon.acting.ServiceableAction;
033import org.apache.cocoon.environment.ObjectModelHelper;
034import org.apache.cocoon.environment.Redirector;
035import org.apache.cocoon.environment.Request;
036import org.apache.cocoon.environment.SourceResolver;
037import org.apache.commons.lang3.StringUtils;
038
039import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
040import org.ametys.cms.search.QueryBuilder;
041import org.ametys.cms.search.query.Query;
042import org.ametys.cms.search.ui.model.DynamicWrappedSearchUIModel;
043import org.ametys.cms.search.ui.model.SearchUIColumn;
044import org.ametys.cms.search.ui.model.SearchUICriterion;
045import org.ametys.cms.search.ui.model.SearchUIModel;
046import org.ametys.cms.search.ui.model.SearchUIModelExtensionPoint;
047import org.ametys.cms.search.ui.model.impl.IndexingFieldSearchUICriterion;
048import org.ametys.cms.search.ui.model.impl.MetadataSearchUIColumn;
049import org.ametys.cms.search.ui.model.impl.SystemSearchUIColumn;
050import org.ametys.cms.search.ui.model.impl.SystemSearchUICriterion;
051import org.ametys.core.cocoon.JSonReader;
052import org.ametys.core.util.AvalonLoggerAdapter;
053import org.ametys.core.util.ServerCommHelper;
054
055/**
056 * Get a solr query string from a search tool.
057 */
058public class GetSolrQueryAction extends ServiceableAction implements Contextualizable
059{
060    
061    /** The search model manager */
062    protected SearchUIModelExtensionPoint _searchModelManager;
063    /** The ContentType Manager*/
064    protected ContentTypeExtensionPoint _contentTypeExtensionPoint;
065    /** The server comm helper */
066    protected ServerCommHelper _serverCommHelper;
067    /** The avalon context */
068    protected Context _context;
069    
070    /** The query builder. */
071    protected QueryBuilder _queryBuilder;
072    
073    @Override
074    public void contextualize(Context context) throws ContextException
075    {
076        _context = context;
077    }
078    
079    @Override
080    public void service(ServiceManager smanager) throws ServiceException
081    {
082        super.service(smanager);
083        _searchModelManager = (SearchUIModelExtensionPoint) smanager.lookup(SearchUIModelExtensionPoint.ROLE);
084        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE);
085        _serverCommHelper = (ServerCommHelper) smanager.lookup(ServerCommHelper.ROLE);
086        
087        _queryBuilder = (QueryBuilder) smanager.lookup(QueryBuilder.ROLE);
088    }
089    
090    @Override
091    @SuppressWarnings ("unchecked")
092    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
093    {
094        Request request = ObjectModelHelper.getRequest(objectModel);
095        
096        Map<String, Object> queryResults = new HashMap<>();
097        request.setAttribute(JSonReader.OBJECT_TO_READ, queryResults);
098        
099        Map<String, Object> jsParameters = _serverCommHelper.getJsParameters();
100        
101        String modelId = (String) jsParameters.get("id");
102        
103        List<String> restrictedContentTypes = (List<String>) jsParameters.get("restrictedContentTypes");
104        Map<String, Object> contextualParameters = (Map<String, Object>) jsParameters.get("contextualParameters");
105        
106        if (contextualParameters == null)
107        {
108            contextualParameters = new HashMap<> ();
109        }
110        
111        SearchUIModel model = _searchModelManager.getExtension(modelId);
112        if (restrictedContentTypes != null)
113        {
114            model = new DynamicWrappedSearchUIModel(model, restrictedContentTypes, _contentTypeExtensionPoint, new AvalonLoggerAdapter(getLogger())   , _context,  manager);
115        }
116        
117        try
118        {
119            Map<String, Object> values = (Map<String, Object>) jsParameters.get("values");
120            String searchMode = StringUtils.defaultString((String) jsParameters.get("searchMode"), "simple");
121            
122            Query query = _queryBuilder.build(model, searchMode, values, contextualParameters);
123            
124            // Set the query string into the results.
125            queryResults.put("query", query.build());
126            
127            // Get the model content types and set them into the results.
128            Set<String> contentTypes = model.getContentTypes(contextualParameters);
129            queryResults.put("contentTypes", contentTypes);
130            
131            // Get the model facets and set them into the results.
132            Map<String, SearchUICriterion> facetedCriteria = model.getFacetedCriteria(contextualParameters);
133            setFacets(queryResults, facetedCriteria.values());
134            
135            // Get the model facets and set them into the results.
136            Map<String, SearchUIColumn> resultFields = model.getResultFields(contextualParameters);
137            setColumns(queryResults, resultFields.values());
138        }
139        catch (Exception e)
140        {
141            getLogger().error("Cannot get solr query string: " + e.getMessage(), e);
142            throw new ProcessingException("Cannot get solr query string: " + e.getMessage(), e);
143        }
144        
145        return EMPTY_MAP;
146    }
147
148    /**
149     * Set the facet list into the query results.
150     * @param queryResults the query results.
151     * @param facetedCriteria the facets to put in the results.
152     */
153    protected void setFacets(Map<String, Object> queryResults, Collection<SearchUICriterion> facetedCriteria)
154    {
155        List<String> facets = new ArrayList<>();
156        queryResults.put("facets", facets);
157        
158        for (SearchUICriterion criterion : facetedCriteria)
159        {
160            if (criterion instanceof IndexingFieldSearchUICriterion)
161            {
162                facets.add(((IndexingFieldSearchUICriterion) criterion).getFieldPath());
163            }
164            else if (criterion instanceof SystemSearchUICriterion)
165            {
166                facets.add(((SystemSearchUICriterion) criterion).getSystemPropertyId());
167            }
168            else
169            {
170                facets.add(criterion.getId());
171            }
172        }
173    }
174
175    /**
176     * Set the column list into the query results.
177     * @param queryResults the query results.
178     * @param columns the columns to put in the results.
179     */
180    protected void setColumns(Map<String, Object> queryResults, Collection<SearchUIColumn> columns)
181    {
182        List<String> columnIds = new ArrayList<>();
183        queryResults.put("columns", columnIds);
184        
185        for (SearchUIColumn column : columns)
186        {
187            if (column instanceof MetadataSearchUIColumn)
188            {
189                columnIds.add(((MetadataSearchUIColumn) column).getFieldPath());
190            }
191            else if (column instanceof SystemSearchUIColumn)
192            {
193                columnIds.add(((SystemSearchUIColumn) column).getSystemPropertyId());
194            }
195        }
196    }
197    
198}