1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.journal.action;
16  
17  import com.liferay.portal.NoSuchLayoutException;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.language.LanguageUtil;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.util.ContentTypes;
23  import com.liferay.portal.kernel.util.ParamUtil;
24  import com.liferay.portal.kernel.util.StringPool;
25  import com.liferay.portal.kernel.util.StringUtil;
26  import com.liferay.portal.kernel.util.Validator;
27  import com.liferay.portal.kernel.xml.Document;
28  import com.liferay.portal.kernel.xml.Element;
29  import com.liferay.portal.kernel.xml.Node;
30  import com.liferay.portal.kernel.xml.SAXReaderUtil;
31  import com.liferay.portal.kernel.xml.XPath;
32  import com.liferay.portal.model.Layout;
33  import com.liferay.portal.service.LayoutLocalServiceUtil;
34  import com.liferay.portal.struts.PortletAction;
35  import com.liferay.portal.theme.ThemeDisplay;
36  import com.liferay.portal.util.PortalUtil;
37  import com.liferay.portal.util.PortletKeys;
38  import com.liferay.portal.util.WebKeys;
39  import com.liferay.portlet.PortletRequestImpl;
40  import com.liferay.portlet.PortletURLImpl;
41  import com.liferay.portlet.journal.model.JournalArticle;
42  import com.liferay.portlet.journal.model.JournalArticleDisplay;
43  import com.liferay.portlet.journal.model.JournalFeed;
44  import com.liferay.portlet.journal.model.JournalFeedConstants;
45  import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
46  import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
47  import com.liferay.portlet.journal.util.JournalRSSUtil;
48  import com.liferay.portlet.journalcontent.util.JournalContentUtil;
49  import com.liferay.util.RSSUtil;
50  
51  import com.sun.syndication.feed.synd.SyndContent;
52  import com.sun.syndication.feed.synd.SyndContentImpl;
53  import com.sun.syndication.feed.synd.SyndEnclosure;
54  import com.sun.syndication.feed.synd.SyndEntry;
55  import com.sun.syndication.feed.synd.SyndEntryImpl;
56  import com.sun.syndication.feed.synd.SyndFeed;
57  import com.sun.syndication.feed.synd.SyndFeedImpl;
58  import com.sun.syndication.feed.synd.SyndLink;
59  import com.sun.syndication.io.FeedException;
60  
61  import java.io.OutputStream;
62  
63  import java.util.ArrayList;
64  import java.util.Iterator;
65  import java.util.List;
66  
67  import javax.portlet.PortletConfig;
68  import javax.portlet.PortletRequest;
69  import javax.portlet.PortletURL;
70  import javax.portlet.ResourceRequest;
71  import javax.portlet.ResourceResponse;
72  import javax.portlet.ResourceURL;
73  
74  import org.apache.struts.action.ActionForm;
75  import org.apache.struts.action.ActionMapping;
76  
77  /**
78   * <a href="RSSAction.java.html"><b><i>View Source</i></b></a>
79   *
80   * @author Raymond Augé
81   */
82  public class RSSAction extends PortletAction {
83  
84      public void serveResource(
85              ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
86              ResourceRequest resourceRequest, ResourceResponse resourceResponse)
87          throws Exception {
88  
89          resourceResponse.setContentType(ContentTypes.TEXT_XML_UTF8);
90  
91          OutputStream os = resourceResponse.getPortletOutputStream();
92  
93          try {
94              os.write(getRSS(resourceRequest, resourceResponse));
95          }
96          finally {
97              os.close();
98          }
99      }
100 
101     protected String exportToRSS(
102             ResourceRequest resourceRequest, ResourceResponse resourceResponse,
103             JournalFeed feed, String languageId, Layout layout,
104             ThemeDisplay themeDisplay)
105         throws Exception {
106 
107         ResourceURL feedURL = resourceResponse.createResourceURL();
108 
109         feedURL.setCacheability(ResourceURL.FULL);
110 
111         feedURL.setParameter("struts_action", "/journal/rss");
112         feedURL.setParameter("groupId", String.valueOf(feed.getGroupId()));
113         feedURL.setParameter("feedId", String.valueOf(feed.getFeedId()));
114 
115         SyndFeed syndFeed = new SyndFeedImpl();
116 
117         syndFeed.setFeedType(feed.getFeedType() + "_" + feed.getFeedVersion());
118         syndFeed.setTitle(feed.getName());
119         syndFeed.setLink(feedURL.toString());
120         syndFeed.setDescription(feed.getDescription());
121 
122         List<SyndEntry> entries = new ArrayList<SyndEntry>();
123 
124         syndFeed.setEntries(entries);
125 
126         List<JournalArticle> articles = JournalRSSUtil.getArticles(feed);
127 
128         if (_log.isDebugEnabled()) {
129             _log.debug("Syndicating " + articles.size() + " articles");
130         }
131 
132         Iterator<JournalArticle> itr = articles.iterator();
133 
134         while (itr.hasNext()) {
135             JournalArticle article = itr.next();
136 
137             String author = PortalUtil.getUserName(
138                 article.getUserId(), article.getUserName());
139             String link = getEntryURL(
140                 resourceRequest, feed, article, layout, themeDisplay);
141 
142             SyndEntry syndEntry = new SyndEntryImpl();
143 
144             syndEntry.setAuthor(author);
145             syndEntry.setTitle(article.getTitle());
146             syndEntry.setLink(link);
147             syndEntry.setUri(syndEntry.getLink());
148             syndEntry.setPublishedDate(article.getDisplayDate());
149             syndEntry.setUpdatedDate(article.getModifiedDate());
150 
151             SyndContent syndContent = new SyndContentImpl();
152 
153             String value = article.getDescription();
154 
155             try {
156                 value = processContent(
157                     feed, article, languageId, themeDisplay, syndEntry,
158                     syndContent);
159             }
160             catch (Exception e) {
161                 if (_log.isWarnEnabled()) {
162                     _log.warn(e, e);
163                 }
164             }
165 
166             syndContent.setType(RSSUtil.DEFAULT_ENTRY_TYPE);
167             syndContent.setValue(value);
168 
169             syndEntry.setDescription(syndContent);
170 
171             entries.add(syndEntry);
172         }
173 
174         try {
175             return RSSUtil.export(syndFeed);
176         }
177         catch (FeedException fe) {
178             throw new SystemException(fe);
179         }
180     }
181 
182     protected String getEntryURL(
183             ResourceRequest resourceRequest, JournalFeed feed,
184             JournalArticle article, Layout layout, ThemeDisplay themeDisplay)
185         throws Exception {
186 
187         List<Long> hitLayoutIds =
188             JournalContentSearchLocalServiceUtil.getLayoutIds(
189                 layout.getGroupId(), layout.isPrivateLayout(),
190                 article.getArticleId());
191 
192         if (hitLayoutIds.size() > 0) {
193             Long hitLayoutId = hitLayoutIds.get(0);
194 
195             Layout hitLayout = LayoutLocalServiceUtil.getLayout(
196                 layout.getGroupId(), layout.isPrivateLayout(),
197                 hitLayoutId.longValue());
198 
199             return PortalUtil.getLayoutFriendlyURL(hitLayout, themeDisplay);
200         }
201         else {
202             long plid = PortalUtil.getPlidFromFriendlyURL(
203                 feed.getCompanyId(), feed.getTargetLayoutFriendlyUrl());
204 
205             String portletId = PortletKeys.JOURNAL_CONTENT;
206 
207             if (Validator.isNotNull(feed.getTargetPortletId())) {
208                 portletId = feed.getTargetPortletId();
209             }
210 
211             PortletURL entryURL = new PortletURLImpl(
212                 (PortletRequestImpl)resourceRequest, portletId, plid,
213                 PortletRequest.RENDER_PHASE);
214 
215             entryURL.setParameter("struts_action", "/journal_content/view");
216             entryURL.setParameter(
217                 "groupId", String.valueOf(article.getGroupId()));
218             entryURL.setParameter("articleId", article.getArticleId());
219 
220             return entryURL.toString();
221         }
222     }
223 
224     protected byte[] getRSS(
225             ResourceRequest resourceRequest, ResourceResponse resourceResponse)
226         throws Exception {
227 
228         ThemeDisplay themeDisplay = (ThemeDisplay)resourceRequest.getAttribute(
229             WebKeys.THEME_DISPLAY);
230 
231         JournalFeed feed = null;
232 
233         long id = ParamUtil.getLong(resourceRequest, "id");
234 
235         long groupId = ParamUtil.getLong(resourceRequest, "groupId");
236         String feedId = ParamUtil.getString(resourceRequest, "feedId");
237 
238         if (id > 0) {
239             feed = JournalFeedLocalServiceUtil.getFeed(id);
240         }
241         else {
242             feed = JournalFeedLocalServiceUtil.getFeed(groupId, feedId);
243         }
244 
245         String languageId = LanguageUtil.getLanguageId(resourceRequest);
246 
247         long plid = PortalUtil.getPlidFromFriendlyURL(
248             themeDisplay.getCompanyId(), feed.getTargetLayoutFriendlyUrl());
249 
250         Layout layout = themeDisplay.getLayout();
251 
252         if (plid > 0) {
253             try {
254                 layout = LayoutLocalServiceUtil.getLayout(plid);
255             }
256             catch (NoSuchLayoutException nsle) {
257             }
258         }
259 
260         String rss = exportToRSS(
261             resourceRequest, resourceResponse, feed, languageId, layout,
262             themeDisplay);
263 
264         return rss.getBytes(StringPool.UTF8);
265     }
266 
267     protected String processContent(
268             JournalFeed feed, JournalArticle article, String languageId,
269             ThemeDisplay themeDisplay, SyndEntry syndEntry,
270             SyndContent syndContent)
271         throws Exception {
272 
273         String content = article.getDescription();
274 
275         String contentField = feed.getContentField();
276 
277         if (contentField.equals(JournalFeedConstants.RENDERED_WEB_CONTENT)) {
278             String rendererTemplateId = article.getTemplateId();
279 
280             if (Validator.isNotNull(feed.getRendererTemplateId())) {
281                 rendererTemplateId = feed.getRendererTemplateId();
282             }
283 
284             JournalArticleDisplay articleDisplay =
285                 JournalContentUtil.getDisplay(
286                     feed.getGroupId(), article.getArticleId(),
287                     rendererTemplateId, null, languageId, themeDisplay, 1,
288                     _XML_REQUUEST);
289 
290             if (articleDisplay != null) {
291                 content = articleDisplay.getContent();
292             }
293         }
294         else if (!contentField.equals(
295                     JournalFeedConstants.WEB_CONTENT_DESCRIPTION)) {
296 
297             Document doc = SAXReaderUtil.read(article.getContent());
298 
299             XPath xpathSelector = SAXReaderUtil.createXPath(
300                 "//dynamic-element[@name='" + contentField + "']");
301 
302             List<Node> results = xpathSelector.selectNodes(doc);
303 
304             if (results.size() == 0) {
305                 return content;
306             }
307 
308             Element el = (Element)results.get(0);
309 
310             String elType = el.attributeValue("type");
311 
312             if (elType.equals("document_library")) {
313                 String url = el.elementText("dynamic-content");
314 
315                 url = processURL(feed, url, themeDisplay, syndEntry);
316             }
317             else if (elType.equals("image") || elType.equals("image_gallery")) {
318                 String url = el.elementText("dynamic-content");
319 
320                 url = processURL(feed, url, themeDisplay, syndEntry);
321 
322                 content =
323                     content + "<br /><br /><img alt='' src='" +
324                         themeDisplay.getURLPortal() + url + "' />";
325             }
326             else if (elType.equals("text_box")) {
327                 syndContent.setType("text");
328 
329                 content = el.elementText("dynamic-content");
330             }
331             else {
332                 content = el.elementText("dynamic-content");
333             }
334         }
335 
336         return content;
337     }
338 
339     protected String processURL(
340         JournalFeed feed, String url, ThemeDisplay themeDisplay,
341         SyndEntry syndEntry) {
342 
343         url = StringUtil.replace(
344             url,
345             new String[] {
346                 "@group_id@",
347                 "@image_path@",
348                 "@main_path@"
349             },
350             new String[] {
351                 String.valueOf(feed.getGroupId()),
352                 themeDisplay.getPathImage(),
353                 themeDisplay.getPathMain()
354             }
355         );
356 
357         List<SyndLink> links = JournalRSSUtil.getDLLinks(
358             themeDisplay.getURLPortal(), url);
359         List<SyndEnclosure> enclosures = JournalRSSUtil.getDLEnclosures(
360             themeDisplay.getURLPortal(), url);
361 
362         syndEntry.setLinks(links);
363         syndEntry.setEnclosures(enclosures);
364 
365         return url;
366     }
367 
368     private static final String _XML_REQUUEST =
369         "<request><parameters><parameter><name>rss</name><value>true</value>" +
370             "</parameter></parameters></request>";
371 
372     private static Log _log = LogFactoryUtil.getLog(RSSAction.class);
373 
374 }