001    /**
002     * Copyright (c) 2000-present 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.portlet.PortletRequestModel;
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.theme.ThemeDisplay;
036    import com.liferay.portal.util.PortalUtil;
037    import com.liferay.portal.util.PortletKeys;
038    import com.liferay.portal.util.WebKeys;
039    import com.liferay.portlet.PortletURLImpl;
040    import com.liferay.portlet.journal.model.JournalArticle;
041    import com.liferay.portlet.journal.model.JournalArticleDisplay;
042    import com.liferay.portlet.journal.model.JournalFeed;
043    import com.liferay.portlet.journal.model.JournalFeedConstants;
044    import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
045    import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
046    import com.liferay.portlet.journal.util.JournalRSSUtil;
047    import com.liferay.portlet.journalcontent.util.JournalContentUtil;
048    import com.liferay.util.RSSUtil;
049    
050    import com.sun.syndication.feed.synd.SyndContent;
051    import com.sun.syndication.feed.synd.SyndContentImpl;
052    import com.sun.syndication.feed.synd.SyndEnclosure;
053    import com.sun.syndication.feed.synd.SyndEntry;
054    import com.sun.syndication.feed.synd.SyndEntryImpl;
055    import com.sun.syndication.feed.synd.SyndFeed;
056    import com.sun.syndication.feed.synd.SyndFeedImpl;
057    import com.sun.syndication.feed.synd.SyndLink;
058    import com.sun.syndication.feed.synd.SyndLinkImpl;
059    import com.sun.syndication.io.FeedException;
060    
061    import java.util.ArrayList;
062    import java.util.Date;
063    import java.util.List;
064    
065    import javax.portlet.PortletRequest;
066    import javax.portlet.PortletURL;
067    import javax.portlet.ResourceRequest;
068    import javax.portlet.ResourceResponse;
069    import javax.portlet.ResourceURL;
070    
071    /**
072     * @author Raymond Aug??
073     */
074    public class RSSAction extends com.liferay.portal.struts.RSSAction {
075    
076            protected String exportToRSS(
077                            ResourceRequest resourceRequest, ResourceResponse resourceResponse,
078                            JournalFeed feed, String languageId, Layout layout,
079                            ThemeDisplay themeDisplay)
080                    throws Exception {
081    
082                    SyndFeed syndFeed = new SyndFeedImpl();
083    
084                    syndFeed.setDescription(feed.getDescription());
085    
086                    List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
087    
088                    syndFeed.setEntries(syndEntries);
089    
090                    List<JournalArticle> articles = JournalRSSUtil.getArticles(feed);
091    
092                    if (_log.isDebugEnabled()) {
093                            _log.debug("Syndicating " + articles.size() + " articles");
094                    }
095    
096                    for (JournalArticle article : articles) {
097                            SyndEntry syndEntry = new SyndEntryImpl();
098    
099                            String author = PortalUtil.getUserName(article);
100    
101                            syndEntry.setAuthor(author);
102    
103                            SyndContent syndContent = new SyndContentImpl();
104    
105                            syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
106    
107                            String value = article.getDescription(languageId);
108    
109                            try {
110                                    value = processContent(
111                                            feed, article, languageId, themeDisplay, syndEntry,
112                                            syndContent);
113                            }
114                            catch (Exception e) {
115                                    if (_log.isWarnEnabled()) {
116                                            _log.warn(e, e);
117                                    }
118                            }
119    
120                            syndContent.setValue(value);
121    
122                            syndEntry.setDescription(syndContent);
123    
124                            String link = getEntryURL(
125                                    resourceRequest, feed, article, layout, themeDisplay);
126    
127                            syndEntry.setLink(link);
128    
129                            syndEntry.setPublishedDate(article.getDisplayDate());
130                            syndEntry.setTitle(article.getTitle(languageId));
131                            syndEntry.setUpdatedDate(article.getModifiedDate());
132                            syndEntry.setUri(link);
133    
134                            syndEntries.add(syndEntry);
135                    }
136    
137                    syndFeed.setFeedType(
138                            feed.getFeedFormat() + "_" + feed.getFeedVersion());
139    
140                    List<SyndLink> syndLinks = new ArrayList<SyndLink>();
141    
142                    syndFeed.setLinks(syndLinks);
143    
144                    SyndLink selfSyndLink = new SyndLinkImpl();
145    
146                    syndLinks.add(selfSyndLink);
147    
148                    ResourceURL feedURL = resourceResponse.createResourceURL();
149    
150                    feedURL.setCacheability(ResourceURL.FULL);
151                    feedURL.setParameter("struts_action", "/journal/rss");
152                    feedURL.setParameter("groupId", String.valueOf(feed.getGroupId()));
153                    feedURL.setParameter("feedId", String.valueOf(feed.getFeedId()));
154    
155                    String link = feedURL.toString();
156    
157                    selfSyndLink.setHref(link);
158    
159                    selfSyndLink.setRel("self");
160    
161                    syndFeed.setTitle(feed.getName());
162                    syndFeed.setPublishedDate(new Date());
163                    syndFeed.setUri(feedURL.toString());
164    
165                    try {
166                            return RSSUtil.export(syndFeed);
167                    }
168                    catch (FeedException fe) {
169                            throw new SystemException(fe);
170                    }
171            }
172    
173            protected String getEntryURL(
174                            ResourceRequest resourceRequest, JournalFeed feed,
175                            JournalArticle article, Layout layout, ThemeDisplay themeDisplay)
176                    throws Exception {
177    
178                    List<Long> hitLayoutIds =
179                            JournalContentSearchLocalServiceUtil.getLayoutIds(
180                                    layout.getGroupId(), layout.isPrivateLayout(),
181                                    article.getArticleId());
182    
183                    if (!hitLayoutIds.isEmpty()) {
184                            Long hitLayoutId = hitLayoutIds.get(0);
185    
186                            Layout hitLayout = LayoutLocalServiceUtil.getLayout(
187                                    layout.getGroupId(), layout.isPrivateLayout(),
188                                    hitLayoutId.longValue());
189    
190                            return PortalUtil.getLayoutFriendlyURL(hitLayout, themeDisplay);
191                    }
192    
193                    long plid = PortalUtil.getPlidFromFriendlyURL(
194                            feed.getCompanyId(), feed.getTargetLayoutFriendlyUrl());
195    
196                    String portletId = PortletKeys.JOURNAL_CONTENT;
197    
198                    if (Validator.isNotNull(feed.getTargetPortletId())) {
199                            portletId = feed.getTargetPortletId();
200                    }
201    
202                    PortletURL entryURL = new PortletURLImpl(
203                            resourceRequest, portletId, plid, PortletRequest.RENDER_PHASE);
204    
205                    entryURL.setParameter("struts_action", "/journal_content/view");
206                    entryURL.setParameter("groupId", String.valueOf(article.getGroupId()));
207                    entryURL.setParameter("articleId", article.getArticleId());
208    
209                    return entryURL.toString();
210            }
211    
212            @Override
213            protected byte[] getRSS(
214                            ResourceRequest resourceRequest, ResourceResponse resourceResponse)
215                    throws Exception {
216    
217                    ThemeDisplay themeDisplay = (ThemeDisplay)resourceRequest.getAttribute(
218                            WebKeys.THEME_DISPLAY);
219    
220                    JournalFeed feed = null;
221    
222                    long id = ParamUtil.getLong(resourceRequest, "id");
223    
224                    long groupId = ParamUtil.getLong(resourceRequest, "groupId");
225                    String feedId = ParamUtil.getString(resourceRequest, "feedId");
226    
227                    if (id > 0) {
228                            feed = JournalFeedLocalServiceUtil.getFeed(id);
229                    }
230                    else {
231                            feed = JournalFeedLocalServiceUtil.getFeed(groupId, feedId);
232                    }
233    
234                    String languageId = LanguageUtil.getLanguageId(resourceRequest);
235    
236                    long plid = PortalUtil.getPlidFromFriendlyURL(
237                            themeDisplay.getCompanyId(), feed.getTargetLayoutFriendlyUrl());
238    
239                    Layout layout = themeDisplay.getLayout();
240    
241                    if (plid > 0) {
242                            try {
243                                    layout = LayoutLocalServiceUtil.getLayout(plid);
244                            }
245                            catch (NoSuchLayoutException nsle) {
246                            }
247                    }
248    
249                    String rss = exportToRSS(
250                            resourceRequest, resourceResponse, feed, languageId, layout,
251                            themeDisplay);
252    
253                    return rss.getBytes(StringPool.UTF8);
254            }
255    
256            protected String processContent(
257                            JournalFeed feed, JournalArticle article, String languageId,
258                            ThemeDisplay themeDisplay, SyndEntry syndEntry,
259                            SyndContent syndContent)
260                    throws Exception {
261    
262                    String content = article.getDescription(languageId);
263    
264                    String contentField = feed.getContentField();
265    
266                    if (contentField.equals(JournalFeedConstants.RENDERED_WEB_CONTENT)) {
267                            String rendererTemplateId = article.getTemplateId();
268    
269                            if (Validator.isNotNull(feed.getRendererTemplateId())) {
270                                    rendererTemplateId = feed.getRendererTemplateId();
271                            }
272    
273                            JournalArticleDisplay articleDisplay =
274                                    JournalContentUtil.getDisplay(
275                                            feed.getGroupId(), article.getArticleId(),
276                                            rendererTemplateId, null, languageId, 1,
277                                            new PortletRequestModel() {
278    
279                                                    @Override
280                                                    public String toXML() {
281                                                            return _XML_REQUUEST;
282                                                    }
283    
284                                            },
285                                            themeDisplay);
286    
287                            if (articleDisplay != null) {
288                                    content = articleDisplay.getContent();
289                            }
290                    }
291                    else if (!contentField.equals(
292                                            JournalFeedConstants.WEB_CONTENT_DESCRIPTION)) {
293    
294                            Document document = SAXReaderUtil.read(
295                                    article.getContentByLocale(languageId));
296    
297                            contentField = HtmlUtil.escapeXPathAttribute(contentField);
298    
299                            XPath xPathSelector = SAXReaderUtil.createXPath(
300                                    "//dynamic-element[@name=" + contentField + "]");
301    
302                            List<Node> results = xPathSelector.selectNodes(document);
303    
304                            if (results.isEmpty()) {
305                                    return content;
306                            }
307    
308                            Element element = (Element)results.get(0);
309    
310                            String elType = element.attributeValue("type");
311    
312                            if (elType.equals("document_library")) {
313                                    String url = element.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 = element.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 = element.elementText("dynamic-content");
330                            }
331                            else {
332                                    content = element.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@", "@image_path@", "@main_path@"
347                            },
348                            new String[] {
349                                    String.valueOf(feed.getGroupId()), themeDisplay.getPathImage(),
350                                    themeDisplay.getPathMain()
351                            }
352                    );
353    
354                    List<SyndEnclosure> syndEnclosures = JournalRSSUtil.getDLEnclosures(
355                            themeDisplay.getURLPortal(), url);
356    
357                    syndEnclosures.addAll(
358                            JournalRSSUtil.getIGEnclosures(themeDisplay.getURLPortal(), url));
359    
360                    syndEntry.setEnclosures(syndEnclosures);
361    
362                    List<SyndLink> syndLinks = JournalRSSUtil.getDLLinks(
363                            themeDisplay.getURLPortal(), url);
364    
365                    syndLinks.addAll(
366                            JournalRSSUtil.getIGLinks(themeDisplay.getURLPortal(), url));
367    
368                    syndEntry.setLinks(syndLinks);
369    
370                    return url;
371            }
372    
373            private static final String _XML_REQUUEST =
374                    "<request><parameters><parameter><name>rss</name><value>true</value>" +
375                            "</parameter></parameters></request>";
376    
377            private static final Log _log = LogFactoryUtil.getLog(RSSAction.class);
378    
379    }