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.explorer;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.cocoon.ProcessingException;
026import org.apache.cocoon.environment.ObjectModelHelper;
027import org.apache.cocoon.environment.Request;
028import org.apache.cocoon.xml.XMLUtils;
029import org.apache.commons.lang.StringUtils;
030import org.apache.solr.client.solrj.util.ClientUtils;
031import org.xml.sax.SAXException;
032
033import org.ametys.cms.content.indexing.solr.SolrFieldNames;
034import org.ametys.cms.search.Sort;
035import org.ametys.cms.search.Sort.Order;
036import org.ametys.cms.search.filter.AccessSearchFilter;
037import org.ametys.cms.search.query.AndQuery;
038import org.ametys.cms.search.query.DocumentTypeQuery;
039import org.ametys.cms.search.query.DublinCoreQuery;
040import org.ametys.cms.search.query.FilenameQuery;
041import org.ametys.cms.search.query.FullTextQuery;
042import org.ametys.cms.search.query.OrQuery;
043import org.ametys.cms.search.query.Query;
044import org.ametys.cms.search.query.Query.Operator;
045import org.ametys.cms.search.query.QuerySyntaxException;
046import org.ametys.cms.search.query.ResourceLocationQuery;
047import org.ametys.cms.search.query.UsersQuery;
048import org.ametys.cms.search.solr.SearcherFactory;
049import org.ametys.core.user.UserIdentity;
050import org.ametys.core.util.JSONUtils;
051import org.ametys.plugins.core.user.UserHelper;
052import org.ametys.plugins.explorer.ExplorerNode;
053import org.ametys.plugins.explorer.resources.Resource;
054import org.ametys.plugins.explorer.resources.generators.SearchGenerator;
055import org.ametys.plugins.repository.AmetysObjectIterable;
056
057/**
058 * Search resources in a specific explorer node.
059 */
060public class SearchResourcesGenerator extends SearchGenerator
061{
062    /** The searcher factory. */
063    protected SearcherFactory _searcherFactory;
064    
065    /** The JSON utils */
066    protected JSONUtils _jsonUtils;
067    
068    /** The user helper */
069    protected UserHelper _userHelper;
070    
071    @Override
072    public void service(ServiceManager sManager) throws ServiceException
073    {
074        super.service(sManager);
075        _searcherFactory = (SearcherFactory) sManager.lookup(SearcherFactory.ROLE);
076        _jsonUtils = (JSONUtils) sManager.lookup(JSONUtils.ROLE);
077        _userHelper = (UserHelper) manager.lookup(UserHelper.ROLE);
078    }
079    
080    @Override
081    public void generate() throws IOException, SAXException, ProcessingException
082    {
083        Request request = ObjectModelHelper.getRequest(objectModel);
084        
085        String id = request.getParameter("id");
086        String rootId = request.getParameter("rootId");
087        ExplorerNode node = _resolver.resolveById(id);
088        
089        Query query = getQuery(request, node, rootId);
090        
091        contentHandler.startDocument();
092        XMLUtils.startElement(contentHandler, "resources");
093        
094        try
095        {
096            Sort sort = new Sort(SolrFieldNames.TITLE_SORT, Order.ASC);
097            
098            AmetysObjectIterable<Resource> resources = _searcherFactory.create()
099                                                        .withQuery(query)
100                                                        .withFilterQueries(new DocumentTypeQuery(SolrFieldNames.TYPE_RESOURCE))
101                                                        .withSort(sort)
102                                                        .addContextElement(AccessSearchFilter.OBJECT_TYPE, "resource")
103                                                        .search();
104            
105            for (Resource resource : resources)
106            {
107                saxResource(resource);
108            }
109        }
110        catch (Exception e)
111        {
112            getLogger().error("Error searching resources in the explorer node " + id, e);
113            throw new ProcessingException("Error searching resources in the explorer node " + id, e);
114        }
115        
116        XMLUtils.endElement(contentHandler, "resources");
117        contentHandler.endDocument();
118    }
119    
120    /**
121     * Build the query object corresponding to the user search.
122     * @param request The user request.
123     * @param explorerNode The explorer node to search into.
124     * @param rootId The root ID, can be null to search all resources.
125     * @return the query object.
126     */
127    protected Query getQuery(Request request, ExplorerNode explorerNode, String rootId)
128    {
129        List<Query> queries = new ArrayList<>();
130        
131        if (explorerNode != null || StringUtils.isNotEmpty(rootId))
132        {
133            String path = explorerNode == null ? "" : explorerNode.getExplorerPath();
134            queries.add(new ResourceLocationQuery(rootId, path));
135        }
136        
137        // File name
138        String name = request.getParameter("name");
139        if (StringUtils.isNotEmpty(name))
140        {
141            queries.add(new FilenameQuery(name));
142        }
143        
144        // Full text
145        String fulltext = request.getParameter("fulltext");
146        if (StringUtils.isNotEmpty(fulltext))
147        {
148            queries.add(new FullTextQuery(fulltext, Operator.LIKE));
149        }
150        
151        String keywords = request.getParameter("keywords");
152        if (StringUtils.isNotEmpty(keywords))
153        {
154            Query subjectQuery = new DublinCoreQuery("subject", keywords);
155            Query descQuery = new DublinCoreQuery("description", keywords);
156            
157            queries.add(new OrQuery(subjectQuery, descQuery));
158        }
159        
160        String authorAsStr = request.getParameter("author");
161        Map<String, Object> json = _jsonUtils.convertJsonToMap(authorAsStr);
162        UserIdentity author = _userHelper.json2userIdentity(json);
163        if (null != author)
164        {
165            queries.add(new UsersQuery(SolrFieldNames.RESOURCE_CREATOR, author));
166        }
167        
168        return new AndQuery(queries);
169    }
170    
171    
172    
173    /**
174     * Represents a {@link Query} testing the resource creator.
175     */
176    class ResourceCreatorQuery implements Query
177    {
178        /** The operator. */
179        private Operator _operator;
180        
181        /** The value to test. */
182        private String _value;
183        
184        /**
185         * Build a string query.
186         * @param value the value.
187         */
188        public ResourceCreatorQuery(String value)
189        {
190            this(Operator.EQ, value);
191        }
192        
193        /**
194         * Build a string query.
195         * @param op the operator.
196         * @param value the value.
197         */
198        public ResourceCreatorQuery(Operator op, String value)
199        {
200            _operator = op;
201            _value = value;
202        }
203        
204        @Override
205        public String build() throws QuerySyntaxException
206        {
207            StringBuilder query = new StringBuilder();
208            
209            if (_operator == Operator.NE)
210            {
211                query.append('-');
212            }
213            
214            query.append(SolrFieldNames.RESOURCE_CREATOR).append(':')
215                          .append(ClientUtils.escapeQueryChars(_value));
216            
217            return query.toString();
218        }
219    }
220    
221}