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.time.ZonedDateTime; 020import java.util.Collection; 021import java.util.Iterator; 022import java.util.LinkedHashSet; 023import java.util.Set; 024 025import org.apache.avalon.framework.service.ServiceException; 026import org.apache.avalon.framework.service.ServiceManager; 027import org.apache.cocoon.ProcessingException; 028import org.apache.cocoon.components.source.impl.SitemapSource; 029import org.apache.cocoon.environment.ObjectModelHelper; 030import org.apache.cocoon.environment.Request; 031import org.apache.cocoon.generation.ServiceableGenerator; 032import org.apache.cocoon.xml.AttributesImpl; 033import org.apache.cocoon.xml.XMLUtils; 034import org.apache.excalibur.source.SourceResolver; 035import org.xml.sax.SAXException; 036 037import org.ametys.cms.content.ContentHelper; 038import org.ametys.cms.repository.Content; 039import org.ametys.core.util.DateUtils; 040import org.ametys.core.util.IgnoreRootHandler; 041import org.ametys.plugins.blog.BlogCacheManager; 042import org.ametys.plugins.blog.BlogCacheManager.Post; 043import org.ametys.plugins.blog.BlogConstants; 044import org.ametys.plugins.repository.AmetysObjectResolver; 045import org.ametys.web.repository.page.Page; 046import org.ametys.web.repository.site.Site; 047import org.ametys.web.repository.site.SiteManager; 048 049/** 050 * Generates posts from the cache. 051 */ 052public class PostsGenerator extends ServiceableGenerator 053{ 054 /** The blog cache manager. */ 055 protected BlogCacheManager _blogCache; 056 057 /** The ametys object resolver. */ 058 protected AmetysObjectResolver _ametysResolver; 059 060 /** The site Manager. */ 061 protected SiteManager _siteManager; 062 063 /** The source resolver. */ 064 protected SourceResolver _sourceResolver; 065 066 /** The content helper. */ 067 protected ContentHelper _contentHelper; 068 069 @Override 070 public void service(ServiceManager serviceManager) throws ServiceException 071 { 072 super.service(serviceManager); 073 _blogCache = (BlogCacheManager) serviceManager.lookup(BlogCacheManager.ROLE); 074 _ametysResolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE); 075 _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE); 076 _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); 077 _contentHelper = (ContentHelper) manager.lookup(ContentHelper.ROLE); 078 } 079 080 @Override 081 public void generate() throws IOException, SAXException, ProcessingException 082 { 083 Request request = ObjectModelHelper.getRequest(objectModel); 084 085 // Get site, language and page in request attributes. Can be null if the filter does not need them. 086 Page page = (Page) request.getAttribute(Page.class.getName()); 087 String siteName = parameters.getParameter("site", page.getSiteName()); 088 String language = parameters.getParameter("lang", page.getSitemapName()); 089 090 String type = parameters.getParameter("type", "all"); 091 int year = parameters.getParameterAsInteger("year", -1); 092 int month = parameters.getParameterAsInteger("month", -1); 093 094 String tagName = parameters.getParameter("tagName", ""); 095 096 Site site = _siteManager.getSite(siteName); 097 Long postsPerPage = site.getValue("posts-service-max-count", false, Long.valueOf(BlogConstants.DEFAULT_POST_COUNT_PER_PAGE)); 098 099 String viewName = parameters.getParameter("viewName", ""); 100 101 AttributesImpl attrs = new AttributesImpl(); 102 attrs.addCDATAAttribute("posts-per-page", Long.toString(postsPerPage)); 103 104 contentHandler.startDocument(); 105 XMLUtils.startElement(contentHandler, "contents", attrs); 106 107 // Get all the posts. 108 Collection<String> postIds = getPosts(siteName, language, type, year, month, tagName, BlogConstants.DEFAULT_POST_TOTAL_COUNT); 109 110 for (String postId : postIds) 111 { 112 // Resolve the content. 113 Content postContent = _ametysResolver.resolveById(postId); 114 115 saxContent(postContent, viewName); 116 } 117 118 XMLUtils.endElement(contentHandler, "contents"); 119 contentHandler.endDocument(); 120 } 121 122 /** 123 * SAX a content in its specific view 124 * @param content The content to SAX 125 * @param viewName The view to use 126 * @throws SAXException If an error occurs while SAXing 127 * @throws IOException If an error occurs while retrieving content. 128 */ 129 public void saxContent(Content content, String viewName) throws SAXException, IOException 130 { 131 AttributesImpl attrs = new AttributesImpl(); 132 attrs.addCDATAAttribute("id", content.getId()); 133 attrs.addCDATAAttribute("name", content.getName()); 134 attrs.addCDATAAttribute("title", content.getTitle()); 135 attrs.addCDATAAttribute("lastModifiedAt", DateUtils.zonedDateTimeToString(content.getLastModified())); 136 137 XMLUtils.startElement(contentHandler, "content", attrs); 138 139 String uri = _contentHelper.getContentHtmlViewUrl(content, viewName); 140 SitemapSource src = null; 141 142 try 143 { 144 src = (SitemapSource) _sourceResolver.resolveURI(uri); 145 src.toSAX(new IgnoreRootHandler(contentHandler)); 146 } 147 finally 148 { 149 _sourceResolver.release(src); 150 } 151 152 XMLUtils.endElement(contentHandler, "content"); 153 } 154 155 /** 156 * Get all the posts for the given criteria. 157 * @param siteName the site name. 158 * @param language the language. 159 * @param type the search type ('all', 'year', 'month' or 'tag'). 160 * @param year the year in case of a 'year' or 'month' search. 161 * @param month the month, in case of a 'month' search. 162 * @param tagName the tag name in case of a 'tag' search. 163 * @return the post IDs. 164 */ 165 protected Collection<String> getPosts(String siteName, String language, String type, int year, int month, String tagName) 166 { 167 return getPosts(siteName, language, type, year, month, tagName, 0); 168 } 169 170 /** 171 * Get a limited number of posts for the given criteria. 172 * @param siteName the site name. 173 * @param language the language. 174 * @param type the search type ('all', 'year', 'month' or 'tag'). 175 * @param year the year in case of a 'year' or 'month' search. 176 * @param month the month, in case of a 'month' search. 177 * @param tagName the tag name in case of a 'tag' search. 178 * @param maxCount the maximum count of posts to retrieve. 179 * @return the post IDs. 180 */ 181 protected Collection<String> getPosts(String siteName, String language, String type, int year, int month, String tagName, int maxCount) 182 { 183 Set<String> posts = new LinkedHashSet<>(); 184 185 boolean displayFuturePosts = true; 186 if (siteName != null) 187 { 188 Site site = _siteManager.getSite(siteName); 189 displayFuturePosts = site.getValue("display-future-posts", false, false); 190 } 191 192 Iterator<Post> postIt = null; 193 if ("all".equals(type)) 194 { 195 postIt = _blogCache.getSortedPosts(siteName, language).iterator(); 196 } 197 else if ("year".equals(type)) 198 { 199 postIt = _blogCache.getSortedPostsByYear(siteName, language, year).iterator(); 200 } 201 else if ("month".equals(type)) 202 { 203 postIt = _blogCache.getSortedPostsByMonth(siteName, language, year, month).iterator(); 204 } 205 else if ("tag".equals(type)) 206 { 207 postIt = _blogCache.getSortedPostsByTag(siteName, language, tagName, true).iterator(); 208 } 209 210 if (postIt != null) 211 { 212 int count = 0; 213 while (postIt.hasNext() && (maxCount == 0 || count < maxCount)) 214 { 215 Post post = postIt.next(); 216 if (displayFuturePosts || !_isFuturePost(post)) 217 { 218 posts.add(post.getId()); 219 count++; 220 } 221 } 222 } 223 224 return posts; 225 } 226 227 private boolean _isFuturePost (Post post) 228 { 229 ZonedDateTime postDate = post.getDate(); 230 return postDate != null && postDate.isAfter(ZonedDateTime.now()); 231 } 232}