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