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.Tag;
035import org.ametys.cms.tag.Tag.TagVisibility;
036import org.ametys.cms.tag.TagHelper;
037import org.ametys.cms.tag.TagProviderExtensionPoint;
038import org.ametys.plugins.blog.BlogCacheManager;
039import org.ametys.plugins.blog.BlogCacheManager.Post;
040import org.ametys.plugins.blog.BlogPageHandler;
041import org.ametys.plugins.blog.repository.VirtualMonthPage;
042import org.ametys.plugins.blog.repository.VirtualPostPage;
043import org.ametys.plugins.blog.repository.VirtualTagPage;
044import org.ametys.plugins.blog.repository.VirtualTagsPage;
045import org.ametys.plugins.blog.repository.VirtualYearPage;
046import org.ametys.plugins.repository.UnknownAmetysObjectException;
047import org.ametys.web.repository.page.Page;
048import org.ametys.web.repository.page.PagesContainer;
049
050/**
051 * Blog pages generator.    
052 */
053public class BlogPagesGenerator extends ServiceableGenerator
054{
055    /** The blog cache manager. */
056    private BlogPageHandler _blogRootPageHandler;
057    
058    /** The blog cache manager */
059    private BlogCacheManager _blogCacheManager;
060    
061    /** The extension point for tag providers. */
062    private TagProviderExtensionPoint _tagProviderExtensionPoint;
063    
064    @Override
065    public void service(ServiceManager serviceManager) throws ServiceException
066    {
067        super.service(serviceManager);
068        _blogRootPageHandler = (BlogPageHandler) serviceManager.lookup(BlogPageHandler.ROLE);
069        _blogCacheManager = (BlogCacheManager) serviceManager.lookup(BlogCacheManager.ROLE);
070        _tagProviderExtensionPoint = (TagProviderExtensionPoint) serviceManager.lookup(TagProviderExtensionPoint.ROLE);
071    }
072    
073    @Override
074    public void generate() throws IOException, SAXException, ProcessingException
075    {
076        Request request = ObjectModelHelper.getRequest(objectModel);
077        Page currentPage = (Page) request.getAttribute(Page.class.getName());
078        
079        String site = parameters.getParameter("site", currentPage.getSiteName());
080        String language = parameters.getParameter("lang", currentPage.getSitemapName());
081        String pagePath = parameters.getParameter("page-path", "");
082        int depth = parameters.getParameterAsInteger("depth", -1);
083        
084        // Service parameters
085        String excludePrivateAsString = parameters.getParameter("excludePrivateTags", request.getParameter("excludePrivateTags"));
086        boolean excludePrivate = Boolean.parseBoolean(excludePrivateAsString);
087        
088        String rootTagName = parameters.getParameter("tag", request.getParameter("tag"));
089        
090        PagesContainer container = null;
091        if (StringUtils.isEmpty(pagePath))
092        {
093            // SAX all pages
094            container = _blogRootPageHandler.getBlogRootPage(site, language);
095        }
096        else
097        {
098            container = _blogRootPageHandler.getBlogPage(site, language, pagePath);
099            
100            if (StringUtils.isNotEmpty(rootTagName) && container instanceof VirtualTagsPage)
101            {
102                // SAX from the specified tag virtual page => find the corresponding container
103                Map<String, Object> params = new HashMap<>();
104                params.put("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            _saxPagesContainer(container, depth, site, excludePrivate);
136        }
137        
138        XMLUtils.endElement(contentHandler, "pages");
139        
140        contentHandler.endDocument();
141    }
142    
143    /**
144     * SAX the pages 
145     * @param pagesContainer 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 _saxPagesContainer(PagesContainer pagesContainer, int depth, String siteName, boolean excludePrivate) throws SAXException
152    {
153        if (depth != 0)
154        {
155            for (Page page : pagesContainer.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                    Tag 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 tag : page.getTags())
208                {
209                    attrs.addCDATAAttribute("PLUGIN_TAGS_" + tag, "empty");
210                }
211                
212                XMLUtils.startElement(contentHandler, "page", attrs);
213                
214                _saxPagesContainer(page, depth - 1, siteName, excludePrivate);
215                
216                XMLUtils.endElement(contentHandler, "page");
217            }
218        }
219    }
220}
221