View Javadoc

1   package com.atlassian.jira.workflow.transition;
2   
3   import java.text.MessageFormat;
4   import java.util.ArrayList;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.Map;
9   
10  import org.apache.log4j.Category;
11  import org.apache.log4j.Logger;
12  
13  import com.atlassian.jira.ComponentManager;
14  import com.atlassian.jira.ManagerFactory;
15  import com.atlassian.jira.issue.Issue;
16  import com.atlassian.jira.issue.IssueManager;
17  import com.atlassian.jira.issue.IssueUtilsBean;
18  import com.atlassian.jira.issue.MutableIssue;
19  import com.atlassian.jira.util.ErrorCollection;
20  import com.atlassian.jira.util.JiraUtils;
21  import com.atlassian.jira.util.SimpleErrorCollection;
22  import com.atlassian.jira.workflow.WorkflowTransitionUtil;
23  import com.atlassian.jira.workflow.WorkflowTransitionUtilAddOnImpl;
24  import com.opensymphony.workflow.loader.ActionDescriptor;
25  
26  /**
27   * FQCN : com.atlassian.jira.workflow.transition.AutoTransitionManager
28   * @author Kaamelot
29   * @since 3.10.1.34
30   * @version 3.10.1.34 
31   * Description : Performs Auto Transition on Issue
32   * - Available Actions are identified 
33   * - Only Actions candidate to Auto Transition are taken in account 
34   * - Only one Auto Transition may be candidate. 
35   * - An auto-transition is tried on each candidate issues
36   */
37  public class DefaultAutoTransitionManager implements AutoTransitionManager {
38  
39  	protected final static Category log = Logger.getInstance(DefaultAutoTransitionManager.class);
40  
41  	protected IssueUtilsBean issueUtilsBean;
42  
43  	protected IssueManager issueManager = ManagerFactory.getIssueManager();
44  	
45  	public DefaultAutoTransitionManager() {
46  		issueUtilsBean = (IssueUtilsBean) ComponentManager.getComponentInstanceOfType(IssueUtilsBean.class);
47  	}
48  
49  	/**
50  	 * @see com.atlassian.jira.workflow.transition.AutoTransitionManager#performAutoTransition(com.atlassian.jira.issue.Issue)
51  	 */
52  	public void performAutoTransition(final MutableIssue _issue) {
53  		// Search for Auto Transition Actions
54  		List autoTransitionActions = getAutoTransitionActions(_issue);
55  		if (autoTransitionActions.size() == 0) {
56  			log.debug("No validated Auto Transition Action for the Issue [" + _issue.getKey() + "]");
57  		} else if (autoTransitionActions.size() > 1) {
58  			log.warn("More than one validated Auto Transition Action found for Issue [" + _issue.getKey() + "]. None of them will be applied !");
59  		} else { // Only on Auto Transition Action, then to apply
60  			log.info("One Auto Transition Action is validated for [" + _issue.getKey() + "]. Trying to apply it.");
61  			ActionDescriptor actionDescriptor = (ActionDescriptor) autoTransitionActions.get(0);
62  			tryAutoTransition(_issue, actionDescriptor);
63  		}
64  	}
65  	
66  	/**
67  	 * @see com.atlassian.jira.workflow.transition.AutoTransitionManager#performAutoTransition(com.atlassian.jira.issue.Issue)
68  	 */
69  	public boolean hasApplicableAutoTransition(final MutableIssue _issue) {
70  		boolean applicableAutoTransition = false;
71  		// Search for Auto Transition Actions
72  		List autoTransitionActions = getAutoTransitionActions(_issue);
73  		if (autoTransitionActions.size() == 0) {
74  			log.debug("No validated Auto Transition Action for the Issue [" + _issue.getKey() + "]");
75  		} else if (autoTransitionActions.size() > 1) {
76  			log.warn("More than one validated Auto Transition Action found for Issue [" + _issue.getKey() + "]. None of them will be applied !");
77  		} else { // Only on Auto Transition Action, then to apply
78  			log.info("One Auto Transition Action is validated for [" + _issue.getKey() + "]. Trying to apply it.");
79  			applicableAutoTransition = true;
80  		}
81  		return applicableAutoTransition;
82  	}
83  	
84  	/**
85  	 * @see com.atlassian.jira.workflow.transition.AutoTransitionManager#getAutoTransitionActions(com.atlassian.jira.issue.Issue)
86  	 */
87  	public List getAutoTransitionActions(final MutableIssue _issue) {
88  		Map availableActions = getAvailableActions(_issue);
89  		List autoTransitionActions = new ArrayList();
90  		for (Iterator iterator = availableActions.keySet().iterator(); iterator.hasNext();) {
91  			ActionDescriptor action = (ActionDescriptor) availableActions.get(iterator.next());
92  			if (isActionCandidate(action)) {
93  				autoTransitionActions.add(action);
94  			}
95  		}
96  		return autoTransitionActions;
97  	}
98  
99  	/**
100 	 * @see com.atlassian.jira.workflow.transition.AutoTransitionManager#getAvailableActions(com.atlassian.jira.issue.Issue)
101 	 */
102 	public Map getAvailableActions(final MutableIssue _issue) {
103 		return issueUtilsBean.loadAvailableActions(_issue);
104 	}
105 
106 	/**
107 	 * @see com.atlassian.jira.workflow.transition.AutoTransitionManager#isActionCandidate(com.opensymphony.workflow.loader.ActionDescriptor)
108 	 */
109 	public boolean isActionCandidate(final ActionDescriptor _actionDescriptor) {
110 		Map metaAttributes = _actionDescriptor.getMetaAttributes();
111 		String allowAutoTransition = null;
112 		if (metaAttributes != null) {
113 			allowAutoTransition = (String) metaAttributes.get("allow.auto.transition");
114 		}
115 		return Boolean.valueOf(allowAutoTransition).booleanValue();
116 	}
117 
118 	/**
119 	 * @param _issue Issue concerned by the Auto Transition
120 	 * @param _action Action to perform on the Transition.
121 	 */
122 	protected void tryAutoTransition(final Issue _issue, final ActionDescriptor _action) {
123 		ErrorCollection errors = new SimpleErrorCollection();
124 		MutableIssue mIssue = null;
125 		if (_issue instanceof MutableIssue) {
126 			mIssue = (MutableIssue) _issue;
127 		} else {
128 			mIssue = issueManager.getIssueObject(_issue.getId());
129 		}
130 		
131 		// We have the workflow Action id.
132 		// Now we need to process and validate all the fields that can be set during the transition
133 		WorkflowTransitionUtil workflowTransitionUtil = (WorkflowTransitionUtil) JiraUtils.loadComponent(WorkflowTransitionUtilAddOnImpl.class);
134 		workflowTransitionUtil.setIssue(mIssue);
135 		workflowTransitionUtil.setAction(_action.getId());
136 		workflowTransitionUtil.setParams(getTransitionParameters(mIssue, _action));
137 
138 		// Validate input
139 		errors.addErrorCollection(workflowTransitionUtil.validate());
140 
141 		if (!errors.hasAnyErrors()) {
142 			// Progress the issue through workflow
143 			errors.addErrorCollection(workflowTransitionUtil.progress());
144 		} else {
145 			log.error(errors.toString());
146 		}
147 	}
148 	
149 	/**
150 	 * @param _issue Issue concerned by the Auto Transition
151 	 * @param _action Action to perform on the Transition.
152 	 * @return Map of default parameters to use for teh Action
153 	 */
154 	protected Map getTransitionParameters(final Issue _issue, final ActionDescriptor _action) {
155 		Map params = new HashMap();
156 		// Build Auto Transition Message
157 		String msgTpl = "Auto Transition Service : All conditions was presents to perform Action [{0}] on Issue [{1}] ...";
158 		params.put(WorkflowTransitionUtil.FIELD_COMMENT, MessageFormat.format(msgTpl, new String[] { _action.getName(), _issue.getKey() }));
159 
160 		// Retrieve Auto Transition Default values
161 		for (Iterator iterator = _action.getMetaAttributes().keySet().iterator(); iterator.hasNext();) {
162 			String metaAttributeKey = (String) iterator.next();
163 			if (metaAttributeKey.startsWith(AutoTransitionManager.DEFAULT_VALUE_PREFFIX)) {
164 				String fieldKey = metaAttributeKey.substring(AutoTransitionManager.DEFAULT_VALUE_PREFFIX.length());
165 				String fieldValue = (String) _action.getMetaAttributes().get(metaAttributeKey);
166 				params.put(fieldKey, fieldValue);
167 			}
168 		}
169 		return params;
170 	}
171 	
172 }