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.PagesContainer;
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        PagesContainer 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 = new HashMap<>();
105                params.put("siteName", site);
106                Tag tag = _tagProviderExtensionPoint.getTag(rootTagName, params);
107
108                if (tag != null)
109                {
110                    Set<String> ancestorNames = TagHelper.getAncestorNames(tag, true);
111                    try
112                    {
113                        container = container.getChild(StringUtils.join(ancestorNames, "/"));
114                    }
115                    catch (UnknownAmetysObjectException e)
116                    {
117                        // There is no virtual tag page for this tag (= no post)
118                        container = null;
119                    }
120                }
121                else
122                {
123                    // Tag does not exist anymore
124                    getLogger().error("Navigation by tags can not be displayed with the unexisting tag '" + rootTagName + "'.");
125                    container = null;
126                }
127            }
128        }
129        
130        contentHandler.startDocument();
131        
132        XMLUtils.startElement(contentHandler, "pages");
133        
134        if (container != null)
135        {
136            _saxPagesContainer(container, depth, site, excludePrivate);
137        }
138        
139        XMLUtils.endElement(contentHandler, "pages");
140        
141        contentHandler.endDocument();
142    }
143    
144    /**
145     * SAX the pages 
146     * @param pagesContainer the page or sitemap from which we start to SAX
147     * @param depth the remaining levels of pages to SAX
148     * @param siteName the site's name
149     * @param excludePrivate true to exclude private pages, false otherwise
150     * @throws SAXException if an error occurs while SAXing the pages' information
151     */
152    private void _saxPagesContainer(PagesContainer pagesContainer, int depth, String siteName, boolean excludePrivate) throws SAXException
153    {
154        if (depth != 0)
155        {
156            for (Page page : pagesContainer.getChildrenPages())
157            {
158                AttributesImpl attrs = new AttributesImpl ();
159                attrs.addCDATAAttribute("name", page.getName());
160                attrs.addCDATAAttribute("title", page.getTitle());
161                attrs.addCDATAAttribute("long-title", page.getLongTitle());
162                attrs.addCDATAAttribute("path", page.getPathInSitemap());
163                attrs.addCDATAAttribute("id", page.getId());
164                
165                if (page instanceof VirtualPostPage)
166                {
167                    attrs.addCDATAAttribute("type", "post");
168                }
169                else if (page instanceof VirtualTagPage)
170                {
171                    VirtualTagPage tagPage = (VirtualTagPage) page;
172                    String tagName = tagPage.getTagName();
173                    
174                    Map<String, Object> contextualParams = new HashMap<>();
175                    contextualParams.put("siteName", siteName);
176                    
177                    CMSTag tag = _tagProviderExtensionPoint.getTag(tagName, contextualParams);
178                    
179                    if (!excludePrivate || !tag.getVisibility().equals(TagVisibility.PRIVATE))
180                    {
181                        // no test on tag visibility
182                        attrs.addCDATAAttribute("type", "tag");
183                        
184                        String language = tagPage.getSitemapName();
185                        Map<String, Post> postsByTag = _blogCacheManager.getPostsByTag(siteName, language, tagName);
186                        
187                        attrs.addCDATAAttribute("entries", String.valueOf(postsByTag.keySet().size()));
188                    }
189                }
190                else if (page instanceof VirtualYearPage)
191                {
192                    attrs.addCDATAAttribute("type", "year");
193                }
194                else if (page instanceof VirtualMonthPage)
195                {
196                    attrs.addCDATAAttribute("type", "month");
197                    
198                    VirtualMonthPage monthPage = (VirtualMonthPage) page;
199                    String language = monthPage.getSitemapName();
200                    int year = monthPage.getYear();
201                    int month = monthPage.getMonth();
202                    
203                    Map<String, Post> postsByMonth = _blogCacheManager.getPostsByMonth(siteName, language, year, month);
204                    
205                    attrs.addCDATAAttribute("entries", String.valueOf(postsByMonth.keySet().size()));
206                }
207                
208                for (String tag : page.getTags())
209                {
210                    attrs.addCDATAAttribute("PLUGIN_TAGS_" + tag, "empty");
211                }
212                
213                XMLUtils.startElement(contentHandler, "page", attrs);
214                
215                _saxPagesContainer(page, depth - 1, siteName, excludePrivate);
216                
217                XMLUtils.endElement(contentHandler, "page");
218            }
219        }
220    }
221}
222