You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SyndicationServlet.java 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright 2011 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit;
  17. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import java.util.Map;
  23. import javax.servlet.http.HttpServlet;
  24. import org.eclipse.jgit.lib.ObjectId;
  25. import org.eclipse.jgit.lib.Repository;
  26. import org.eclipse.jgit.revwalk.RevCommit;
  27. import org.slf4j.Logger;
  28. import org.slf4j.LoggerFactory;
  29. import com.gitblit.AuthenticationFilter.AuthenticatedRequest;
  30. import com.gitblit.models.FeedEntryModel;
  31. import com.gitblit.models.ProjectModel;
  32. import com.gitblit.models.RefModel;
  33. import com.gitblit.models.RepositoryModel;
  34. import com.gitblit.models.UserModel;
  35. import com.gitblit.utils.HttpUtils;
  36. import com.gitblit.utils.JGitUtils;
  37. import com.gitblit.utils.StringUtils;
  38. import com.gitblit.utils.SyndicationUtils;
  39. /**
  40. * SyndicationServlet generates RSS 2.0 feeds and feed links.
  41. *
  42. * Access to this servlet is protected by the SyndicationFilter.
  43. *
  44. * @author James Moger
  45. *
  46. */
  47. public class SyndicationServlet extends HttpServlet {
  48. private static final long serialVersionUID = 1L;
  49. private transient Logger logger = LoggerFactory.getLogger(SyndicationServlet.class);
  50. /**
  51. * Create a feed link for the specified repository and branch/tag/commit id.
  52. *
  53. * @param baseURL
  54. * @param repository
  55. * the repository name
  56. * @param objectId
  57. * the branch, tag, or first commit for the feed
  58. * @param length
  59. * the number of commits to include in the feed
  60. * @return an RSS feed url
  61. */
  62. public static String asLink(String baseURL, String repository, String objectId, int length) {
  63. if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
  64. baseURL = baseURL.substring(0, baseURL.length() - 1);
  65. }
  66. StringBuilder url = new StringBuilder();
  67. url.append(baseURL);
  68. url.append(Constants.SYNDICATION_PATH);
  69. url.append(repository);
  70. if (!StringUtils.isEmpty(objectId) || length > 0) {
  71. StringBuilder parameters = new StringBuilder("?");
  72. if (StringUtils.isEmpty(objectId)) {
  73. parameters.append("l=");
  74. parameters.append(length);
  75. } else {
  76. parameters.append("h=");
  77. parameters.append(objectId);
  78. if (length > 0) {
  79. parameters.append("&l=");
  80. parameters.append(length);
  81. }
  82. }
  83. url.append(parameters);
  84. }
  85. return url.toString();
  86. }
  87. /**
  88. * Determines the appropriate title for a feed.
  89. *
  90. * @param repository
  91. * @param objectId
  92. * @return title of the feed
  93. */
  94. public static String getTitle(String repository, String objectId) {
  95. String id = objectId;
  96. if (!StringUtils.isEmpty(id)) {
  97. if (id.startsWith(org.eclipse.jgit.lib.Constants.R_HEADS)) {
  98. id = id.substring(org.eclipse.jgit.lib.Constants.R_HEADS.length());
  99. } else if (id.startsWith(org.eclipse.jgit.lib.Constants.R_REMOTES)) {
  100. id = id.substring(org.eclipse.jgit.lib.Constants.R_REMOTES.length());
  101. } else if (id.startsWith(org.eclipse.jgit.lib.Constants.R_TAGS)) {
  102. id = id.substring(org.eclipse.jgit.lib.Constants.R_TAGS.length());
  103. }
  104. }
  105. return MessageFormat.format("{0} ({1})", repository, id);
  106. }
  107. /**
  108. * Generates the feed content.
  109. *
  110. * @param request
  111. * @param response
  112. * @throws javax.servlet.ServletException
  113. * @throws java.io.IOException
  114. */
  115. private void processRequest(javax.servlet.http.HttpServletRequest request,
  116. javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
  117. java.io.IOException {
  118. String servletUrl = request.getContextPath() + request.getServletPath();
  119. String url = request.getRequestURI().substring(servletUrl.length());
  120. if (url.charAt(0) == '/' && url.length() > 1) {
  121. url = url.substring(1);
  122. }
  123. String repositoryName = url;
  124. String objectId = request.getParameter("h");
  125. String l = request.getParameter("l");
  126. String page = request.getParameter("pg");
  127. String searchString = request.getParameter("s");
  128. Constants.SearchType searchType = Constants.SearchType.COMMIT;
  129. if (!StringUtils.isEmpty(request.getParameter("st"))) {
  130. Constants.SearchType type = Constants.SearchType.forName(request.getParameter("st"));
  131. if (type != null) {
  132. searchType = type;
  133. }
  134. }
  135. int length = GitBlit.getInteger(Keys.web.syndicationEntries, 25);
  136. if (StringUtils.isEmpty(objectId)) {
  137. objectId = org.eclipse.jgit.lib.Constants.HEAD;
  138. }
  139. if (!StringUtils.isEmpty(l)) {
  140. try {
  141. length = Integer.parseInt(l);
  142. } catch (NumberFormatException x) {
  143. }
  144. }
  145. int offset = 0;
  146. if (!StringUtils.isEmpty(page)) {
  147. try {
  148. offset = length * Integer.parseInt(page);
  149. } catch (NumberFormatException x) {
  150. }
  151. }
  152. response.setContentType("application/rss+xml; charset=UTF-8");
  153. boolean isProjectFeed = false;
  154. String feedName = null;
  155. String feedTitle = null;
  156. String feedDescription = null;
  157. List<String> repositories = null;
  158. if (repositoryName.indexOf('/') == -1 && !repositoryName.toLowerCase().endsWith(".git")) {
  159. // try to find a project
  160. UserModel user = null;
  161. if (request instanceof AuthenticatedRequest) {
  162. user = ((AuthenticatedRequest) request).getUser();
  163. }
  164. ProjectModel project = GitBlit.self().getProjectModel(repositoryName, user);
  165. if (project != null) {
  166. isProjectFeed = true;
  167. repositories = new ArrayList<String>(project.repositories);
  168. // project feed
  169. feedName = project.name;
  170. feedTitle = project.title;
  171. feedDescription = project.description;
  172. }
  173. }
  174. if (repositories == null) {
  175. // could not find project, assume this is a repository
  176. repositories = Arrays.asList(repositoryName);
  177. }
  178. boolean mountParameters = GitBlit.getBoolean(Keys.web.mountParameters, true);
  179. String urlPattern;
  180. if (mountParameters) {
  181. // mounted parameters
  182. urlPattern = "{0}/commit/{1}/{2}";
  183. } else {
  184. // parameterized parameters
  185. urlPattern = "{0}/commit/?r={1}&h={2}";
  186. }
  187. String gitblitUrl = HttpUtils.getGitblitURL(request);
  188. char fsc = GitBlit.getChar(Keys.web.forwardSlashCharacter, '/');
  189. List<FeedEntryModel> entries = new ArrayList<FeedEntryModel>();
  190. for (String name : repositories) {
  191. Repository repository = GitBlit.self().getRepository(name);
  192. RepositoryModel model = GitBlit.self().getRepositoryModel(name);
  193. if (!isProjectFeed) {
  194. // single-repository feed
  195. feedName = model.name;
  196. feedTitle = model.name;
  197. feedDescription = model.description;
  198. }
  199. List<RevCommit> commits;
  200. if (StringUtils.isEmpty(searchString)) {
  201. // standard log/history lookup
  202. commits = JGitUtils.getRevLog(repository, objectId, offset, length);
  203. } else {
  204. // repository search
  205. commits = JGitUtils.searchRevlogs(repository, objectId, searchString, searchType,
  206. offset, length);
  207. }
  208. Map<ObjectId, List<RefModel>> allRefs = JGitUtils.getAllRefs(repository, model.showRemoteBranches);
  209. // convert RevCommit to SyndicatedEntryModel
  210. for (RevCommit commit : commits) {
  211. FeedEntryModel entry = new FeedEntryModel();
  212. entry.title = commit.getShortMessage();
  213. entry.author = commit.getAuthorIdent().getName();
  214. entry.link = MessageFormat.format(urlPattern, gitblitUrl,
  215. StringUtils.encodeURL(model.name.replace('/', fsc)), commit.getName());
  216. entry.published = commit.getCommitterIdent().getWhen();
  217. entry.contentType = "text/html";
  218. String message = GitBlit.self().processCommitMessage(model.name,
  219. commit.getFullMessage());
  220. entry.content = message;
  221. entry.repository = model.name;
  222. entry.branch = objectId;
  223. entry.tags = new ArrayList<String>();
  224. // add commit id and parent commit ids
  225. entry.tags.add("commit:" + commit.getName());
  226. for (RevCommit parent : commit.getParents()) {
  227. entry.tags.add("parent:" + parent.getName());
  228. }
  229. // add refs to tabs list
  230. List<RefModel> refs = allRefs.get(commit.getId());
  231. if (refs != null && refs.size() > 0) {
  232. for (RefModel ref : refs) {
  233. entry.tags.add("ref:" + ref.getName());
  234. }
  235. }
  236. entries.add(entry);
  237. }
  238. }
  239. // sort & truncate the feed
  240. Collections.sort(entries);
  241. if (entries.size() > length) {
  242. // clip the list
  243. entries = entries.subList(0, length);
  244. }
  245. String feedLink;
  246. if (isProjectFeed) {
  247. // project feed
  248. if (mountParameters) {
  249. // mounted url
  250. feedLink = MessageFormat.format("{0}/project/{1}", gitblitUrl,
  251. StringUtils.encodeURL(feedName));
  252. } else {
  253. // parameterized url
  254. feedLink = MessageFormat.format("{0}/project/?p={1}", gitblitUrl,
  255. StringUtils.encodeURL(feedName));
  256. }
  257. } else {
  258. // repository feed
  259. if (mountParameters) {
  260. // mounted url
  261. feedLink = MessageFormat.format("{0}/summary/{1}", gitblitUrl,
  262. StringUtils.encodeURL(feedName));
  263. } else {
  264. // parameterized url
  265. feedLink = MessageFormat.format("{0}/summary/?r={1}", gitblitUrl,
  266. StringUtils.encodeURL(feedName));
  267. }
  268. }
  269. try {
  270. SyndicationUtils.toRSS(gitblitUrl, feedLink, getTitle(feedTitle, objectId),
  271. feedDescription, entries, response.getOutputStream());
  272. } catch (Exception e) {
  273. logger.error("An error occurred during feed generation", e);
  274. }
  275. }
  276. @Override
  277. protected void doPost(javax.servlet.http.HttpServletRequest request,
  278. javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
  279. java.io.IOException {
  280. processRequest(request, response);
  281. }
  282. @Override
  283. protected void doGet(javax.servlet.http.HttpServletRequest request,
  284. javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
  285. java.io.IOException {
  286. processRequest(request, response);
  287. }
  288. }