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.web.filter; 017 018import java.io.IOException; 019import java.text.DateFormat; 020import java.text.SimpleDateFormat; 021import java.util.Date; 022import java.util.Iterator; 023import java.util.Locale; 024 025import org.apache.avalon.framework.parameters.ParameterException; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.cocoon.ProcessingException; 029import org.apache.cocoon.components.source.impl.SitemapSource; 030import org.apache.cocoon.environment.ObjectModelHelper; 031import org.apache.cocoon.environment.Request; 032import org.apache.cocoon.generation.ServiceableGenerator; 033import org.apache.cocoon.xml.XMLUtils; 034import org.apache.excalibur.source.SourceResolver; 035import org.xml.sax.SAXException; 036 037import org.ametys.cms.filter.ContentFilter; 038import org.ametys.cms.repository.Content; 039import org.ametys.core.util.IgnoreRootHandler; 040import org.ametys.plugins.repository.AmetysObjectIterable; 041import org.ametys.runtime.i18n.I18nizableText; 042import org.ametys.web.renderingcontext.RenderingContext; 043import org.ametys.web.renderingcontext.RenderingContextHandler; 044import org.ametys.web.repository.content.WebContent; 045import org.ametys.web.repository.page.Page; 046import org.ametys.web.repository.site.Site; 047import org.ametys.web.repository.site.SiteManager; 048import org.ametys.web.repository.sitemap.Sitemap; 049 050/** 051 * Generates SAX events for RSS feed for contents matching a {@link ContentFilter} set in request attributes 052 */ 053public class RSSGenerator extends ServiceableGenerator 054{ 055 private static final int _DEFAULT_MAX_COUNT = 20; 056 057 /** The content filter helper. */ 058 protected ContentFilterHelper _contentFilterHelper; 059 060 private SourceResolver _resolver; 061 private SiteManager _siteManager; 062 private RenderingContextHandler _renderingContextHandler; 063 064 @Override 065 public void service(ServiceManager smanager) throws ServiceException 066 { 067 super.service(smanager); 068 _contentFilterHelper = (ContentFilterHelper) smanager.lookup(ContentFilterHelper.ROLE); 069 _resolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE); 070 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 071 _renderingContextHandler = (RenderingContextHandler) manager.lookup(RenderingContextHandler.ROLE); 072 } 073 074 @Override 075 public void generate() throws IOException, SAXException, ProcessingException 076 { 077 Request request = ObjectModelHelper.getRequest(objectModel); 078 079 // Get filter in request attributes 080 ContentFilter filter = (ContentFilter) request.getAttribute("filter"); 081 082 String siteName; 083 String lang; 084 try 085 { 086 // Get site and language in sitemap parameters. Can not be null. 087 siteName = parameters.getParameter("siteName"); 088 lang = parameters.getParameter("lang"); 089 } 090 catch (ParameterException e) 091 { 092 throw new ProcessingException("Missing the site name and/or the language parameters to generate RSS feed", e); 093 } 094 095 // The path can be null if the filter does not need the current page. 096 String path = parameters.getParameter("path", null); 097 098 Site site = _siteManager.getSite(siteName); 099 Sitemap sitemap = site.getSitemap(lang); 100 Page page = null; 101 if (path != null) 102 { 103 page = sitemap.getChild(path); 104 } 105 106 contentHandler.startDocument(); 107 XMLUtils.startElement(contentHandler, "RssFeed"); 108 109 if (filter != null && filter instanceof WebContentFilter) 110 { 111 WebContentFilter webFilter = (WebContentFilter) filter; 112 113 I18nizableText title = webFilter.getTitle(); 114 if (title != null) 115 { 116 title.toSAX(contentHandler, "title"); 117 } 118 119 I18nizableText description = webFilter.getDescription(); 120 if (description != null) 121 { 122 description.toSAX(contentHandler, "description"); 123 } 124 125 DateFormat dfRFC = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH); 126 XMLUtils.createElement(contentHandler, "pubDate", dfRFC.format(new Date())); 127 128 AmetysObjectIterable<Content> contents = webFilter.getMatchingContents(siteName, lang, page); 129 Iterator<Content> it = contents.iterator(); 130 131 int maxCount = filter.getLength(); 132 if (maxCount == Integer.MAX_VALUE) 133 { 134 maxCount = _DEFAULT_MAX_COUNT; 135 } 136 137 int index = 0; 138 while (it.hasNext() && index < maxCount) 139 { 140 Content content = it.next(); 141 if (_contentFilterHelper.isContentValid(content, page, webFilter)) 142 { 143 _saxItem(content, filter.getView(), siteName); 144 index++; 145 } 146 } 147 } 148 149 XMLUtils.endElement(contentHandler, "RssFeed"); 150 contentHandler.endDocument(); 151 } 152 153 /** 154 * Determines if a content is orphan 155 * @param content the content to test 156 * @return true if the content is orphan 157 */ 158 protected boolean isOrphan(Content content) 159 { 160 if (content instanceof WebContent) 161 { 162 return ((WebContent) content).getReferencingPages().size() == 0; 163 } 164 return true; 165 } 166 167 private void _saxItem (Content content, String viewName, String siteName) throws SAXException, IOException 168 { 169 RenderingContext currentContext = _renderingContextHandler.getRenderingContext(); 170 if (currentContext == RenderingContext.BACK) 171 { 172 // Issue CMS-2642 173 _renderingContextHandler.setRenderingContext(RenderingContext.PREVIEW); 174 } 175 176 String uri = "cocoon:/_content.rss?contentId=" + content.getId() + "&viewName=" + viewName + "&siteName=" + siteName; 177 SitemapSource src = null; 178 179 try 180 { 181 src = (SitemapSource) _resolver.resolveURI(uri); 182 src.toSAX(new IgnoreRootHandler(contentHandler)); 183 } 184 finally 185 { 186 _resolver.release(src); 187 _renderingContextHandler.setRenderingContext(currentContext); 188 } 189 } 190}