1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.rssaggregator.generator;
35
36 import static info.magnolia.module.rssaggregator.RSSAggregator.*;
37 import static java.lang.String.format;
38
39 import info.magnolia.cms.beans.config.ServerConfiguration;
40 import info.magnolia.jcr.util.NodeTypes;
41 import info.magnolia.jcr.util.PropertyUtil;
42 import info.magnolia.jcr.util.SessionUtil;
43 import info.magnolia.module.rssaggregator.RSSAggregatorConstants;
44 import info.magnolia.module.rssaggregator.util.ContentMapper;
45 import info.magnolia.module.rssaggregator.util.MagnoliaTemplate;
46 import info.magnolia.objectfactory.Components;
47
48 import java.util.Date;
49 import java.util.List;
50
51 import javax.jcr.Node;
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang3.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import com.rometools.rome.feed.synd.SyndContent;
59 import com.rometools.rome.feed.synd.SyndContentImpl;
60 import com.rometools.rome.feed.synd.SyndEntry;
61 import com.rometools.rome.feed.synd.SyndEntryImpl;
62 import com.rometools.rome.feed.synd.SyndFeed;
63 import com.rometools.rome.feed.synd.SyndLink;
64 import com.rometools.rome.feed.synd.SyndLinkImpl;
65
66
67
68
69 public class PlanetFeedGenerator extends AbstractSyndFeedGenerator implements Cloneable {
70
71 private static final ContentMapper<SyndEntry> MAPPER = new FeedEntryMapper();
72
73 private static final Logger log = LoggerFactory.getLogger(PlanetFeedGenerator.class);
74
75 private static final String FEED_TYPE_RSS = "rss_2.0";
76 private static final String FEED_TYPE_ATOM = "atom_1.0";
77
78 private static final String DEFAULT_DESCRIPTION = "Magnolia Planet feed post content";
79
80 private MagnoliaTemplate magnoliaTemplate;
81
82 private String feedPath;
83 private static String feedType;
84
85 public PlanetFeedGenerator() {
86 this.magnoliaTemplate = new MagnoliaTemplate();
87 }
88
89 public void setFeedPath(String feedPath) {
90 this.feedPath = feedPath;
91 }
92
93 @Override
94 public Feed generate() throws FeedGenerationException {
95 feedType = getFeedType();
96
97 try {
98 SyndFeed syndFeed = newSyndFeed();
99 syndFeed.setFeedType(feedType);
100 setFeedInfo(syndFeed);
101 syndFeed.setEntries(loadFeedEntries());
102
103 String xml = syndFeedToXml(syndFeed);
104
105 return new Feed(xml, DEFAULT_CONTENT_TYPE, DEFAULT_ENCODING);
106 } catch (Exception e) {
107 String message = format("Failed to generate Feed using generator '%s'", getClass().getName());
108 log.error(message, e);
109 throw new FeedGenerationException(message, e);
110 }
111 }
112
113 @Override
114 public List<SyndEntry> loadFeedEntries() {
115 String entriesQuery = format("/jcr:root%s/planetData[1]/*/* order by @pubDate descending", feedPath);
116 return magnoliaTemplate.xpathQueryForList(RSSAggregatorConstants.WORKSPACE, entriesQuery, NodeTypes.Content.NAME, MAPPER);
117 }
118
119 @Override
120 @SuppressWarnings(value = "unchecked")
121 public void setFeedInfo(SyndFeed feed) {
122
123 Node feedDescr = SessionUtil.getNode(RSSAggregatorConstants.WORKSPACE, feedPath);
124 feed.setTitle(StringUtils.defaultIfEmpty(PropertyUtil.getString(feedDescr, "title"), ""));
125 feed.setDescription(StringUtils.defaultIfEmpty(PropertyUtil.getString(feedDescr, "description"), DEFAULT_DESCRIPTION));
126 String link = Components.getComponent(ServerConfiguration.class).getDefaultBaseUrl();
127
128
129 if (FEED_TYPE_ATOM.equals(feedType)) {
130 if (!StringUtils.endsWith(link, "/")) {
131 link += "/";
132 }
133 feed.setUri(link);
134 feed.setPublishedDate(new Date());
135
136 SyndLink selfLink = new SyndLinkImpl();
137 selfLink.setRel("self");
138 selfLink.setHref(link);
139 selfLink.setType("application/atom+xml");
140 feed.getLinks().add(selfLink);
141 } else {
142
143 feed.setLink(link);
144 }
145 }
146
147 @Override
148 public Object clone() throws CloneNotSupportedException {
149 return super.clone();
150 }
151
152
153
154
155
156
157 protected String getFeedType() {
158 String feedType = "";
159
160 if (StringUtils.endsWith(this.feedPath, "/rss")) {
161 this.feedPath = StringUtils.substringBeforeLast(this.feedPath, "/rss");
162 feedType = FEED_TYPE_RSS;
163 } else {
164 if (StringUtils.endsWith(this.feedPath, "/atom")) {
165 this.feedPath = StringUtils.substringBeforeLast(this.feedPath, "/atom");
166 feedType = FEED_TYPE_ATOM;
167 }
168 }
169 if (StringUtils.isBlank(feedType)) {
170 feedType = DEFAULT_FEEDTYPE;
171 }
172 return feedType;
173 }
174
175 private static class FeedEntryMapper implements ContentMapper<SyndEntry> {
176
177 @Override
178 public SyndEntry map(Node content) throws RepositoryException {
179
180 SyndEntry entry = new SyndEntryImpl();
181
182
183 entry.setTitle(PropertyUtil.getString(content, "title"));
184 entry.setLink(PropertyUtil.getString(content, "link"));
185 entry.setAuthor(PropertyUtil.getString(content, "author"));
186 if (content.hasProperty("pubDate")) {
187 entry.setPublishedDate(PropertyUtil.getDate(content, "pubDate").getTime());
188 } else {
189 entry.setPublishedDate(new Date());
190 }
191 SyndContent description = new SyndContentImpl();
192
193 description.setType("text/html");
194 description.setValue(PropertyUtil.getString(content, "description"));
195 entry.setDescription(description);
196
197
198 if (FEED_TYPE_ATOM.equals(feedType)) {
199 entry.setUri(PropertyUtil.getString(content, "link"));
200 }
201
202
203 return entry;
204 }
205 }
206 }