001/*
002 *  Copyright 2010 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.plugins.tagcloud.generators;
017
018import java.io.IOException;
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.Collections;
022import java.util.List;
023
024import org.apache.cocoon.ProcessingException;
025import org.apache.commons.lang3.StringUtils;
026import org.apache.solr.client.solrj.SolrQuery;
027import org.apache.solr.client.solrj.response.QueryResponse;
028
029import org.ametys.cms.search.query.AndQuery;
030import org.ametys.cms.search.query.FullTextQuery;
031import org.ametys.cms.search.query.OrQuery;
032import org.ametys.cms.search.query.Query;
033import org.ametys.cms.search.query.Query.Operator;
034import org.ametys.core.util.URIUtils;
035import org.ametys.plugins.repository.data.holder.ModelAwareDataHolder;
036import org.ametys.runtime.i18n.I18nizableText;
037import org.ametys.web.search.query.PageContentQuery;
038import org.ametys.web.search.query.SiteQuery;
039import org.ametys.web.search.query.SitemapQuery;
040
041/**
042 * Generates a tag cloud based upon words
043 */
044public class TagCloudOnWordsGenerator extends AbstractTagCloudGenerator
045{
046    
047    @Override
048    protected List<TagCloudItem> getTagCloudItems(String siteName, String lang, ModelAwareDataHolder serviceParameters) throws IOException, ProcessingException
049    {
050        // Content types
051        String[] cTypes = serviceParameters.getValue("content-types");
052
053        // Pages
054        String[] pages = serviceParameters.getValue("search-by-pages");
055        
056        // Get key words to match. 
057        // TODO If empty, use top ranking terms from the solr server.
058        String keywordsAsString = serviceParameters.getValue("keywords");
059        String[] keywords = keywordsAsString.split("[,;\n]");
060        
061        // Set of {@link TagCloudItem} sorted by occurrence
062        List<TagCloudItem> tagCloud = new ArrayList<>();
063        
064        int pos = 0;
065        for (String keyword : keywords)
066        {
067            String trimKeyword = StringUtils.trimToNull(keyword);
068            if (trimKeyword != null)
069            {
070                try
071                {
072                    Query queryObject = getQuery(siteName, lang, trimKeyword, cTypes, pages);
073                    
074                    SolrQuery query = build(queryObject);
075                    
076                    if (getLogger().isInfoEnabled())
077                    {
078                        getLogger().info("Solr query: " + URIUtils.decode(query.toString()));
079                    }
080                    
081                    String collection = _solrClientProvider.getCollectionName();
082                    QueryResponse response = _solrClient.query(collection, query);
083                    
084                    int count = (int) response.getResults().getNumFound();
085                    if (count > 0)
086                    {
087                        tagCloud.add(new WordTagCloudItem(count, trimKeyword, pos));
088                        pos++;
089                    }
090                }
091                catch (Exception e)
092                {
093                    getLogger().error("Query on keyword '" + trimKeyword + "' failed. Unable to get number of occurrence", e);
094                    throw new ProcessingException("Query on keyword '" + trimKeyword + "' failed. Unable to get number of occurrence", e);
095                }
096            }
097        }
098        
099        Collections.sort(tagCloud, OCCURRENCE_COMPARATOR);
100        
101        return tagCloud;
102    }
103    
104    /**
105     * Get the query
106     * @param siteName The site name.
107     * @param language The current language.
108     * @param keyword The key word
109     * @param contentTypes The content types
110     * @param pages The pages
111     * @return the query object.
112     * @throws IllegalArgumentException If the search field is invalid
113     */
114    protected Query getQuery(String siteName, String language, String keyword, String[] contentTypes, String[] pages) throws IllegalArgumentException
115    {
116        List<Query> queries = new ArrayList<>();
117        
118        Query siteQuery = new SiteQuery(siteName);
119        Query langQuery = new SitemapQuery(language);
120        
121        queries.add(siteQuery);
122        queries.add(langQuery);
123        
124        _addContentTypeQuery(queries, contentTypes);
125        
126        _addPagesQuery(queries, pages);
127        
128        _addTextFieldQuery(queries, language, keyword);
129        
130        return new AndQuery(queries);
131    }
132    
133    // One or more of the words
134    private void _addTextFieldQuery(Collection<Query> queries, String language, String keyword) throws IllegalArgumentException
135    {
136        if (StringUtils.isNotBlank(keyword))
137        {
138            Query query = new FullTextQuery(keyword, language, Operator.SEARCH);
139            Query contentQuery = new PageContentQuery(query);
140            
141            queries.add(new OrQuery(query, contentQuery));
142        }
143    }
144    
145    private class WordTagCloudItem implements TagCloudItem
146    {
147        private int _occurrence;
148        private String _keyword;
149        private int _position;
150        
151        /**
152         * Constructor
153         * 
154         * @param occurrence the number of occurrence
155         * @param keyword the keyword
156         * @param position the original position
157         */
158        public WordTagCloudItem(int occurrence, String keyword, int position)
159        {
160            _occurrence = occurrence;
161            _keyword = keyword;
162            _position = position;
163        }
164        
165        @Override
166        public I18nizableText getWord()
167        {
168            return new I18nizableText(_keyword);
169        }
170        
171        @Override
172        public int getOccurrenceCount()
173        {
174            return _occurrence;
175        }
176        
177        @Override
178        public int getPosition()
179        {
180            return _position;
181        }
182    }
183
184}
185