001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.journal.action;
016    
017    import com.liferay.portal.NoSuchLayoutException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.ContentTypes;
023    import com.liferay.portal.kernel.util.HtmlUtil;
024    import com.liferay.portal.kernel.util.ParamUtil;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.Node;
031    import com.liferay.portal.kernel.xml.SAXReaderUtil;
032    import com.liferay.portal.kernel.xml.XPath;
033    import com.liferay.portal.model.Layout;
034    import com.liferay.portal.service.LayoutLocalServiceUtil;
035    import com.liferay.portal.struts.PortletAction;
036    import com.liferay.portal.theme.ThemeDisplay;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PortletKeys;
039    import com.liferay.portal.util.WebKeys;
040    import com.liferay.portlet.PortletRequestImpl;
041    import com.liferay.portlet.PortletURLImpl;
042    import com.liferay.portlet.journal.model.JournalArticle;
043    import com.liferay.portlet.journal.model.JournalArticleDisplay;
044    import com.liferay.portlet.journal.model.JournalFeed;
045    import com.liferay.portlet.journal.model.JournalFeedConstants;
046    import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
047    import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
048    import com.liferay.portlet.journal.util.JournalRSSUtil;
049    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
050    import com.liferay.util.RSSUtil;
051    
052    import com.sun.syndication.feed.synd.SyndContent;
053    import com.sun.syndication.feed.synd.SyndContentImpl;
054    import com.sun.syndication.feed.synd.SyndEnclosure;
055    import com.sun.syndication.feed.synd.SyndEntry;
056    import com.sun.syndication.feed.synd.SyndEntryImpl;
057    import com.sun.syndication.feed.synd.SyndFeed;
058    import com.sun.syndication.feed.synd.SyndFeedImpl;
059    import com.sun.syndication.feed.synd.SyndLink;
060    import com.sun.syndication.io.FeedException;
061    
062    import java.io.OutputStream;
063    
064    import java.util.ArrayList;
065    import java.util.Iterator;
066    import java.util.List;
067    
068    import javax.portlet.PortletConfig;
069    import javax.portlet.PortletRequest;
070    import javax.portlet.PortletURL;
071    import javax.portlet.ResourceRequest;
072    import javax.portlet.ResourceResponse;
073    import javax.portlet.ResourceURL;
074    
075    import org.apache.struts.action.ActionForm;
076    import org.apache.struts.action.ActionMapping;
077    
078    /**
079     * @author Raymond Augé
080     */
081    public class RSSAction extends PortletAction {
082    
083            public void serveResource(
084                            ActionMapping mapping, ActionForm form, PortletConfig portletConfig,
085                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
086                    throws Exception {
087    
088                    resourceResponse.setContentType(ContentTypes.TEXT_XML_UTF8);
089    
090                    OutputStream os = resourceResponse.getPortletOutputStream();
091    
092                    try {
093                            os.write(getRSS(resourceRequest, resourceResponse));
094                    }
095                    finally {
096                            os.close();
097                    }
098            }
099    
100            protected String exportToRSS(
101                            ResourceRequest resourceRequest, ResourceResponse resourceResponse,
102                            JournalFeed feed, String languageId, Layout layout,
103                            ThemeDisplay themeDisplay)
104                    throws Exception {
105    
106                    ResourceURL feedURL = resourceResponse.createResourceURL();
107    
108                    feedURL.setCacheability(ResourceURL.FULL);
109    
110                    feedURL.setParameter("struts_action", "/journal/rss");
111                    feedURL.setParameter("groupId", String.valueOf(feed.getGroupId()));
112                    feedURL.setParameter("feedId", String.valueOf(feed.getFeedId()));
113    
114                    SyndFeed syndFeed = new SyndFeedImpl();
115    
116                    syndFeed.setFeedType(feed.getFeedType() + "_" + feed.getFeedVersion());
117                    syndFeed.setTitle(feed.getName());
118                    syndFeed.setLink(feedURL.toString());
119                    syndFeed.setDescription(feed.getDescription());
120    
121                    List<SyndEntry> entries = new ArrayList<SyndEntry>();
122    
123                    syndFeed.setEntries(entries);
124    
125                    List<JournalArticle> articles = JournalRSSUtil.getArticles(feed);
126    
127                    if (_log.isDebugEnabled()) {
128                            _log.debug("Syndicating " + articles.size() + " articles");
129                    }
130    
131                    Iterator<JournalArticle> itr = articles.iterator();
132    
133                    while (itr.hasNext()) {
134                            JournalArticle article = itr.next();
135    
136                            String author = HtmlUtil.escape(
137                                    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    }