001
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.PortletURLImpl;
041 import com.liferay.portlet.journal.model.JournalArticle;
042 import com.liferay.portlet.journal.model.JournalArticleDisplay;
043 import com.liferay.portlet.journal.model.JournalFeed;
044 import com.liferay.portlet.journal.model.JournalFeedConstants;
045 import com.liferay.portlet.journal.service.JournalContentSearchLocalServiceUtil;
046 import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
047 import com.liferay.portlet.journal.util.JournalRSSUtil;
048 import com.liferay.portlet.journalcontent.util.JournalContentUtil;
049 import com.liferay.util.RSSUtil;
050
051 import com.sun.syndication.feed.synd.SyndContent;
052 import com.sun.syndication.feed.synd.SyndContentImpl;
053 import com.sun.syndication.feed.synd.SyndEnclosure;
054 import com.sun.syndication.feed.synd.SyndEntry;
055 import com.sun.syndication.feed.synd.SyndEntryImpl;
056 import com.sun.syndication.feed.synd.SyndFeed;
057 import com.sun.syndication.feed.synd.SyndFeedImpl;
058 import com.sun.syndication.feed.synd.SyndLink;
059 import com.sun.syndication.io.FeedException;
060
061 import java.io.OutputStream;
062
063 import java.util.ArrayList;
064 import java.util.Iterator;
065 import java.util.List;
066
067 import javax.portlet.PortletConfig;
068 import javax.portlet.PortletRequest;
069 import javax.portlet.PortletURL;
070 import javax.portlet.ResourceRequest;
071 import javax.portlet.ResourceResponse;
072 import javax.portlet.ResourceURL;
073
074 import org.apache.struts.action.ActionForm;
075 import org.apache.struts.action.ActionMapping;
076
077
080 public class RSSAction extends PortletAction {
081
082 @Override
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 outputStream = resourceResponse.getPortletOutputStream();
091
092 try {
093 byte[] bytes = getRSS(resourceRequest, resourceResponse);
094
095 outputStream.write(bytes);
096 }
097 finally {
098 outputStream.close();
099 }
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 feedURL.setParameter("struts_action", "/journal/rss");
112 feedURL.setParameter("groupId", String.valueOf(feed.getGroupId()));
113 feedURL.setParameter("feedId", String.valueOf(feed.getFeedId()));
114
115 SyndFeed syndFeed = new SyndFeedImpl();
116
117 syndFeed.setDescription(feed.getDescription());
118 syndFeed.setFeedType(feed.getFeedType() + "_" + feed.getFeedVersion());
119 syndFeed.setLink(feedURL.toString());
120 syndFeed.setTitle(feed.getName());
121
122 List<SyndEntry> syndEntries = new ArrayList<SyndEntry>();
123
124 syndFeed.setEntries(syndEntries);
125
126 List<JournalArticle> articles = JournalRSSUtil.getArticles(feed);
127
128 if (_log.isDebugEnabled()) {
129 _log.debug("Syndicating " + articles.size() + " articles");
130 }
131
132 Iterator<JournalArticle> itr = articles.iterator();
133
134 while (itr.hasNext()) {
135 JournalArticle article = itr.next();
136
137 String author = HtmlUtil.escape(
138 PortalUtil.getUserName(
139 article.getUserId(), article.getUserName()));
140 String link = getEntryURL(
141 resourceRequest, feed, article, layout, themeDisplay);
142
143 SyndEntry syndEntry = new SyndEntryImpl();
144
145 syndEntry.setAuthor(author);
146
147 SyndContent syndContent = new SyndContentImpl();
148
149 String value = article.getDescription(languageId);
150
151 try {
152 value = processContent(
153 feed, article, languageId, themeDisplay, syndEntry,
154 syndContent);
155 }
156 catch (Exception e) {
157 if (_log.isWarnEnabled()) {
158 _log.warn(e, e);
159 }
160 }
161
162 syndContent.setType(RSSUtil.ENTRY_TYPE_DEFAULT);
163 syndContent.setValue(value);
164
165 syndEntry.setDescription(syndContent);
166
167 syndEntry.setLink(link);
168 syndEntry.setPublishedDate(article.getDisplayDate());
169 syndEntry.setTitle(article.getTitle(languageId));
170 syndEntry.setUpdatedDate(article.getModifiedDate());
171 syndEntry.setUri(syndEntry.getLink());
172
173 syndEntries.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 resourceRequest, portletId, plid, PortletRequest.RENDER_PHASE);
215
216 entryURL.setParameter("struts_action", "/journal_content/view");
217 entryURL.setParameter(
218 "groupId", String.valueOf(article.getGroupId()));
219 entryURL.setParameter("articleId", article.getArticleId());
220
221 return entryURL.toString();
222 }
223 }
224
225 protected byte[] getRSS(
226 ResourceRequest resourceRequest, ResourceResponse resourceResponse)
227 throws Exception {
228
229 ThemeDisplay themeDisplay = (ThemeDisplay)resourceRequest.getAttribute(
230 WebKeys.THEME_DISPLAY);
231
232 JournalFeed feed = null;
233
234 long id = ParamUtil.getLong(resourceRequest, "id");
235
236 long groupId = ParamUtil.getLong(resourceRequest, "groupId");
237 String feedId = ParamUtil.getString(resourceRequest, "feedId");
238
239 if (id > 0) {
240 feed = JournalFeedLocalServiceUtil.getFeed(id);
241 }
242 else {
243 feed = JournalFeedLocalServiceUtil.getFeed(groupId, feedId);
244 }
245
246 String languageId = LanguageUtil.getLanguageId(resourceRequest);
247
248 long plid = PortalUtil.getPlidFromFriendlyURL(
249 themeDisplay.getCompanyId(), feed.getTargetLayoutFriendlyUrl());
250
251 Layout layout = themeDisplay.getLayout();
252
253 if (plid > 0) {
254 try {
255 layout = LayoutLocalServiceUtil.getLayout(plid);
256 }
257 catch (NoSuchLayoutException nsle) {
258 }
259 }
260
261 String rss = exportToRSS(
262 resourceRequest, resourceResponse, feed, languageId, layout,
263 themeDisplay);
264
265 return rss.getBytes(StringPool.UTF8);
266 }
267
268 protected String processContent(
269 JournalFeed feed, JournalArticle article, String languageId,
270 ThemeDisplay themeDisplay, SyndEntry syndEntry,
271 SyndContent syndContent)
272 throws Exception {
273
274 String content = article.getDescription(languageId);
275
276 String contentField = feed.getContentField();
277
278 if (contentField.equals(JournalFeedConstants.RENDERED_WEB_CONTENT)) {
279 String rendererTemplateId = article.getTemplateId();
280
281 if (Validator.isNotNull(feed.getRendererTemplateId())) {
282 rendererTemplateId = feed.getRendererTemplateId();
283 }
284
285 JournalArticleDisplay articleDisplay =
286 JournalContentUtil.getDisplay(
287 feed.getGroupId(), article.getArticleId(),
288 rendererTemplateId, null, languageId, themeDisplay, 1,
289 _XML_REQUUEST);
290
291 if (articleDisplay != null) {
292 content = articleDisplay.getContent();
293 }
294 }
295 else if (!contentField.equals(
296 JournalFeedConstants.WEB_CONTENT_DESCRIPTION)) {
297
298 Document document = SAXReaderUtil.read(
299 article.getContentByLocale(languageId));
300
301 XPath xPathSelector = SAXReaderUtil.createXPath(
302 "
303
304 List<Node> results = xPathSelector.selectNodes(document);
305
306 if (results.size() == 0) {
307 return content;
308 }
309
310 Element element = (Element)results.get(0);
311
312 String elType = element.attributeValue("type");
313
314 if (elType.equals("document_library")) {
315 String url = element.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 = element.elementText("dynamic-content");
321
322 url = processURL(feed, url, themeDisplay, syndEntry);
323
324 content =
325 content + "<br /><br /><img alt='' src='" +
326 themeDisplay.getURLPortal() + url + "' />";
327 }
328 else if (elType.equals("text_box")) {
329 syndContent.setType("text");
330
331 content = element.elementText("dynamic-content");
332 }
333 else {
334 content = element.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@", "@image_path@", "@main_path@"
349 },
350 new String[] {
351 String.valueOf(feed.getGroupId()), themeDisplay.getPathImage(),
352 themeDisplay.getPathMain()
353 }
354 );
355
356 List<SyndEnclosure> syndEnclosures = JournalRSSUtil.getDLEnclosures(
357 themeDisplay.getURLPortal(), url);
358
359 syndEnclosures.addAll(
360 JournalRSSUtil.getIGEnclosures(themeDisplay.getURLPortal(), url));
361
362 syndEntry.setEnclosures(syndEnclosures);
363
364 List<SyndLink> syndLinks = JournalRSSUtil.getDLLinks(
365 themeDisplay.getURLPortal(), url);
366
367 syndLinks.addAll(
368 JournalRSSUtil.getIGLinks(themeDisplay.getURLPortal(), url));
369
370 syndEntry.setLinks(syndLinks);
371
372 return url;
373 }
374
375 private static final String _XML_REQUUEST =
376 "<request><parameters><parameter><name>rss</name><value>true</value>" +
377 "</parameter></parameters></request>";
378
379 private static Log _log = LogFactoryUtil.getLog(RSSAction.class);
380
381 }