001/*
002 *  Copyright 2015 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.blog.posts;
017
018import java.io.IOException;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.Set;
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.generation.ServiceableGenerator;
029import org.apache.cocoon.xml.AttributesImpl;
030import org.apache.cocoon.xml.XMLUtils;
031import org.apache.commons.lang.StringUtils;
032import org.xml.sax.SAXException;
033
034import org.ametys.cms.tag.CMSTag;
035import org.ametys.cms.tag.CMSTag.TagVisibility;
036import org.ametys.cms.tag.Tag;
037import org.ametys.cms.tag.TagHelper;
038import org.ametys.cms.tag.TagProviderExtensionPoint;
039import org.ametys.plugins.blog.BlogCacheManager;
040import org.ametys.plugins.blog.BlogCacheManager.Post;
041import org.ametys.plugins.blog.BlogPageHandler;
042import org.ametys.plugins.blog.repository.VirtualMonthPage;
043import org.ametys.plugins.blog.repository.VirtualPostPage;
044import org.ametys.plugins.blog.repository.VirtualTagPage;
045import org.ametys.plugins.blog.repository.VirtualTagsPage;
046import org.ametys.plugins.blog.repository.VirtualYearPage;
047import org.ametys.plugins.repository.UnknownAmetysObjectException;
048import org.ametys.web.repository.page.Page;
049import org.ametys.web.repository.page.SitemapElement;
050
051/**
052 * Blog pages generator.    
053 */
054public class BlogPagesGenerator extends ServiceableGenerator
055{
056    /** The blog cache manager. */
057    private BlogPageHandler _blogRootPageHandler;
058    
059    /** The blog cache manager */
060    private BlogCacheManager _blogCacheManager;
061    
062    /** The extension point for tag providers. */
063    private TagProviderExtensionPoint _tagProviderExtensionPoint;
064    
065    @Override
066    public void service(ServiceManager serviceManager) throws ServiceException
067    {
068        super.service(serviceManager);
069        _blogRootPageHandler = (BlogPageHandler) serviceManager.lookup(BlogPageHandler.ROLE);
070        _blogCacheManager = (BlogCacheManager) serviceManager.lookup(BlogCacheManager.ROLE);
071        _tagProviderExtensionPoint = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE);
072    }
073    
074    @Override
075    public void generate() throws IOException, SAXException, ProcessingException
076    {
077        Request request = ObjectModelHelper.getRequest(objectModel);
078        Page currentPage = (Page) request.getAttribute(Page.class.getName());
079        
080        String site = parameters.getParameter("site", currentPage.getSiteName());
081        String language = parameters.getParameter("lang", currentPage.getSitemapName());
082        String pagePath = parameters.getParameter("page-path", "");
083        int depth = parameters.getParameterAsInteger("depth", -1);
084        
085        // Service parameters
086        String excludePrivateAsString = parameters.getParameter("excludePrivateTags", request.getParameter("excludePrivateTags"));
087        boolean excludePrivate = Boolean.parseBoolean(excludePrivateAsString);
088        
089        String rootTagName = parameters.getParameter("tag", request.getParameter("tag"));
090        
091        SitemapElement container = null;
092        if (StringUtils.isEmpty(pagePath))
093        {
094            // SAX all pages
095            container = _blogRootPageHandler.getBlogRootPage(site, language);
096        }
097        else
098        {
099            container = _blogRootPageHandler.getBlogPage(site, language, pagePath);
100            
101            if (StringUtils.isNotEmpty(rootTagName) && container instanceof VirtualTagsPage)
102            {
103                // SAX from the specified tag virtual page => find the corresponding container
104                Map<String, Object> params = Map.of("siteName", site);
105                Tag tag = _tagProviderExtensionPoint.getTag(rootTagName, params);
106
107                if (tag != null)
108                {
109                    Set<String> ancestorNames = TagHelper.getAncestorNames(tag, true);
110                    try
111                    {
112                        container = container.getChild(StringUtils.join(ancestorNames, "/"));
113                    }
114                    catch (UnknownAmetysObjectException e)
115                    {
116                        // There is no virtual tag page for this tag (= no post)
117                        container = null;
118                    }
119                }
120                else
121                {
122                    // Tag does not exist anymore
123                    getLogger().error("Navigation by tags can not be displayed with the unexisting tag '" + rootTagName + "'.");
124                    container = null;
125                }
126            }
127        }
128        
129        contentHandler.startDocument();
130        
131        XMLUtils.startElement(contentHandler, "pages");
132        
133        if (container != null)
134        {
135            _saxSitemapElement(container, depth, site, excludePrivate);
136        }
137        
138        XMLUtils.endElement(contentHandler, "pages");
139        
140        contentHandler.endDocument();
141    }
142    
143    /**
144     * SAX the pages 
145     * @param sitemapElement the page or sitemap from which we start to SAX
146     * @param depth the remaining levels of pages to SAX
147     * @param siteName the site's name
148     * @param excludePrivate true to exclude private pages, false otherwise
149     * @throws SAXException if an error occurs while SAXing the pages' information
150     */
151    private void _saxSitemapElement(SitemapElement sitemapElement, int depth, String siteName, boolean excludePrivate) throws SAXException
152    {
153        if (depth != 0)
154        {
155            for (Page page : sitemapElement.getChildrenPages())
156            {
157                AttributesImpl attrs = new AttributesImpl ();
158                attrs.addCDATAAttribute("name", page.getName());
159                attrs.addCDATAAttribute("title", page.getTitle());
160                attrs.addCDATAAttribute("long-title", page.getLongTitle());
161                attrs.addCDATAAttribute("path", page.getPathInSitemap());
162                attrs.addCDATAAttribute("id", page.getId());
163                
164                if (page instanceof VirtualPostPage)
165                {
166                    attrs.addCDATAAttribute("type", "post");
167                }
168                else if (page instanceof VirtualTagPage)
169                {
170                    VirtualTagPage tagPage = (VirtualTagPage) page;
171                    String tagName = tagPage.getTagName();
172                    
173                    Map<String, Object> contextualParams = new HashMap<>();
174                    contextualParams.put("siteName", siteName);
175                    
176                    CMSTag tag = _tagProviderExtensionPoint.getTag(tagName, contextualParams);
177                    
178                    if (!excludePrivate || !tag.getVisibility().equals(TagVisibility.PRIVATE))
179                    {
180                        // no test on tag visibility
181                        attrs.addCDATAAttribute("type", "tag");
182                        
183                        String language = tagPage.getSitemapName();
184                        Map<String, Post> postsByTag = _blogCacheManager.getPostsByTag(siteName, language, tagName);
185                        
186                        attrs.addCDATAAttribute("entries", String.valueOf(postsByTag.keySet().size()));
187                    }
188                }
189                else if (page instanceof VirtualYearPage)
190                {
191                    attrs.addCDATAAttribute("type", "year");
192                }
193                else if (page instanceof VirtualMonthPage)
194                {
195                    attrs.addCDATAAttribute("type", "month");
196                    
197                    VirtualMonthPage monthPage = (VirtualMonthPage) page;
198                    String language = monthPage.getSitemapName();
199                    int year = monthPage.getYear();
200                    int month = monthPage.getMonth();
201                    
202                    Map<String, Post> postsByMonth = _blogCacheManager.getPostsByMonth(siteName, language, year, month);
203                    
204                    attrs.addCDATAAttribute("entries", String.valueOf(postsByMonth.keySet().size()));
205                }
206                
207                for (String tagName : page.getTags())
208                {
209                    Map<String, Object> params = Map.of("siteName", siteName);
210                    Tag tag = _tagProviderExtensionPoint.getTag(tagName, params);
211
212                    if (tag != null)
213                    {
214                        attrs.addCDATAAttribute("PLUGIN_TAGS_" + tagName, "empty");
215                    }
216                }
217                
218                XMLUtils.startElement(contentHandler, "page", attrs);
219                
220                _saxSitemapElement(page, depth - 1, siteName, excludePrivate);
221                
222                XMLUtils.endElement(contentHandler, "page");
223            }
224        }
225    }
226}
227