View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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 org.kuali.rice.kew.framework.support.krms;
17  
18  import org.junit.Test;
19  import org.kuali.rice.kew.api.KewApiServiceLocator;
20  import org.kuali.rice.kew.api.WorkflowDocument;
21  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
22  import org.kuali.rice.kew.api.peopleflow.PeopleFlowDefinition;
23  import org.kuali.rice.kew.test.KEWTestCase;
24  import org.kuali.rice.krad.service.BusinessObjectService;
25  import org.kuali.rice.krad.service.KRADServiceLocator;
26  import org.kuali.rice.krms.api.KrmsApiServiceLocator;
27  import org.kuali.rice.krms.api.KrmsConstants;
28  import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
29  import org.kuali.rice.krms.api.repository.type.KrmsTypeAttribute;
30  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
31  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
32  import org.kuali.rice.krms.impl.repository.ActionAttributeBo;
33  import org.kuali.rice.krms.impl.repository.ActionBo;
34  import org.kuali.rice.krms.impl.repository.AgendaAttributeBo;
35  import org.kuali.rice.krms.impl.repository.AgendaBo;
36  import org.kuali.rice.krms.impl.repository.AgendaItemBo;
37  import org.kuali.rice.krms.impl.repository.ContextBo;
38  import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionBo;
39  import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionService;
40  import org.kuali.rice.krms.impl.repository.RuleBo;
41  import org.kuali.rice.krms.impl.util.KRMSServiceLocatorInternal;
42  import org.kuali.rice.test.BaselineTestCase;
43  
44  import java.util.ArrayList;
45  import java.util.HashSet;
46  import java.util.List;
47  import java.util.Set;
48  
49  import static org.junit.Assert.*;
50  
51  /**
52   * An integration test which tests KEW integration with KRMS producing PeopleFlows for routing purposes.  KEW provides
53   * standard integration with KRMS through the use of it's {@code <rulesEngine executorClass="..."/>} element, which is
54   * what this test is testing.
55   *
56   * @author Kuali Rice Team (rice.collab@kuali.org)
57   */
58  @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.CLEAR_DB)
59  public class KewToRulesEngineIntegrationTest extends KEWTestCase {
60  
61      private static final String SIMPLE_DOCUMENT_TYPE = "RulesEngineIntegration-Simple";
62  
63      private static final String PEOPLE_FLOW_ID_ATTRIBUTE = "peopleFlowId";
64      private static final String PEOPLE_FLOW_NAME_ATTRIBUTE = "peopleFlowName";
65      private static final String EVENT_ATTRIBUTE = "Event";
66  
67      private BusinessObjectService businessObjectService;
68  
69      private KrmsAttributeDefinition peopleFlowIdAttributeDefinition;
70      private KrmsAttributeDefinition peopleFlowNameAttributeDefinition;
71      private KrmsTypeDefinition approvalPeopleFlowActionType;
72      private RuleBo ruleBo;
73  
74  
75      @Override
76      protected void loadTestData() throws Exception {
77          loadXmlFile("KewToRulesEngineIntegrationTest.xml");
78          businessObjectService = KRADServiceLocator.getBusinessObjectService();
79          assertNotNull(businessObjectService);
80          PeopleFlowDefinition peopleFlow = createFirstPeopleFlow();
81          this.peopleFlowIdAttributeDefinition = createPeopleFlowIdAttributeDefinition();
82          this.peopleFlowNameAttributeDefinition = createPeopleFlowNameAttributeDefinition();
83          KrmsAttributeDefinitionBo eventAttributeDefinition = createEventAttributeDefinition();
84          this.approvalPeopleFlowActionType = createApprovalPeopleFlowActionType(peopleFlowIdAttributeDefinition);
85          this.ruleBo = createRule(approvalPeopleFlowActionType, peopleFlowIdAttributeDefinition,
86                                   peopleFlowNameAttributeDefinition, peopleFlow.getId());
87          ContextBo contextBo = createContext();
88          createAgenda(ruleBo, contextBo, eventAttributeDefinition);
89      }
90  
91      private PeopleFlowDefinition createFirstPeopleFlow() {
92          String user1 = getPrincipalIdForName("user1");
93          String user2 = getPrincipalIdForName("user2");
94          String testWorkgroup = getGroupIdForName("KR-WKFLW", "TestWorkgroup");
95          PeopleFlowDefinition.Builder peopleFlow = PeopleFlowDefinition.Builder.create("TEST", "PeopleFlow1");
96          peopleFlow.addPrincipal(user1).setPriority(1);
97          peopleFlow.addPrincipal(user2).setPriority(2);
98          peopleFlow.addGroup(testWorkgroup).setPriority(3);
99          return KewApiServiceLocator.getPeopleFlowService().createPeopleFlow(peopleFlow.build());
100     }
101 
102     /**
103      * Create an attribute definition for "peopleFlowId" which can be used on PeopleFlow-related action types.
104      */
105     private KrmsAttributeDefinition createPeopleFlowIdAttributeDefinition() {
106         return createPeopleFlowAttributeDefinition(PEOPLE_FLOW_ID_ATTRIBUTE, "PeopleFlow ID");
107     }
108 
109     /**
110      * Create an attribute definition for "peopleFlowName" 
111      */
112     private KrmsAttributeDefinition createPeopleFlowNameAttributeDefinition() {
113         return createPeopleFlowAttributeDefinition(PEOPLE_FLOW_NAME_ATTRIBUTE, "PeopleFlow Name");
114     }
115 
116     /**
117      * Create an attribute definition for "peopleFlow" using given attribute and label
118      */
119     private KrmsAttributeDefinition createPeopleFlowAttributeDefinition(String attribute, String label) {
120         KrmsAttributeDefinitionService service = KRMSServiceLocatorInternal.getService("krmsAttributeDefinitionService");
121         assertNotNull(service);
122         KrmsAttributeDefinitionBo attributeDefinitionBo = new KrmsAttributeDefinitionBo();
123         attributeDefinitionBo.setNamespace(KrmsConstants.KRMS_NAMESPACE);
124         attributeDefinitionBo.setName(attribute);
125         attributeDefinitionBo.setLabel(label);
126         attributeDefinitionBo.setActive(true);
127         attributeDefinitionBo = businessObjectService.save(attributeDefinitionBo);
128         assertNotNull(attributeDefinitionBo.getId());
129         return KrmsAttributeDefinitionBo.to(attributeDefinitionBo);
130     }
131 
132 
133     /**
134      * Creates the KRMS Type for PeopleFlow approval actions.
135      */
136     private KrmsTypeDefinition createApprovalPeopleFlowActionType(KrmsAttributeDefinition peopleFlowIdAttributeDefinition) {
137         KrmsTypeRepositoryService krmsTypeRepositoryService = KrmsApiServiceLocator.getKrmsTypeRepositoryService();
138         KrmsTypeDefinition.Builder typeDefinition = KrmsTypeDefinition.Builder.create(KrmsConstants.KRMS_NAMESPACE, "approvalPeopleFlowActionType");
139         typeDefinition.setServiceName("approvalPeopleFlowActionTypeService");
140         KrmsTypeAttribute.Builder attributeDefinition = KrmsTypeAttribute.Builder.create(null, peopleFlowIdAttributeDefinition.getId(), 1);
141         typeDefinition.getAttributes().add(attributeDefinition);
142         KrmsTypeDefinition approvalPeopleFlowActionType = krmsTypeRepositoryService.createKrmsType(typeDefinition.build());
143         assertNotNull(approvalPeopleFlowActionType);
144         assertNotNull(approvalPeopleFlowActionType.getId());
145         assertEquals(1, approvalPeopleFlowActionType.getAttributes().size());
146         assertNotNull(approvalPeopleFlowActionType.getAttributes().get(0).getId());
147         assertEquals(approvalPeopleFlowActionType.getId(), approvalPeopleFlowActionType.getAttributes().get(0).getTypeId());
148         return approvalPeopleFlowActionType;
149     }
150 
151     /**
152      * Creates a rule linked with the given action type and people flow action
153      * @param actionType
154      * @param peopleFlowIdAttributeDefinition
155      * @param peopleFlowId
156      */
157     private RuleBo createRule(KrmsTypeDefinition actionType, KrmsAttributeDefinition peopleFlowIdAttributeDefinition,
158             KrmsAttributeDefinition peopleFlowNameAttributeDefinition, String peopleFlowId) {
159         RuleBo rule = new RuleBo();
160         rule.setNamespace("TEST");
161         rule.setName("PeopleFlowRule");
162         // no propositions on this rule so it should (hopefully) always evaluate to true
163 
164         List<ActionBo> actions = new ArrayList<ActionBo>();
165         rule.setActions(actions);
166 
167         // create the action with an attribute pointing to a peopleflow
168         ActionBo peopleFlowAction = new ActionBo();
169         actions.add(peopleFlowAction);
170         peopleFlowAction.setNamespace("TEST");
171         peopleFlowAction.setName("PeopleFlowApprovalAction");
172         peopleFlowAction.setSequenceNumber(1);
173         peopleFlowAction.setTypeId(actionType.getId());
174         Set<ActionAttributeBo> actionAttributes = new HashSet<ActionAttributeBo>();
175         peopleFlowAction.setAttributeBos(actionAttributes);
176 
177         ActionAttributeBo actionAttribute = new ActionAttributeBo();
178         actionAttributes.add(actionAttribute);
179         actionAttribute.setAttributeDefinitionId(peopleFlowIdAttributeDefinition.getId());
180         actionAttribute.setAttributeDefinition(KrmsAttributeDefinitionBo.from(peopleFlowIdAttributeDefinition));
181         actionAttribute.setValue(peopleFlowId);
182 
183         ActionAttributeBo actionNameAttribute = new ActionAttributeBo();
184         actionAttributes.add(actionNameAttribute);
185         actionNameAttribute.setAttributeDefinitionId(peopleFlowNameAttributeDefinition.getId());
186         actionNameAttribute.setAttributeDefinition(KrmsAttributeDefinitionBo.from(peopleFlowNameAttributeDefinition));
187         actionNameAttribute.setValue(peopleFlowAction.getName() + " Name attr");
188 
189         // set up a simple default type for the rule
190         KrmsTypeRepositoryService krmsTypeRepositoryService = KrmsApiServiceLocator.getKrmsTypeRepositoryService();
191         KrmsTypeDefinition.Builder typeDefinition = KrmsTypeDefinition.Builder.create("PeopleFlowRule Name", KrmsConstants.KRMS_NAMESPACE);
192         typeDefinition.setServiceName("defaultRuleTypeService");
193         KrmsTypeDefinition defaultRuleType = krmsTypeRepositoryService.createKrmsType(typeDefinition.build());
194         assertNotNull(defaultRuleType);
195         assertNotNull(defaultRuleType.getId());
196 
197         // now assign the default type to the rule and save it
198         rule.setTypeId(defaultRuleType.getId());
199         rule = businessObjectService.save(rule);
200         assertNotNull(rule.getId());
201         assertEquals(1, rule.getActions().size());
202         assertNotNull(rule.getActions().get(0).getId());
203         assertEquals(2, rule.getActions().get(0).getAttributeBos().size());
204         return rule;
205     }
206 
207     private ContextBo createContext() {
208         // set up a simple default type for the context
209         KrmsTypeRepositoryService krmsTypeRepositoryService = KrmsApiServiceLocator.getKrmsTypeRepositoryService();
210         KrmsTypeDefinition.Builder typeDefinition = KrmsTypeDefinition.Builder.create(KrmsConstants.KRMS_NAMESPACE, "DefaultContextType");
211         KrmsTypeDefinition defaultContextType = krmsTypeRepositoryService.createKrmsType(typeDefinition.build());
212 
213         ContextBo contextBo = new ContextBo();
214         contextBo.setNamespace(KrmsConstants.KRMS_NAMESPACE);
215         contextBo.setName("MyContext");
216         contextBo.setTypeId(defaultContextType.getId());
217         return businessObjectService.save(contextBo);
218     }
219 
220     /**
221      * Create an attribute definition for "Event" which is used to define the triggering event on an agenda.
222      */
223     private KrmsAttributeDefinitionBo createEventAttributeDefinition() {
224         KrmsAttributeDefinitionService service = KRMSServiceLocatorInternal.getService("krmsAttributeDefinitionService");
225         assertNotNull(service);
226         KrmsAttributeDefinitionBo attributeDefinitionBo = new KrmsAttributeDefinitionBo();
227         attributeDefinitionBo.setNamespace(KrmsConstants.KRMS_NAMESPACE);
228         attributeDefinitionBo.setName(EVENT_ATTRIBUTE);
229         attributeDefinitionBo.setLabel("Event");
230         attributeDefinitionBo.setActive(true);
231         attributeDefinitionBo = businessObjectService.save(attributeDefinitionBo);
232         assertNotNull(attributeDefinitionBo.getId());
233         return attributeDefinitionBo;
234     }
235 
236     private AgendaBo createAgenda(RuleBo ruleBo, ContextBo contextBo, KrmsAttributeDefinitionBo eventAttributeDefinition) {
237         // set up a simple default type for the agenda
238         AgendaBo agendaBo = new AgendaBo();
239         agendaBo.setActive(true);
240         agendaBo.setContextId(contextBo.getId());
241         agendaBo.setName("MyAgenda");
242         agendaBo.setTypeId(null);
243         agendaBo = businessObjectService.save(agendaBo);
244 
245         agendaBo.setFirstItemId(ruleBo.getId());
246         AgendaItemBo agendaItemBo = new AgendaItemBo();
247         agendaItemBo.setRule(ruleBo);
248         agendaItemBo.setAgendaId(agendaBo.getId());
249         agendaItemBo = businessObjectService.save(agendaItemBo);
250 
251         List<AgendaItemBo> agendaItems = new ArrayList<AgendaItemBo>();
252         agendaItems.add(agendaItemBo);
253         agendaBo.setItems(agendaItems);
254         agendaBo.setFirstItemId(agendaItemBo.getId());
255 
256         // also add attribute to the agenda to store event
257         Set<AgendaAttributeBo> agendaAttributes = new HashSet<AgendaAttributeBo>();
258         agendaBo.setAttributeBos(agendaAttributes);
259         AgendaAttributeBo agendaAttribute = new AgendaAttributeBo();
260         agendaAttributes.add(agendaAttribute);
261         agendaAttribute.setAttributeDefinitionId(eventAttributeDefinition.getId());
262         agendaAttribute.setAttributeDefinition(eventAttributeDefinition);
263         agendaAttribute.setValue("workflow");
264         agendaBo = businessObjectService.save(agendaBo);
265 
266         contextBo.getAgendas().add(agendaBo);
267 
268         return agendaBo;
269     }
270 
271     @Test
272     public void testSimpleKrmsPeopleFlowRules() throws Exception {
273         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user3"), SIMPLE_DOCUMENT_TYPE);
274         document.route("");
275         assertTrue(document.isEnroute());
276 
277         String user1 = getPrincipalIdForName("user1");
278         String user2 = getPrincipalIdForName("user2");
279         String ewestfal = getPrincipalIdForName("ewestfal"); // ewestfal is a member of TestWorkgroup
280         // at this point, the PeopleFlow should have triggered requests to user1, user2, and TestWorkgroup, in that order
281         // but only the request to user1 should be activated
282         document.switchPrincipal(ewestfal);
283         assertFalse(document.isApprovalRequested());
284         document.switchPrincipal(user2);
285         assertFalse(document.isApprovalRequested());
286         document.switchPrincipal(user1);
287         assertTrue(document.isApprovalRequested());
288 
289         // now approve as user1
290         document.approve("");
291         assertTrue(document.isEnroute());
292 
293         // should now be activated to user2
294         document.switchPrincipal(user2);
295         assertTrue(document.isApprovalRequested());
296         document.approve("");
297         assertTrue(document.isEnroute());
298 
299         // should now be activated to TestWorkgroup, of which ewestfal is a member
300         document.switchPrincipal(ewestfal);
301         assertTrue(document.isApprovalRequested());
302         document.approve("");
303 
304         // all approvals have been taken, document should now be final
305         assertTrue(document.isFinal());
306     }
307 
308     @Test
309     public void testMultipleKrmsPeopleFlowRules() throws Exception {
310         // first, let's add a second peopleflow to the rule action setup
311         addAnotherPeopleFlow(ruleBo);
312 
313         WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("user3"), SIMPLE_DOCUMENT_TYPE);
314         document.route("");
315         assertTrue(document.isEnroute());
316 
317         String user1 = getPrincipalIdForName("user1");
318         String user2 = getPrincipalIdForName("user2");
319         String ewestfal = getPrincipalIdForName("ewestfal"); // ewestfal is a member of TestWorkgroup
320         // at this point, the PeopleFlow should have triggered requests to user1, user2, and TestWorkgroup, in that order
321         // but only the request to user1 should be activated
322         document.switchPrincipal(ewestfal);
323         assertFalse(document.isApprovalRequested());
324         document.switchPrincipal(user2);
325         assertFalse(document.isApprovalRequested());
326         document.switchPrincipal(user1);
327         assertTrue(document.isApprovalRequested());
328         // there should also only be 3 action requests, action request to second peopleflow should not yet be generated
329         assertEquals(3, document.getRootActionRequests().size());
330 
331         // now approve as user1
332         document.approve("");
333         assertTrue(document.isEnroute());
334 
335         // should now be activated to user2
336         document.switchPrincipal(user2);
337         assertTrue(document.isApprovalRequested());
338         document.approve("");
339         assertTrue(document.isEnroute());
340 
341         // should now be activated to TestWorkgroup, of which ewestfal is a member
342         document.switchPrincipal(ewestfal);
343         assertTrue(document.isApprovalRequested());
344         document.approve("");
345 
346         // document should still be enroute, and now we should be routed to second peopleflow
347         assertTrue(document.isEnroute());
348         String testuser1 = getPrincipalIdForName("testuser1");
349         document.switchPrincipal(testuser1);
350         assertTrue(document.isApprovalRequested());
351         // there should be 4 action requests total now
352         assertEquals(4, document.getRootActionRequests().size());
353         document.approve("");
354 
355         // all approvals have been taken, document should now be final
356         assertTrue(document.isFinal());
357     }
358 
359     private void addAnotherPeopleFlow(RuleBo ruleBo) {
360         String testuser1 = getPrincipalIdForName("testuser1");
361         PeopleFlowDefinition.Builder peopleFlowBuilder = PeopleFlowDefinition.Builder.create("TEST", "PeopleFlow2");
362         peopleFlowBuilder.addPrincipal(testuser1).setPriority(1);
363         PeopleFlowDefinition peopleFlow =  KewApiServiceLocator.getPeopleFlowService().createPeopleFlow(peopleFlowBuilder.build());
364 
365         // create the action with an attribute pointing to a peopleflow
366         ActionBo peopleFlowAction = new ActionBo();
367         ruleBo.getActions().add(peopleFlowAction);
368         peopleFlowAction.setNamespace("TEST");
369         peopleFlowAction.setName("PeopleFlowApprovalAction2");
370         peopleFlowAction.setSequenceNumber(2);
371         peopleFlowAction.setTypeId(approvalPeopleFlowActionType.getId());
372         Set<ActionAttributeBo> actionAttributes = new HashSet<ActionAttributeBo>();
373         peopleFlowAction.setAttributeBos(actionAttributes);
374         ActionAttributeBo actionAttribute = new ActionAttributeBo();
375         actionAttributes.add(actionAttribute);
376         actionAttribute.setAttributeDefinitionId(peopleFlowIdAttributeDefinition.getId());
377         actionAttribute.setAttributeDefinition(KrmsAttributeDefinitionBo.from(peopleFlowIdAttributeDefinition));
378         actionAttribute.setValue(peopleFlow.getId());
379 
380         ActionAttributeBo actionNameAttribute = new ActionAttributeBo();
381         actionAttributes.add(actionNameAttribute);
382         actionNameAttribute.setAttributeDefinitionId(peopleFlowNameAttributeDefinition.getId());
383         actionNameAttribute.setAttributeDefinition(KrmsAttributeDefinitionBo.from(peopleFlowNameAttributeDefinition));
384         actionNameAttribute.setValue(peopleFlowAction.getName() + " Name attr");
385 
386         businessObjectService.save(ruleBo);
387         
388     }
389 
390 }
391