PageRenderTime 25ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/ru/megaplan/jira/plugins/workflow/util/traveller/impl/WorkflowTravellerImpl.java

https://github.com/Firfi/jira-workflow-traveller
Java | 272 lines | 229 code | 32 blank | 11 comment | 54 complexity | c33cfbac7f535b0f103974233c732338 MD5 | raw file
  1. package ru.megaplan.jira.plugins.workflow.util.traveller.impl;
  2. import com.atlassian.crowd.embedded.api.User;
  3. import com.atlassian.jira.bc.issue.IssueService;
  4. import com.atlassian.jira.component.ComponentAccessor;
  5. import com.atlassian.jira.config.StatusManager;
  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.status.Status;
  10. import com.atlassian.jira.security.JiraAuthenticationContext;
  11. import com.atlassian.jira.util.collect.MultiMap;
  12. import com.atlassian.jira.util.collect.MultiMaps;
  13. import com.atlassian.jira.workflow.IssueWorkflowManager;
  14. import com.atlassian.jira.workflow.JiraWorkflow;
  15. import com.atlassian.jira.workflow.WorkflowManager;
  16. import com.atlassian.jira.workflow.WorkflowSchemeManager;
  17. import com.atlassian.plugin.web.descriptors.ConditionalDescriptor;
  18. import com.google.common.collect.Sets;
  19. import com.opensymphony.workflow.Workflow;
  20. import com.opensymphony.workflow.loader.ActionDescriptor;
  21. import com.opensymphony.workflow.loader.ConditionalResultDescriptor;
  22. import com.opensymphony.workflow.loader.ResultDescriptor;
  23. import com.opensymphony.workflow.loader.StepDescriptor;
  24. import org.apache.log4j.Logger;
  25. import org.ofbiz.core.entity.GenericValue;
  26. import ru.megaplan.jira.plugins.workflow.util.traveller.WorkflowTraveller;
  27. import java.awt.event.ComponentAdapter;
  28. import java.util.*;
  29. /**
  30. * Created with IntelliJ IDEA.
  31. * User: firfi
  32. * Date: 19.06.12
  33. * Time: 12:43
  34. * To change this template use File | Settings | File Templates.
  35. */
  36. public class WorkflowTravellerImpl implements WorkflowTraveller {
  37. private final static Logger log = Logger.getLogger(WorkflowTravellerImpl.class);
  38. private final IssueService issueService;
  39. private final IssueWorkflowManager issueWorkflowManager;
  40. private final WorkflowManager workflowManager;
  41. private final StatusManager statusManager;
  42. private final JiraAuthenticationContext jiraAuthenticationContext;
  43. WorkflowTravellerImpl(IssueService issueService,
  44. IssueWorkflowManager issueWorkflowManager,
  45. WorkflowManager workflowManager,
  46. StatusManager statusManager, JiraAuthenticationContext jiraAuthenticationContext) {
  47. this.issueService = issueService;
  48. this.issueWorkflowManager = issueWorkflowManager;
  49. this.workflowManager = workflowManager;
  50. this.statusManager = statusManager;
  51. this.jiraAuthenticationContext = jiraAuthenticationContext;
  52. }
  53. @Override
  54. public List<IssueService.IssueResult> travel(User user,
  55. Issue issue,
  56. Status to, MultiMap<String, Object, ? extends List> params,
  57. final List<IssueService.TransitionValidationResult> errorResults) {
  58. if (user == null) throw new IllegalArgumentException("user is null, gimme some body");
  59. if (issue == null) throw new IllegalArgumentException("issue is null");
  60. log.debug("issue : " + issue.getKey());
  61. if (to == null) throw new IllegalArgumentException("to status is null");
  62. if (params == null) params = MultiMaps.createListMultiMap();
  63. if (checkForNullValues(params)) throw new IllegalArgumentException("I do not accept null values in param map");
  64. if (to.equals(issue.getStatusObject())) {
  65. log.error("to and from are equals");
  66. throw new IllegalArgumentException("to and from are equals");
  67. }
  68. log.debug("travel start... args : " + user.getName() + " to : " + to.getName() + "; issue : " + issue.getKey() + " params length : " + params.size());
  69. Set<Status> availableWorkflowStatuses = getAllAvailableWorkflowStatuses(issue);
  70. if (!availableWorkflowStatuses.contains(to))
  71. throw new IllegalArgumentException("passed status : " + to.getName() + " does not exist in available statuses here or even not exist in issue workflow");
  72. List<IssueService.IssueResult> validResults = simpleTravel(user, issue, to, params, errorResults);
  73. //TODO:add not simple travel
  74. return validResults;
  75. }
  76. private boolean checkForNullValues(MultiMap<String, Object, ? extends List> params) {
  77. for (List list : params.values()) {
  78. if (list == null) return true;
  79. for (Object o : list) {
  80. if (o == null) return true;
  81. }
  82. }
  83. return false;
  84. }
  85. @Override
  86. public List<IssueService.IssueResult> travel(User user, Issue issue, Status to, Map<String, Object> params,
  87. final List<IssueService.TransitionValidationResult> errorResults) {
  88. MultiMap<String, Object, ? extends List> multiParams = createMultiMap(params);
  89. return travel(user, issue, to, multiParams, errorResults);
  90. }
  91. @Override
  92. public List<IssueService.IssueResult> travel(User user, Issue issue, Status to, List<IssueService.TransitionValidationResult> errorResults) {
  93. return travel(user, issue, to, MultiMaps.<String, Object>createListMultiMap(), errorResults);
  94. }
  95. private MultiMap<String, Object, ? extends List> createMultiMap(Map<String, Object> params) {
  96. MultiMap<String, Object, ? extends List> result = MultiMaps.createListMultiMap();
  97. for (Map.Entry<String, Object> entry : params.entrySet()) {
  98. result.putSingle(entry.getKey(), entry.getValue());
  99. }
  100. return result;
  101. }
  102. private List<IssueService.IssueResult> simpleTravel(User user,
  103. Issue issue,
  104. Status to,
  105. MultiMap<String, Object, ? extends List> params,
  106. final List<IssueService.TransitionValidationResult> errorResults
  107. ) {
  108. List<IssueService.IssueResult> resultList = new ArrayList<IssueService.IssueResult>();
  109. User oldUser = jiraAuthenticationContext.getLoggedInUser();
  110. jiraAuthenticationContext.setLoggedInUser(user);
  111. List<IssueService.TransitionValidationResult> validResults = getValidResults(user, issue, to, params, errorResults);
  112. if (!validResults.isEmpty()) {
  113. for (IssueService.TransitionValidationResult validResult : validResults) {
  114. IssueService.IssueResult result = issueService.transition(user, validResult);
  115. if (result.getErrorCollection() != null && result.getErrorCollection().hasAnyErrors()) {
  116. log.warn("result of transition for issue : " + validResult.getIssue().getKey() + " and transition : " +
  117. to.getName() + " is not so valid, something wrong here : " +
  118. (result.getErrorCollection().getErrorMessages() != null?Arrays.toString(result.getErrorCollection().getErrorMessages().toArray()):" dunno what"));
  119. errorResults.add(validResult);
  120. } else {
  121. resultList.add(result);
  122. return resultList;
  123. }
  124. }
  125. //TODO: do something with multiple results
  126. }
  127. jiraAuthenticationContext.setLoggedInUser(oldUser);
  128. return resultList;
  129. }
  130. private List<IssueService.TransitionValidationResult> getValidResults(User user, Issue issue, Status to, MultiMap<String, Object, ? extends List> params, List<IssueService.TransitionValidationResult> errorResults) {
  131. List<IssueService.TransitionValidationResult> result = new ArrayList<IssueService.TransitionValidationResult>();
  132. List<IssueService.TransitionValidationResult> simpleTransitionResults = getSimpleTransitionResults(user, issue, to, params);
  133. for (IssueService.TransitionValidationResult transitionValidationResult : simpleTransitionResults) {
  134. if (transitionValidationResult.isValid()) result.add(transitionValidationResult);
  135. else errorResults.add(transitionValidationResult);
  136. }
  137. //TODO : add not simple
  138. return result;
  139. }
  140. private List<IssueService.TransitionValidationResult> getSimpleTransitionResults(User user, Issue issue, Status to, MultiMap<String, Object, ? extends List> params) {
  141. List<IssueService.TransitionValidationResult> result = new ArrayList<IssueService.TransitionValidationResult>();
  142. Map<String, Object> simpleParams = getSimpleMap(params);
  143. Set<Integer> nextStatusActionIds = getNextStatusActionIds(issue, to);
  144. if (nextStatusActionIds.size() == 0) throw new IllegalArgumentException("to status is not valid for issue : " + issue.getKey() +
  145. " and status : " + to.getName());
  146. if (nextStatusActionIds.size() > 1) log.warn("found more than one actions for next status transition : " + issue.getKey() +
  147. " and status : " + to.getName());
  148. for (Integer actionId : nextStatusActionIds) {
  149. IssueInputParameters issueInputParameters = newIssueInputParameters(simpleParams);
  150. issueInputParameters.setSkipScreenCheck(true);
  151. log.debug("traveling to status : " + to.getName() + " with action id : " + actionId + "; user : " + user.getName() +
  152. " ; issueInputParameters : " + issueInputParameters + " : " + to.getId() + " and logged in user : " + jiraAuthenticationContext.getLoggedInUser().getName());
  153. IssueService.TransitionValidationResult transitionValidationResult =
  154. issueService.validateTransition(user, issue.getId(), actionId, issueInputParameters);
  155. log.debug("validation result status : " + transitionValidationResult.getIssue().getStatusObject().getName() + " and action id : " + transitionValidationResult.getActionId());
  156. result.add(transitionValidationResult);
  157. }
  158. return result;
  159. }
  160. private IssueInputParameters newIssueInputParameters(Map<String, Object> simpleParams) {
  161. Map<String, String[]> likeHttp = getLikeHttpInput(simpleParams);
  162. return issueService.newIssueInputParameters(likeHttp);
  163. }
  164. private Map<String, String[]> getLikeHttpInput(Map<String, Object> simpleParams) {
  165. Map<String, String[]> result = new HashMap<String, String[]>();
  166. for (Map.Entry<String, Object> entry : simpleParams.entrySet()) {
  167. String[] likeHttpValue;
  168. if (entry.getValue() instanceof String[]) likeHttpValue = (String[]) entry.getValue();
  169. else {
  170. likeHttpValue = new String[] {entry.getValue().toString()};
  171. }
  172. result.put(entry.getKey(), likeHttpValue);
  173. }
  174. return result;
  175. }
  176. private Map<String, Object> getSimpleMap(MultiMap<String, Object, ? extends List> params) {
  177. Map<String, Object> result = new HashMap<String, Object>();
  178. for (Map.Entry<String, ? extends List> entry : params.entrySet()) {
  179. List values = entry.getValue();
  180. if (values == null || values.size() != 1) continue;
  181. String key = entry.getKey();
  182. Object value = values.get(0);
  183. result.put(key, value);
  184. }
  185. return result;
  186. }
  187. private Set<Integer> getNextStatusActionIds(Issue issue, Status to) {
  188. JiraWorkflow workflow = workflowManager.getWorkflow(issue);
  189. Set<Integer> result = new HashSet<Integer>();
  190. for (ActionDescriptor actionDescriptor : getAvailableActions(issue)) {
  191. Set<ResultDescriptor> results = getAllResults(actionDescriptor); //supposed to be size of 1
  192. for (ResultDescriptor resultDescriptor : results) {
  193. Status status = workflow.getLinkedStatusObject(workflow.getDescriptor().getStep(resultDescriptor.getStep()));
  194. if (status != null && status.equals(to)) {
  195. result.add(actionDescriptor.getId());
  196. }
  197. }
  198. }
  199. return result;
  200. }
  201. private Set<Status> getAllAvailableWorkflowStatuses(Issue issue) {
  202. log.debug("getting available workflow statuses");
  203. JiraWorkflow workflow = workflowManager.getWorkflow(issue);
  204. Set<Status> result = new HashSet<Status>();
  205. for (ActionDescriptor actionDescriptor : getAvailableActions(issue)) {
  206. log.debug("available action : " + actionDescriptor.getName());
  207. Set<ResultDescriptor> results = getAllResults(actionDescriptor);
  208. if (results.size() > 1)
  209. log.warn("for some reason issue action : "
  210. + actionDescriptor.getName() + " for issue : " + issue.getKey() + " has more than one results");
  211. for (ResultDescriptor resultDescriptor : results) {
  212. Status status = workflow.getLinkedStatusObject(workflow.getDescriptor().getStep(resultDescriptor.getStep()));
  213. result.add(status);
  214. log.debug("linked status object : " + status.getName());
  215. }
  216. }
  217. log.debug("available statuses size : " + result.size());
  218. return result;
  219. }
  220. private Collection<ActionDescriptor> getAvailableActions(Issue issue) {
  221. Collection<ActionDescriptor> result = new ArrayList<ActionDescriptor>();
  222. JiraWorkflow workflow = workflowManager.getWorkflow(issue);
  223. StepDescriptor step = workflow.getLinkedStep(issue.getStatusObject());
  224. for (Object o : step.getActions()) {
  225. ActionDescriptor actionDescriptor = (ActionDescriptor) o;
  226. result.add(actionDescriptor);
  227. }
  228. log.debug("available actions size : " + result.size());
  229. return result;
  230. }
  231. private Set<ResultDescriptor> getAllResults(ActionDescriptor actionDescriptor) {
  232. //List<ResultDescriptor> results = actionDescriptor.getConditionalResults();
  233. List<ResultDescriptor> results = new ArrayList<ResultDescriptor>();
  234. if (actionDescriptor.getConditionalResults() != null && actionDescriptor.getConditionalResults().size() > 0)
  235. log.error("What conditional result doing here? : " + actionDescriptor.getConditionalResults().get(0));
  236. ResultDescriptor unconditionalResult = actionDescriptor.getUnconditionalResult();
  237. if (unconditionalResult != null) {results.add(unconditionalResult);}
  238. return Sets.newHashSet(results);
  239. }
  240. }