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.net.URLDecoder;
020import java.util.ArrayList;
021import java.util.Collection;
022import java.util.Collections;
023import java.util.HashMap;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.cocoon.ProcessingException;
031import org.apache.cocoon.xml.AttributesImpl;
032import org.apache.solr.client.solrj.SolrQuery;
033import org.apache.solr.client.solrj.response.QueryResponse;
034import org.xml.sax.SAXException;
035
036import org.ametys.cms.search.query.AndQuery;
037import org.ametys.cms.search.query.Query;
038import org.ametys.cms.search.query.TagQuery;
039import org.ametys.cms.tag.Tag;
040import org.ametys.cms.tag.TagProvider;
041import org.ametys.cms.tag.TagProviderExtensionPoint;
042import org.ametys.plugins.repository.metadata.CompositeMetadata;
043import org.ametys.runtime.i18n.I18nizableText;
044import org.ametys.web.search.query.PageContentQuery;
045import org.ametys.web.search.query.SiteQuery;
046import org.ametys.web.search.query.SitemapQuery;
047
048/**
049 * Generates a tag cloud based upon content tags
050 */
051public class TagCloudOnTagsGenerator extends AbstractTagCloudGenerator
052{
053    
054    /** The {@link TagProviderExtensionPoint} */
055    protected TagProviderExtensionPoint _tagExtPt;
056    
057    @Override
058    public void service(ServiceManager serviceManager) throws ServiceException
059    {
060        super.service(serviceManager);
061        _tagExtPt = (TagProviderExtensionPoint) manager.lookup(TagProviderExtensionPoint.ROLE);
062    }
063
064    @Override
065    protected List<TagCloudItem> getTagCloudItems(String siteName, String lang, CompositeMetadata serviceParameters) throws IOException, ProcessingException
066    {
067        // Set of {@link TagCloud} sorted by occurrence
068        List<TagCloudItem> tagCloud = new ArrayList<>();
069
070        // Content types
071        String[] cTypes = serviceParameters.getStringArray("content-types");
072
073        // Pages
074        String[] pages = serviceParameters.getStringArray("search-by-pages");
075        
076        // Tags to search for
077        String[] tagArray = serviceParameters.getStringArray("search-by-tags");
078        List<Tag> tags = _getTags(siteName, tagArray);
079        
080        int pos = 0;
081        for (Tag tag : tags)
082        {
083            try
084            {
085                Query queryObject = getQuery(siteName, lang, tag.getName(), cTypes, pages);
086                
087                SolrQuery query = build(queryObject);
088                
089                if (getLogger().isInfoEnabled())
090                {
091                    getLogger().info("Solr query: " + URLDecoder.decode(query.toString(), "UTF-8"));
092                }
093                
094                String collection = _solrClientProvider.getCollectionName();
095                QueryResponse response = _solrClient.query(collection, query);
096                
097                int count = (int) response.getResults().getNumFound();
098                if (count > 0)
099                {
100                    tagCloud.add(new TagTagCloudItem(count, tag, pos));
101                    pos++;
102                }
103            }
104            catch (Exception e)
105            {
106                getLogger().error("Query on tag " + tag.getName() + " failed. Unable to get number of occurrence", e);
107                throw new ProcessingException("Query on tag " + tag.getName() + " failed. Unable to get number of occurrence", e);
108            }
109        }
110        
111        Collections.sort(tagCloud, OCCURRENCE_COMPARATOR);
112        
113        return tagCloud;
114    }
115    
116    @Override
117    protected void _saxAdditionalAttributes(TagCloudItem item, AttributesImpl attrs) throws SAXException
118    {
119        if (item instanceof TagTagCloudItem)
120        {
121            Tag tag = ((TagTagCloudItem) item).getTag();
122            attrs.addCDATAAttribute("tag", tag.getName());
123        }
124    }
125    
126    /**
127     * Get the query
128     * @param siteName The site name.
129     * @param language The current language.
130     * @param tagName The tag name
131     * @param contentTypes The content types
132     * @param pages The pages
133     * @return the query
134     * @throws IllegalArgumentException If the search field is invalid
135     */
136    protected Query getQuery(String siteName, String language, String tagName, String[] contentTypes, String[] pages)
137    {
138        List<Query> queries = new ArrayList<>();
139        
140        Query siteQuery = new SiteQuery(siteName);
141        Query langQuery = new SitemapQuery(language);
142        
143        queries.add(siteQuery);
144        queries.add(langQuery);
145        
146        _addContentTypeQuery(queries, contentTypes);
147        
148        _addPagesQuery(queries, pages);
149        
150        _addTagQuery(queries, tagName);
151        
152        return new AndQuery(queries);
153    }
154    
155    private void _addTagQuery(Collection<Query> queries, String tagName)
156    {
157        queries.add(new PageContentQuery(new TagQuery(tagName)));
158    }
159    
160    private List<Tag> _getTags(String siteName, String[] tagArray)
161    {
162        Map<String, Object> contextParameters = new HashMap<>();
163        contextParameters.put("siteName", siteName);
164        
165        List<Tag> tags = new ArrayList<>();
166        
167        for (String tagName : tagArray)
168        {
169            boolean found = false;
170            Iterator<String> extensionsIds = _tagExtPt.getExtensionsIds().iterator();
171            
172            while (extensionsIds.hasNext() && !found)
173            {
174                String id = extensionsIds.next();
175                
176                TagProvider tagProvider = _tagExtPt.getExtension(id);
177                if (tagName.startsWith("provider_") && id.equals(tagName.substring("provider_".length())))
178                {
179                    found = true;
180                    tags.addAll(tagProvider.getTags(contextParameters).values());
181                }
182                else if (tagProvider.hasTag(tagName, contextParameters))
183                {
184                    found = true;
185                    Tag tag = tagProvider.getTag(tagName, contextParameters);
186                    tags.addAll(tag.getTags().values());
187                }
188            }
189        }
190        
191        return tags;
192    }
193    
194    /**
195     * Class representing an item of tag cloud
196     */
197    private class TagTagCloudItem implements TagCloudItem
198    {
199        private int _occurence;
200        private Tag _tag;
201        private int _position;
202
203        /**
204         * Constructor
205         * 
206         * @param occurence the number of occurence
207         * @param tag the tag
208         * @param position the item original position.
209         */
210        public TagTagCloudItem(int occurence, Tag tag, int position)
211        {
212            _occurence = occurence;
213            _tag = tag;
214            _position = position;
215        }
216
217        /**
218         * Returns the tag
219         * 
220         * @return the tag
221         */
222        public Tag getTag()
223        {
224            return _tag;
225        }
226
227        @Override
228        public I18nizableText getWord()
229        {
230            return _tag.getTitle();
231        }
232        
233        @Override
234        public int getOccurrenceCount()
235        {
236            return _occurence;
237        }
238        
239        @Override
240        public int getPosition()
241        {
242            return _position;
243        }
244    }
245    
246}