1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.impl.peopleflow;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.kuali.rice.core.api.config.ConfigurationException;
20 import org.kuali.rice.core.api.exception.RiceRuntimeException;
21 import org.kuali.rice.core.api.util.xml.XmlJotter;
22 import org.kuali.rice.kew.actionrequest.ActionRequestValue;
23 import org.kuali.rice.kew.api.action.ActionRequestType;
24 import org.kuali.rice.kew.api.peopleflow.PeopleFlowDefinition;
25 import org.kuali.rice.kew.api.peopleflow.PeopleFlowService;
26 import org.kuali.rice.kew.engine.RouteContext;
27 import org.kuali.rice.kew.engine.node.NodeState;
28 import org.kuali.rice.kew.engine.node.RouteNodeUtils;
29 import org.kuali.rice.kew.api.exception.WorkflowException;
30 import org.kuali.rice.kew.routemodule.RouteModule;
31 import org.kuali.rice.kew.service.KEWServiceLocator;
32 import org.kuali.rice.kew.util.ResponsibleParty;
33 import org.w3c.dom.Element;
34
35 import javax.xml.bind.JAXBContext;
36 import javax.xml.bind.JAXBException;
37 import javax.xml.bind.annotation.XmlAttribute;
38 import javax.xml.bind.annotation.XmlElement;
39 import javax.xml.bind.annotation.XmlElements;
40 import javax.xml.bind.annotation.XmlRootElement;
41 import javax.xml.bind.annotation.XmlValue;
42 import java.util.ArrayList;
43 import java.util.List;
44
45 public class PeopleFlowRouteModule implements RouteModule {
46
47 private static final String PEOPLE_FLOW_PROPERTY = "peopleFlow";
48
49 private static final String PEOPLE_FLOW_ITERATION_KEY = "peopleFlowIteration";
50 public static final String PEOPLE_FLOW_SEQUENCE = "peopleFlowSequence";
51
52 private static final JAXBContext jaxbContext;
53 static {
54 try {
55 jaxbContext = JAXBContext.newInstance(PeopleFlowConfig.class);
56 } catch (JAXBException e) {
57 throw new RiceRuntimeException("Failed to initialize JAXB!", e);
58 }
59 }
60
61 private PeopleFlowService peopleFlowService;
62 private PeopleFlowRequestGenerator peopleFlowRequestGenerator;
63
64 @Override
65 public List<ActionRequestValue> findActionRequests(RouteContext context) throws Exception {
66 int iteration = incrementIteration(context);
67 List<PeopleFlowConfig> configurations = parsePeopleFlowConfiguration(context);
68 List<ActionRequestValue> actionRequests = new ArrayList<ActionRequestValue>();
69 int index = 0;
70 for (PeopleFlowConfig configuration : configurations) {
71 if (index++ == iteration) {
72 PeopleFlowDefinition peopleFlow = loadPeopleFlow(configuration);
73 actionRequests.addAll(getPeopleFlowRequestGenerator().generateRequests(context, peopleFlow, configuration.actionRequested));
74 break;
75 }
76 }
77 return actionRequests;
78 }
79
80 @Override
81 public boolean isMoreRequestsAvailable(RouteContext context) {
82 Integer currentIteration = getCurrentIteration(context);
83 if (currentIteration == null) {
84 return false;
85 }
86 List<PeopleFlowConfig> configurations = parsePeopleFlowConfiguration(context);
87 return currentIteration.intValue() < configurations.size();
88 }
89
90 @Override
91 public ResponsibleParty resolveResponsibilityId(String responsibilityId) throws WorkflowException {
92 return null;
93 }
94
95 protected List<PeopleFlowConfig> parsePeopleFlowConfiguration(RouteContext context) {
96 List<PeopleFlowConfig> configs = new ArrayList<PeopleFlowConfig>();
97 NodeState peopleFlowSequenceNodeState = context.getNodeInstance().getNodeState(PEOPLE_FLOW_SEQUENCE);
98 if (peopleFlowSequenceNodeState != null) {
99 String peopleFlowSequence = peopleFlowSequenceNodeState.getValue();
100 if (StringUtils.isNotBlank(peopleFlowSequence)) {
101 String[] peopleFlowValues = peopleFlowSequence.split(",");
102 for (String peopleFlowValue : peopleFlowValues) {
103 String[] peopleFlowProperties = peopleFlowValue.split(":");
104 PeopleFlowConfig config = new PeopleFlowConfig();
105 config.actionRequested = ActionRequestType.fromCode(peopleFlowProperties[0]);
106 config.peopleFlowIdentifier = peopleFlowProperties[1];
107 configs.add(config);
108 }
109 }
110 } else {
111 List<Element> peopleFlowElements = RouteNodeUtils.getCustomRouteNodeElements(
112 context.getNodeInstance().getRouteNode(), PEOPLE_FLOW_PROPERTY);
113
114 for (Element peopleFlowElement : peopleFlowElements) {
115 try {
116 PeopleFlowConfig config = (PeopleFlowConfig)jaxbContext.createUnmarshaller().unmarshal(peopleFlowElement);
117 if (config.actionRequested == null) {
118
119 config.actionRequested = ActionRequestType.APPROVE;
120 }
121 if (config == null) {
122 throw new IllegalStateException("People flow configuration element did not properly unmarshall from XML: " + XmlJotter.jotNode(peopleFlowElement));
123 }
124 configs.add(config);
125 } catch (JAXBException e) {
126 throw new RiceRuntimeException("Failed to unmarshall people flow configuration from route node.", e);
127 }
128 }
129 }
130 return configs;
131 }
132
133 protected PeopleFlowDefinition loadPeopleFlow(PeopleFlowConfig configuration) {
134 if (configuration.isId()) {
135 PeopleFlowDefinition peopleFlow = getPeopleFlowService().getPeopleFlow(configuration.getId());
136 if (peopleFlow == null) {
137 throw new ConfigurationException("Failed to locate a people flow with the given id of '" + configuration.getId() + "'");
138 }
139 return peopleFlow;
140 } else {
141 String namespaceCode = configuration.getName().namespaceCode;
142 String name = configuration.getName().name;
143 PeopleFlowDefinition peopleFlow = getPeopleFlowService().getPeopleFlowByName(namespaceCode, name);
144 if (peopleFlow == null) {
145 throw new ConfigurationException("Failed to locate a people flow with the given namespaceCode of '" + namespaceCode + "' and name of '" + name + "'");
146 }
147 return peopleFlow;
148 }
149 }
150
151 protected int incrementIteration(RouteContext context) {
152 int nextIteration = 0;
153 NodeState nodeState = context.getNodeInstance().getNodeState(PEOPLE_FLOW_ITERATION_KEY);
154 if (nodeState == null) {
155 nodeState = new NodeState();
156 nodeState.setNodeInstance(context.getNodeInstance());
157 nodeState.setKey(PEOPLE_FLOW_ITERATION_KEY);
158 context.getNodeInstance().addNodeState(nodeState);
159 } else {
160 int currentIteration = Integer.parseInt(nodeState.getValue());
161 nextIteration = currentIteration + 1;
162 }
163 nodeState.setValue(Integer.toString(nextIteration));
164 if (!context.isSimulation()) {
165 KEWServiceLocator.getRouteNodeService().save(nodeState);
166 }
167 return nextIteration;
168 }
169
170 protected Integer getCurrentIteration(RouteContext context) {
171 NodeState nodeState = context.getNodeInstance().getNodeState(PEOPLE_FLOW_ITERATION_KEY);
172 if (nodeState == null) {
173 return null;
174 }
175 return Integer.valueOf(nodeState.getValue());
176 }
177
178 public PeopleFlowService getPeopleFlowService() {
179 return peopleFlowService;
180 }
181
182 public void setPeopleFlowService(PeopleFlowService peopleFlowService) {
183 this.peopleFlowService = peopleFlowService;
184 }
185
186 public PeopleFlowRequestGenerator getPeopleFlowRequestGenerator() {
187 return peopleFlowRequestGenerator;
188 }
189
190 public void setPeopleFlowRequestGenerator(PeopleFlowRequestGenerator peopleFlowRequestGenerator) {
191 this.peopleFlowRequestGenerator = peopleFlowRequestGenerator;
192 }
193
194 @XmlRootElement(name = "peopleFlow")
195 private static class PeopleFlowConfig {
196
197 @XmlElement(name = "actionRequested")
198 ActionRequestType actionRequested;
199
200 @XmlElements(value = {
201 @XmlElement(name = "name", type = NameConfig.class),
202 @XmlElement(name = "id", type = String.class)
203 })
204 Object peopleFlowIdentifier;
205
206 boolean isId() {
207 return peopleFlowIdentifier instanceof String;
208 }
209 boolean isName() {
210 return peopleFlowIdentifier instanceof NameConfig;
211 }
212
213 NameConfig getName() {
214 return (NameConfig)peopleFlowIdentifier;
215 }
216
217 String getId() {
218 return (String)peopleFlowIdentifier;
219 }
220
221 }
222
223 private static class NameConfig {
224
225 @XmlAttribute(name = "namespace")
226 String namespaceCode;
227
228 @XmlValue
229 String name;
230
231 }
232
233 }