001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.portlet.journal.action;
022:
023: import com.liferay.portal.NoSuchLayoutException;
024: import com.liferay.portal.SystemException;
025: import com.liferay.portal.kernel.language.LanguageUtil;
026: import com.liferay.portal.kernel.portlet.LiferayWindowState;
027: import com.liferay.portal.kernel.util.ContentTypes;
028: import com.liferay.portal.kernel.util.ParamUtil;
029: import com.liferay.portal.kernel.util.StringMaker;
030: import com.liferay.portal.kernel.util.StringPool;
031: import com.liferay.portal.kernel.util.StringUtil;
032: import com.liferay.portal.kernel.util.Validator;
033: import com.liferay.portal.model.Layout;
034: import com.liferay.portal.service.LayoutLocalServiceUtil;
035: import com.liferay.portal.struts.ActionConstants;
036: import com.liferay.portal.struts.PortletAction;
037: import com.liferay.portal.theme.ThemeDisplay;
038: import com.liferay.portal.util.PortalUtil;
039: import com.liferay.portal.util.PortletKeys;
040: import com.liferay.portal.util.WebKeys;
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.impl.JournalFeedImpl;
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.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.io.FeedException;
058:
059: import java.io.IOException;
060: import java.io.OutputStream;
061:
062: import java.util.ArrayList;
063: import java.util.Iterator;
064: import java.util.List;
065:
066: import javax.portlet.PortletConfig;
067: import javax.portlet.RenderRequest;
068: import javax.portlet.RenderResponse;
069:
070: import org.apache.commons.logging.Log;
071: import org.apache.commons.logging.LogFactory;
072: import org.apache.struts.action.ActionForm;
073: import org.apache.struts.action.ActionForward;
074: import org.apache.struts.action.ActionMapping;
075:
076: import org.dom4j.Document;
077: import org.dom4j.DocumentHelper;
078: import org.dom4j.Element;
079: import org.dom4j.XPath;
080:
081: /**
082: * <a href="RSSAction.java.html"><b><i>View Source</i></b></a>
083: *
084: * @author Raymond Augé
085: *
086: */
087: public class RSSAction extends PortletAction {
088:
089: public ActionForward render(ActionMapping mapping, ActionForm form,
090: PortletConfig config, RenderRequest req, RenderResponse res)
091: throws Exception {
092:
093: if (req.getWindowState() == LiferayWindowState.EXCLUSIVE) {
094: res.setContentType(ContentTypes.TEXT_XML_UTF8);
095:
096: OutputStream out = res.getPortletOutputStream();
097:
098: try {
099: out.write(getRSS(req));
100: } finally {
101: out.close();
102: }
103: }
104:
105: return mapping.findForward(ActionConstants.COMMON_NULL);
106: }
107:
108: protected String exportToRSS(JournalFeed feed, String languageId,
109: Layout layout, ThemeDisplay themeDisplay) throws Exception {
110:
111: String feedURL = PortalUtil.getLayoutFriendlyURL(layout,
112: themeDisplay)
113: + "/journal/rss/"
114: + feed.getGroupId()
115: + "/"
116: + feed.getFeedId();
117:
118: SyndFeed syndFeed = new SyndFeedImpl();
119:
120: syndFeed.setFeedType(feed.getFeedType() + "_"
121: + feed.getFeedVersion());
122: syndFeed.setTitle(feed.getName());
123: syndFeed.setLink(feedURL);
124: syndFeed.setDescription(feed.getDescription());
125:
126: List entries = new ArrayList();
127:
128: syndFeed.setEntries(entries);
129:
130: List articles = JournalRSSUtil.getArticles(feed);
131:
132: if (_log.isDebugEnabled()) {
133: _log.debug("Syndicating " + articles.size() + " articles");
134: }
135:
136: Iterator itr = articles.iterator();
137:
138: while (itr.hasNext()) {
139: JournalArticle article = (JournalArticle) itr.next();
140:
141: String author = PortalUtil.getUserName(article.getUserId(),
142: article.getUserName());
143: String link = getEntryURL(feed, article, layout,
144: themeDisplay);
145:
146: SyndEntry syndEntry = new SyndEntryImpl();
147:
148: syndEntry.setAuthor(author);
149: syndEntry.setTitle(article.getTitle());
150: syndEntry.setLink(link);
151: syndEntry.setPublishedDate(article.getDisplayDate());
152:
153: SyndContent syndContent = new SyndContentImpl();
154:
155: String value = article.getDescription();
156:
157: try {
158: value = processContent(feed, article, languageId,
159: themeDisplay, syndEntry, syndContent);
160: } catch (Exception e) {
161: if (_log.isWarnEnabled()) {
162: _log.warn(e, e);
163: }
164: }
165:
166: syndContent.setType("html");
167: syndContent.setValue(value);
168:
169: syndEntry.setDescription(syndContent);
170:
171: entries.add(syndEntry);
172: }
173:
174: try {
175: return RSSUtil.export(syndFeed);
176: } catch (FeedException fe) {
177: throw new SystemException(fe);
178: } catch (IOException ioe) {
179: throw new SystemException(ioe);
180: }
181: }
182:
183: protected String getEntryURL(JournalFeed feed,
184: JournalArticle article, Layout layout,
185: ThemeDisplay themeDisplay) throws Exception {
186:
187: StringMaker sm = new StringMaker();
188:
189: List hitLayoutIds = JournalContentSearchLocalServiceUtil
190: .getLayoutIds(layout.getGroupId(), layout
191: .isPrivateLayout(), article.getArticleId());
192:
193: if (hitLayoutIds.size() > 0) {
194: Long hitLayoutId = (Long) hitLayoutIds.get(0);
195:
196: Layout hitLayout = LayoutLocalServiceUtil.getLayout(layout
197: .getGroupId(), layout.isPrivateLayout(),
198: hitLayoutId.longValue());
199:
200: return PortalUtil.getLayoutFriendlyURL(hitLayout,
201: themeDisplay);
202: } else if (Validator.isNotNull(feed
203: .getTargetLayoutFriendlyUrl())) {
204: long plid = PortalUtil.getPlidIdFromFriendlyURL(feed
205: .getCompanyId(), feed.getTargetLayoutFriendlyUrl());
206:
207: Layout targetLayout = LayoutLocalServiceUtil
208: .getLayout(plid);
209:
210: sm.append(PortalUtil.getLayoutFriendlyURL(targetLayout,
211: themeDisplay));
212: } else {
213: sm.append(PortalUtil.getLayoutFriendlyURL(layout,
214: themeDisplay));
215: }
216:
217: sm.append("/journal_content/");
218:
219: if (Validator.isNotNull(feed.getTargetPortletId())) {
220: sm.append(feed.getTargetPortletId());
221: } else {
222: sm.append(PortletKeys.JOURNAL_CONTENT);
223: }
224:
225: sm.append(StringPool.SLASH);
226: sm.append(article.getGroupId());
227: sm.append(StringPool.SLASH);
228: sm.append(article.getArticleId());
229:
230: return sm.toString();
231: }
232:
233: protected byte[] getRSS(RenderRequest req) throws Exception {
234: ThemeDisplay themeDisplay = (ThemeDisplay) req
235: .getAttribute(WebKeys.THEME_DISPLAY);
236:
237: JournalFeed feed = null;
238:
239: long id = ParamUtil.getLong(req, "id");
240:
241: long groupId = ParamUtil.getLong(req, "groupId");
242: String feedId = ParamUtil.getString(req, "feedId");
243:
244: if (id > 0) {
245: feed = JournalFeedLocalServiceUtil.getFeed(id);
246: } else {
247: feed = JournalFeedLocalServiceUtil.getFeed(groupId, feedId);
248: }
249:
250: String languageId = LanguageUtil.getLanguageId(req);
251:
252: long plid = PortalUtil.getPlidIdFromFriendlyURL(themeDisplay
253: .getCompanyId(), feed.getTargetLayoutFriendlyUrl());
254:
255: Layout layout = themeDisplay.getLayout();
256:
257: if (plid > 0) {
258: try {
259: layout = LayoutLocalServiceUtil.getLayout(plid);
260: } catch (NoSuchLayoutException nsle) {
261: }
262: }
263:
264: String rss = exportToRSS(feed, languageId, layout, themeDisplay);
265:
266: return rss.getBytes(StringPool.UTF8);
267: }
268:
269: protected String processContent(JournalFeed feed,
270: JournalArticle article, String languageId,
271: ThemeDisplay themeDisplay, SyndEntry syndEntry,
272: SyndContent syndContent) throws Exception {
273:
274: String content = article.getDescription();
275:
276: String contentField = feed.getContentField();
277:
278: if (contentField.equals(JournalFeedImpl.RENDERED_ARTICLE)) {
279: String rendererTemplateId = article.getTemplateId();
280:
281: if (Validator.isNotNull(feed.getRendererTemplateId())) {
282: rendererTemplateId = feed.getRendererTemplateId();
283: }
284:
285: JournalArticleDisplay articleDisplay = JournalContentUtil
286: .getDisplay(feed.getGroupId(), article
287: .getArticleId(), rendererTemplateId,
288: languageId, themeDisplay, 1, _XML_REQUUEST);
289:
290: if (articleDisplay != null) {
291: content = articleDisplay.getContent();
292: }
293: } else if (!contentField
294: .equals(JournalFeedImpl.ARTICLE_DESCRIPTION)) {
295: Document doc = PortalUtil.readDocumentFromXML(article
296: .getContent());
297:
298: XPath xpathSelector = DocumentHelper
299: .createXPath("//dynamic-element[@name='"
300: + contentField + "']");
301:
302: List 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: } else if (elType.equals("image")
317: || elType.equals("image_gallery")) {
318: String url = el.elementText("dynamic-content");
319:
320: url = processURL(feed, url, themeDisplay, syndEntry);
321:
322: content = content + "<br /><br /><img src='"
323: + themeDisplay.getURLPortal() + url + "' />";
324: } else if (elType.equals("text_box")) {
325: syndContent.setType("text");
326:
327: content = el.elementText("dynamic-content");
328: } else {
329: content = el.elementText("dynamic-content");
330: }
331: }
332:
333: return content;
334: }
335:
336: protected String processURL(JournalFeed feed, String url,
337: ThemeDisplay themeDisplay, SyndEntry syndEntry) {
338:
339: url = StringUtil.replace(url, new String[] { "@group_id@",
340: "@image_path@", "@main_path@" },
341: new String[] { String.valueOf(feed.getGroupId()),
342: themeDisplay.getPathImage(),
343: themeDisplay.getPathMain() });
344:
345: List links = JournalRSSUtil.getDLLinks(themeDisplay
346: .getURLPortal(), url);
347: List enclosures = JournalRSSUtil.getDLEnclosures(themeDisplay
348: .getURLPortal(), url);
349:
350: syndEntry.setLinks(links);
351: syndEntry.setEnclosures(enclosures);
352:
353: return url;
354: }
355:
356: private static final String _XML_REQUUEST = "<request><parameters><parameter><name>rss</name><value>true</value>"
357: + "</parameter></parameters></request>";
358:
359: private static Log _log = LogFactory.getLog(RSSAction.class);
360:
361: }
|