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