1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.exoplatform.wcm.connector.collaboration;
18
19 import java.io.ByteArrayInputStream;
20 import java.text.DateFormat;
21 import java.text.SimpleDateFormat;
22 import java.util.ArrayList;
23 import java.util.Date;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.jcr.Node;
30 import javax.ws.rs.GET;
31 import javax.ws.rs.Path;
32 import javax.ws.rs.QueryParam;
33 import javax.ws.rs.core.MediaType;
34 import javax.ws.rs.core.Response;
35 import javax.xml.parsers.DocumentBuilderFactory;
36 import javax.xml.transform.dom.DOMSource;
37
38 import org.exoplatform.services.jcr.util.Text;
39 import org.exoplatform.services.log.ExoLogger;
40 import org.exoplatform.services.log.Log;
41 import org.exoplatform.services.rest.resource.ResourceContainer;
42 import org.exoplatform.services.wcm.core.WCMConfigurationService;
43 import org.exoplatform.services.wcm.publication.WCMComposer;
44 import org.exoplatform.services.wcm.utils.WCMCoreUtils;
45 import org.exoplatform.wcm.connector.BaseConnector;
46 import org.w3c.dom.Document;
47
48 import com.sun.syndication.feed.synd.SyndContent;
49 import com.sun.syndication.feed.synd.SyndContentImpl;
50 import com.sun.syndication.feed.synd.SyndEntry;
51 import com.sun.syndication.feed.synd.SyndEntryImpl;
52 import com.sun.syndication.feed.synd.SyndFeed;
53 import com.sun.syndication.feed.synd.SyndFeedImpl;
54 import com.sun.syndication.io.SyndFeedOutput;
55
56
57
58
59
60
61
62
63 @Path("/feed/")
64 public class RssConnector extends BaseConnector implements ResourceContainer {
65
66
67 static private String WORKSPACE = "workspace" ;
68
69
70 static private String REPOSITORY = "repository" ;
71
72
73 static private String RSS_VERSION = "rss_2.0" ;
74
75
76 static private String FEED_TITLE = "exo:feedTitle" ;
77
78
79 static private String DESCRIPTION = "exo:description" ;
80
81
82 static private String TITLE = "exo:title";
83
84
85 static private String LINK = "exo:link" ;
86
87
88 static private String SUMMARY = "exo:summary";
89
90
91 static private String DETAIL_PAGE = "detail-page";
92
93
94 static private String DETAIL_PARAM = "detail-param";
95
96
97 private WCMComposer wcmComposer;
98
99
100 private WCMConfigurationService wcmConfigurationService;
101
102 private static final Log LOG = ExoLogger.getLogger(RssConnector.class.getName());
103
104
105
106
107 public RssConnector() {
108 this.wcmConfigurationService = WCMCoreUtils.getService(WCMConfigurationService.class);
109 this.wcmComposer = WCMCoreUtils.getService(WCMComposer.class);
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 @GET
134 @Path("/rss/")
135 public Response generate(@QueryParam("repository") String repository,
136 @QueryParam("workspace") String workspace,
137 @QueryParam("server") String server,
138 @QueryParam("siteName") String siteName,
139 @QueryParam("title") String title,
140 @QueryParam("desc") String desc,
141 @QueryParam("folderPath") String folderPath,
142 @QueryParam("orderBy") String orderBy,
143 @QueryParam("orderType") String orderType,
144 @QueryParam("lang") String lang,
145 @QueryParam("detailPage") String detailPage,
146 @QueryParam("detailParam") String detailParam,
147 @QueryParam("recursive") String recursive) throws Exception {
148 Map<String, String> contextRss = new HashMap<String, String>();
149 contextRss.put(REPOSITORY, repository);
150 contextRss.put(WORKSPACE, workspace);
151 contextRss.put(RSS_VERSION, "rss_2.0");
152 contextRss.put(FEED_TITLE, title);
153 if (desc == null)
154 desc = "Powered by eXo WCM-" + WCMCoreUtils.getProjectVersion();
155 contextRss.put(DESCRIPTION, desc);
156
157 contextRss.put(LINK, server);
158
159 if (detailPage == null)
160 detailPage = wcmConfigurationService.getRuntimeContextParam(WCMConfigurationService.PARAMETERIZED_PAGE_URI);
161 contextRss.put(DETAIL_PAGE, detailPage);
162 if (detailParam == null) detailParam = "content-id";
163 contextRss.put(DETAIL_PARAM, detailParam);
164
165
166 HashMap<String, String> filters = new HashMap<String, String>();
167 filters.put(WCMComposer.FILTER_MODE, WCMComposer.MODE_LIVE);
168 if (orderType == null) orderType = "DESC";
169 if (orderBy == null) orderBy = "publication:liveDate";
170 if (lang == null) lang = "en";
171 filters.put(WCMComposer.FILTER_ORDER_BY, orderBy);
172 filters.put(WCMComposer.FILTER_ORDER_TYPE, orderType);
173 filters.put(WCMComposer.FILTER_LANGUAGE, lang);
174 filters.put(WCMComposer.FILTER_RECURSIVE, recursive);
175
176 String path=null;
177 if (folderPath!=null) {
178 path = folderPath;
179 }
180
181 List<Node> nodes = wcmComposer.getContents(workspace,
182 path,
183 filters,
184 WCMCoreUtils.getUserSessionProvider());
185
186 String feedXML = generateRSS(nodes, contextRss);
187
188 Document document = DocumentBuilderFactory.newInstance()
189 .newDocumentBuilder()
190 .parse(new ByteArrayInputStream(feedXML.getBytes()));
191
192 DateFormat dateFormat = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT);
193 Response response = Response.ok(new DOMSource(document), MediaType.TEXT_XML)
194 .header(LAST_MODIFIED_PROPERTY, dateFormat.format(new Date()))
195 .build();
196 return response;
197 }
198
199
200
201
202
203
204
205 private String generateRSS(List<Node> nodes , Map<String, String> context) {
206 String rssVersion = context.get(RSS_VERSION) ;
207 String feedTitle = context.get(FEED_TITLE) ;
208 String feedDescription = context.get(DESCRIPTION) ;
209 String feedLink = context.get(LINK) ;
210 String detailPage = context.get(DETAIL_PAGE) ;
211 String detailParam = context.get(DETAIL_PARAM) ;
212 String repository = context.get(REPOSITORY) ;
213 String workspace = context.get(WORKSPACE) ;
214 String contentUrl;
215 if (!feedLink.endsWith("/")) {
216 contentUrl = feedLink + "/" + detailPage + "?" + detailParam + "=/" + repository + "/"
217 + workspace;
218 } else {
219 contentUrl = feedLink + detailPage + "?" + detailParam + "=/" + repository + "/" + workspace;
220 }
221
222 if(feedTitle == null || feedTitle.length() == 0) feedTitle = "" ;
223 try {
224
225 SyndFeed feed = new SyndFeedImpl();
226 feed.setFeedType(rssVersion);
227 feed.setTitle(feedTitle.replaceAll(" ", " "));
228 feed.setLink(feedLink);
229 feed.setDescription(feedDescription.replaceAll(" ", " "));
230 feed.setEncoding("UTF-8");
231
232 List<SyndEntry> entries = new ArrayList<SyndEntry>();
233 Iterator<Node> iter = nodes.iterator();
234 while (iter.hasNext()) {
235 Node node = iter.next();
236
237 StringBuilder url= new StringBuilder();
238 url.append(contentUrl);
239 if (node.isNodeType("nt:frozenNode")) {
240 String uuid = node.getProperty("jcr:frozenUuid").getString();
241 Node originalNode = node.getSession().getNodeByUUID(uuid);
242 url.append(originalNode.getPath());
243 url.append("&version=");
244 url.append(node.getParent().getName());
245 } else {
246 url.append(node.getPath());
247 }
248
249 SyndEntry entry = new SyndEntryImpl();
250
251 if (node.hasProperty(TITLE)) {
252 String nTitle = node.getProperty(TITLE).getString();
253
254 nTitle = Text.unescapeIllegalJcrChars(new String(nTitle.getBytes("UTF-8")));
255 entry.setTitle(Text.encodeIllegalXMLCharacters(nTitle).replaceAll(""", "\"").replaceAll("'", "\'"));
256 }
257 else entry.setTitle("") ;
258
259 entry.setLink(url.toString());
260 SyndContent description = new SyndContentImpl();
261 description.setType("text/plain");
262
263 if (node.hasProperty(SUMMARY)){
264 String summary=Text.encodeIllegalXMLCharacters(node.getProperty(SUMMARY)
265 .getString())
266 .replaceAll(" ", " ").replaceAll("&quot;", "\"").replaceAll("'", "\'");
267 description.setValue(summary);
268 }else
269 description.setValue("");
270
271 entry.setDescription(description);
272 entries.add(entry);
273 entry.getEnclosures() ;
274 }
275 feed.setEntries(entries);
276
277 SyndFeedOutput output = new SyndFeedOutput();
278 return output.outputString(feed);
279 } catch (Exception e) {
280 if (LOG.isErrorEnabled()) {
281 LOG.error("Error when perform generateRSS: ", e);
282 }
283 }
284 return null;
285 }
286
287
288
289
290 protected String getContentStorageType() throws Exception {
291 return null;
292 }
293
294
295
296
297 protected Node getRootContentStorage(Node node) throws Exception {
298 return null;
299 }
300 }