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