PageRenderTime 28ms CodeModel.GetById 0ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/com/example/plugins/tutorial/servlet/IssueCRUD.java

https://bitbucket.org/atlassian/tutorial-jira-simple-issue-crud
Java | 264 lines | 147 code | 23 blank | 94 comment | 14 complexity | 08f1bf453ee4fefc47336678610283c8 MD5 | raw file
  1. package com.example.plugins.tutorial.servlet;
  2. import com.atlassian.crowd.embedded.api.User;
  3. import com.atlassian.jira.bc.issue.IssueService;
  4. import com.atlassian.jira.bc.issue.search.SearchService;
  5. import com.atlassian.jira.bc.project.ProjectService;
  6. import com.atlassian.jira.issue.Issue;
  7. import com.atlassian.jira.issue.IssueInputParameters;
  8. import com.atlassian.jira.issue.MutableIssue;
  9. import com.atlassian.jira.issue.search.SearchException;
  10. import com.atlassian.jira.jql.builder.JqlClauseBuilder;
  11. import com.atlassian.jira.jql.builder.JqlQueryBuilder;
  12. import com.atlassian.jira.project.Project;
  13. import com.atlassian.jira.web.bean.PagerFilter;
  14. import com.atlassian.sal.api.user.UserManager;
  15. import com.atlassian.templaterenderer.TemplateRenderer;
  16. import com.google.common.collect.Maps;
  17. import org.slf4j.Logger;
  18. import org.slf4j.LoggerFactory;
  19. import javax.servlet.ServletException;
  20. import javax.servlet.http.HttpServlet;
  21. import javax.servlet.http.HttpServletRequest;
  22. import javax.servlet.http.HttpServletResponse;
  23. import java.io.IOException;
  24. import java.util.List;
  25. import java.util.Map;
  26. public class IssueCRUD extends HttpServlet {
  27. private static final Logger log = LoggerFactory.getLogger(IssueCRUD.class);
  28. private IssueService issueService;
  29. private ProjectService projectService;
  30. private SearchService searchService;
  31. private UserManager userManager;
  32. private TemplateRenderer renderer;
  33. private static final String LIST_BROWSER_TEMPLATE = "/templates/list.vm";
  34. private static final String NEW_BROWSER_TEMPLATE = "/templates/new.vm";
  35. private static final String EDIT_BROWSER_TEMPLATE = "/templates/edit.vm";
  36. private com.atlassian.jira.user.util.UserManager jiraUserManager;
  37. /**
  38. * Servlet constructor that is auto-wired by Spring to include the following services registered
  39. * in the params.
  40. *
  41. * @param issueService
  42. * @param projectService
  43. * @param searchService
  44. * @param userManager
  45. * @param jiraUserManager
  46. * @param templateRenderer
  47. */
  48. public IssueCRUD(IssueService issueService, ProjectService projectService, SearchService searchService,
  49. UserManager userManager, com.atlassian.jira.user.util.UserManager jiraUserManager,
  50. TemplateRenderer templateRenderer) {
  51. this.issueService = issueService;
  52. this.projectService = projectService;
  53. this.searchService = searchService;
  54. this.userManager = userManager;
  55. this.renderer = templateRenderer;
  56. this.jiraUserManager = jiraUserManager;
  57. }
  58. /**
  59. * GET method for servlet handles both showing a list of issues, the new issue page, and the edit issue page
  60. *
  61. * @param req
  62. * @param resp
  63. * @throws ServletException
  64. * @throws IOException
  65. */
  66. @Override
  67. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  68. if ("y".equals(req.getParameter("new"))) {
  69. // Renders new.vm template if the "new" parameter is passed
  70. // Create an empty context map to pass into the render method
  71. Map<String, Object> context = Maps.newHashMap();
  72. // Make sure to set the contentType otherwise bad things happen
  73. resp.setContentType("text/html;charset=utf-8");
  74. // Render the velocity template (new.vm). Since the new.vm template doesn't need to render
  75. // any in dynamic content, we just pass it an empty context
  76. renderer.render(NEW_BROWSER_TEMPLATE, context, resp.getWriter());
  77. } else if ("y".equals(req.getParameter("edit"))) {
  78. // Renders edit.vm template if the "edit" parameter is passed
  79. // Retrieve issue with the specified key
  80. IssueService.IssueResult issue = issueService.getIssue(getCurrentUser(req), req.getParameter("key"));
  81. Map<String, Object> context = Maps.newHashMap();
  82. context.put("issue", issue.getIssue());
  83. resp.setContentType("text/html;charset=utf-8");
  84. // Render the template with the issue inside the context
  85. renderer.render(EDIT_BROWSER_TEMPLATE, context, resp.getWriter());
  86. } else {
  87. // Render the list of issues (list.vm) if no params are passed in
  88. List<Issue> issues = getIssues(req);
  89. Map<String, Object> context = Maps.newHashMap();
  90. context.put("issues", issues);
  91. resp.setContentType("text/html;charset=utf-8");
  92. // Pass in the list of issues as the context
  93. renderer.render(LIST_BROWSER_TEMPLATE, context, resp.getWriter());
  94. }
  95. }
  96. /**
  97. * Returns a list of issues used to populate the list.vm template in the GET request
  98. *
  99. * @param req
  100. * @return
  101. */
  102. private List<Issue> getIssues(HttpServletRequest req) {
  103. // User is required to carry out a search
  104. User user = getCurrentUser(req);
  105. // search issues
  106. // The search interface requires JQL clause... so let's build one
  107. JqlClauseBuilder jqlClauseBuilder = JqlQueryBuilder.newClauseBuilder();
  108. // Our JQL clause is simple project="TUTORIAL"
  109. com.atlassian.query.Query query = jqlClauseBuilder.project("TUTORIAL").buildQuery();
  110. // A page filter is used to provide pagination. Let's use an unlimited filter to
  111. // to bypass pagination.
  112. PagerFilter pagerFilter = PagerFilter.getUnlimitedFilter();
  113. com.atlassian.jira.issue.search.SearchResults searchResults = null;
  114. try {
  115. // Perform search results
  116. searchResults = searchService.search(user, query, pagerFilter);
  117. } catch (SearchException e) {
  118. e.printStackTrace();
  119. }
  120. // return the results
  121. return searchResults.getIssues();
  122. }
  123. /**
  124. * Helper method for getting the current user
  125. *
  126. * @param req
  127. * @return
  128. */
  129. private User getCurrentUser(HttpServletRequest req) {
  130. // To get the current user, we first get the username from the session.
  131. // Then we pass that over to the jiraUserManager in order to get an
  132. // actual User object.
  133. return jiraUserManager.getUser(userManager.getRemoteUsername(req));
  134. }
  135. /**
  136. * POST method for servlet handles creating new issues and updating existing issues
  137. *
  138. * @param req
  139. * @param resp
  140. * @throws ServletException
  141. * @throws IOException
  142. */
  143. @Override
  144. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  145. Map params = req.getParameterMap();
  146. User user = getCurrentUser(req);
  147. if ("y".equals(req.getParameter("edit"))) {
  148. // Perform update if the "edit" param is passed in
  149. // First get the issue from the key that's passed in
  150. IssueService.IssueResult issueResult = issueService.getIssue(user, req.getParameter("key"));
  151. MutableIssue issue = issueResult.getIssue();
  152. // Next we need to validate the updated issue
  153. IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
  154. issueInputParameters.setSummary(req.getParameter("summary"));
  155. issueInputParameters.setDescription(req.getParameter("description"));
  156. IssueService.UpdateValidationResult result = issueService.validateUpdate(user, issue.getId(),
  157. issueInputParameters);
  158. if (result.getErrorCollection().hasAnyErrors()) {
  159. // If the validation fails, we re-render the edit page with the errors in the context
  160. Map<String, Object> context = Maps.newHashMap();
  161. context.put("issue", issue);
  162. context.put("errors", result.getErrorCollection().getErrors());
  163. resp.setContentType("text/html;charset=utf-8");
  164. renderer.render(EDIT_BROWSER_TEMPLATE, context, resp.getWriter());
  165. } else {
  166. // If the validation passes, we perform the update then redirect the user back to the
  167. // page with the list of issues
  168. issueService.update(user, result);
  169. resp.sendRedirect("issuecrud");
  170. }
  171. } else {
  172. // Perform creation if the "new" param is passed in
  173. // First we need to validate the new issue being created
  174. IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
  175. // We're only going to set the summary and description. The rest are hard-coded to
  176. // simplify this tutorial.
  177. issueInputParameters.setSummary(req.getParameter("summary"));
  178. issueInputParameters.setDescription(req.getParameter("description"));
  179. // We need to set the assignee, reporter, project, and issueType...
  180. // For assignee and reporter, we'll just use the currentUser
  181. issueInputParameters.setAssigneeId(user.getName());
  182. issueInputParameters.setReporterId(user.getName());
  183. // We hard-code the project name to be the project with the TUTORIAL key
  184. Project project = projectService.getProjectByKey(user, "TUTORIAL").getProject();
  185. issueInputParameters.setProjectId(project.getId());
  186. // We also hard-code the issueType to be a "bug" == 1
  187. issueInputParameters.setIssueTypeId("1");
  188. // Perform the validation
  189. IssueService.CreateValidationResult result = issueService.validateCreate(user, issueInputParameters);
  190. if (result.getErrorCollection().hasAnyErrors()) {
  191. // If the validation fails, render the list of issues with the error in a flash message
  192. List<Issue> issues = getIssues(req);
  193. Map<String, Object> context = Maps.newHashMap();
  194. context.put("issues", issues);
  195. context.put("errors", result.getErrorCollection().getErrors());
  196. resp.setContentType("text/html;charset=utf-8");
  197. renderer.render(LIST_BROWSER_TEMPLATE, context, resp.getWriter());
  198. } else {
  199. // If the validation passes, redirect the user to the main issue list page
  200. issueService.create(user, result);
  201. resp.sendRedirect("issuecrud");
  202. }
  203. }
  204. }
  205. /**
  206. * DELETE method handles AJAX based deletion of issues. Returns JSON status.
  207. *
  208. * @param req
  209. * @param resp
  210. * @throws ServletException
  211. * @throws IOException
  212. */
  213. @Override
  214. protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  215. User user = getCurrentUser(req);
  216. // This will be the output string that we will put the JSON in
  217. String respStr = "";
  218. // Retrieve the issue with the specified key
  219. IssueService.IssueResult issue = issueService.getIssue(user, req.getParameter("key"));
  220. if (issue.isValid()) {
  221. // If the issue is found, let's delete it...
  222. // ... but first, we must validate that user can delete issue
  223. IssueService.DeleteValidationResult result = issueService.validateDelete(user, issue.getIssue().getId());
  224. if (result.getErrorCollection().hasAnyErrors()) {
  225. // If the validation fails, we send the error back to the user in a JSON payload
  226. respStr = "{ \"success\": \"false\", error: \"" + result.getErrorCollection().getErrors().get(0) + "\" }";
  227. } else {
  228. // If the validation passes, we perform the delete, then return a success msg back to the user
  229. issueService.delete(user, result);
  230. respStr = "{ \"success\" : \"true\" }";
  231. }
  232. } else {
  233. // The issue can't be found... so we send an error to the user
  234. respStr = "{ \"success\" : \"false\", error: \"Couldn't find issue\"}";
  235. }
  236. // We set the content-type to application/json here so that the AJAX client knows how to deal with it
  237. resp.setContentType("application/json;charset=utf-8");
  238. // Send the raw output string we put together
  239. resp.getWriter().write(respStr);
  240. }
  241. }