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