View Javadoc

1   /**
2    * Copyright 2005-2011 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.rule.web;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionForm;
20  import org.apache.struts.action.ActionForward;
21  import org.apache.struts.action.ActionMapping;
22  import org.apache.struts.action.ActionMessages;
23  import org.kuali.rice.kew.actionrequest.ActionRequestValue;
24  import org.kuali.rice.kew.api.KewApiConstants;
25  import org.kuali.rice.kew.api.action.ActionRequestStatus;
26  import org.kuali.rice.kew.doctype.bo.DocumentType;
27  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
28  import org.kuali.rice.kew.engine.ActivationContext;
29  import org.kuali.rice.kew.engine.RouteContext;
30  import org.kuali.rice.kew.engine.node.RouteNode;
31  import org.kuali.rice.kew.engine.node.RouteNodeInstance;
32  import org.kuali.rice.kew.routeheader.AttributeDocumentContent;
33  import org.kuali.rice.kew.routeheader.DocumentContent;
34  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
35  import org.kuali.rice.kew.routelog.web.RouteLogAction;
36  import org.kuali.rice.kew.routelog.web.RouteLogForm;
37  import org.kuali.rice.kew.rule.FlexRM;
38  import org.kuali.rice.kew.rule.WorkflowRuleAttribute;
39  import org.kuali.rice.kew.rule.bo.RuleAttribute;
40  import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo;
41  import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
42  import org.kuali.rice.kew.rule.service.RuleTemplateService;
43  import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
44  import org.kuali.rice.kew.service.KEWServiceLocator;
45  import org.kuali.rice.kew.api.KewApiConstants;
46  import org.kuali.rice.kew.web.KewKualiAction;
47  import org.kuali.rice.kns.web.ui.Field;
48  import org.kuali.rice.kns.web.ui.Row;
49  import org.kuali.rice.krad.UserSession;
50  import org.kuali.rice.krad.exception.ValidationException;
51  import org.kuali.rice.krad.util.GlobalVariables;
52  
53  import javax.servlet.http.HttpServletRequest;
54  import javax.servlet.http.HttpServletResponse;
55  import java.sql.Timestamp;
56  import java.text.SimpleDateFormat;
57  import java.util.ArrayList;
58  import java.util.Calendar;
59  import java.util.Collections;
60  import java.util.Date;
61  import java.util.HashMap;
62  import java.util.HashSet;
63  import java.util.Iterator;
64  import java.util.List;
65  import java.util.Map;
66  import java.util.Set;
67  
68  
69  /**
70   * A Struts Action for executing routing reports and retrieving the results.
71   *
72   * @author Kuali Rice Team (rice.collab@kuali.org)
73   */
74  public class RoutingReportAction extends KewKualiAction {
75  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoutingReportAction.class);
76  
77  	public static final String DOC_TYPE_REPORTING = "documentType";
78  	public static final String TEMPLATE_REPORTING = "template";
79  
80      @Override
81      public ActionForward execute(ActionMapping mapping, ActionForm form,
82              HttpServletRequest request, HttpServletResponse response)
83              throws Exception {
84          this.initiateForm(request, form);
85          RoutingReportForm routingForm = (RoutingReportForm)form;
86          if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDateRef())) {
87              SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
88              routingForm.setEffectiveHour("5");
89              routingForm.setEffectiveMinute("0");
90              routingForm.setAmPm("1");
91              routingForm.setDateRef(sdf.format(new Date()));
92              routingForm.setReportType(TEMPLATE_REPORTING);
93          }
94          if (DOC_TYPE_REPORTING.equals(routingForm.getReportType())) {
95              if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDocumentTypeParam())) {
96                  throw new RuntimeException("No document type was given");
97              }
98              if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getInitiatorPrincipalId())) {
99                  throw new RuntimeException("No initiator principal id was given");
100             }
101             if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDocumentContent())) {
102                 throw new RuntimeException("No document content was given");
103             }
104         } else if (!(TEMPLATE_REPORTING.equals(routingForm.getReportType()))) {
105             // report type is not Document Type or Template Type... error out
106             throw new RuntimeException("The Routing Report type is not set");
107         }
108         return super.execute(mapping, form, request, response);
109     }
110 
111 	public ActionForward calculateRoute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
112 		RoutingReportForm routingForm = (RoutingReportForm) form;
113 
114 		List errors = new ArrayList();
115 
116 		if (getDocumentTypeService().findByName(routingForm.getDocumentType()) == null) {
117 		    GlobalVariables.getMessageMap().putError("Document type is required.", "doctype.documenttypeservice.doctypename.required");
118 		}
119 		Timestamp date = null;
120 		if (!org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDateRef())) {
121 			SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
122 			try {
123 				Calendar calendar = Calendar.getInstance();
124 				calendar.setTime(sdf.parse(routingForm.getDateRef()));
125 				calendar.set(Calendar.HOUR, Integer.parseInt(routingForm.getEffectiveHour()));
126 				calendar.set(Calendar.MINUTE, Integer.parseInt(routingForm.getEffectiveMinute()));
127 				calendar.set(Calendar.AM_PM, Integer.parseInt(routingForm.getAmPm()));
128 				date = new Timestamp(calendar.getTimeInMillis());
129 			} catch (Exception e) {
130 				LOG.error("error parsing date", e);
131 				GlobalVariables.getMessageMap().putError("Invalid date.", "routereport.effectiveDate.invalid");
132 			}
133 		}
134 
135 		if (!GlobalVariables.getMessageMap().hasNoErrors()) {
136             throw new ValidationException("Errors populating rule attributes.");
137         }
138 
139 		DocumentTypeService documentTypeService = (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
140 		DocumentType docType = documentTypeService.findByName(routingForm.getDocumentType());
141 
142 		DocumentRouteHeaderValue routeHeader = new DocumentRouteHeaderValue();
143 		routeHeader.setDocumentId("");
144 		routeHeader.setDocumentTypeId(docType.getDocumentTypeId());
145 		routeHeader.setDocRouteLevel(new Integer(0));
146         routeHeader.setDocVersion(new Integer(KewApiConstants.DocumentContentVersions.CURRENT));
147 
148         List<RouteReportRuleTemplateContainer> ruleTemplateContainers = new ArrayList<RouteReportRuleTemplateContainer>();
149 		if (routingForm.getReportType().equals(DOC_TYPE_REPORTING)) {
150 
151           List routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(docType, true);
152 			for (Iterator iter = routeNodes.iterator(); iter.hasNext();) {
153                 RouteNode routeNode = (RouteNode) iter.next();
154 				if (routeNode.isFlexRM()) {
155 					RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateName(routeNode.getRouteMethodName());
156 					if (ruleTemplate != null) {
157 					    ruleTemplateContainers.add(new RouteReportRuleTemplateContainer(ruleTemplate, routeNode));
158 						if (ruleTemplate.getDelegationTemplate() != null) {
159 						    ruleTemplateContainers.add(new RouteReportRuleTemplateContainer(ruleTemplate.getDelegationTemplate(), routeNode));
160 						}
161 					}
162 				}
163 			}
164 		} else {
165 			RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(routingForm.getRuleTemplateId());
166 			RouteNode routeNode = new RouteNode();
167 			routeNode.setRouteNodeName(ruleTemplate.getName());
168 			ruleTemplateContainers.add(new RouteReportRuleTemplateContainer(ruleTemplate, routeNode));
169 			if (ruleTemplate.getDelegationTemplate() != null) {
170 			    ruleTemplateContainers.add(new RouteReportRuleTemplateContainer(ruleTemplate.getDelegationTemplate(), routeNode));
171 			}
172 		}
173 
174         String xmlDocumentContent = routingForm.getDocumentContent();
175         if (routingForm.getReportType().equals(TEMPLATE_REPORTING)) {
176             List<WorkflowRuleAttribute> attributes = new ArrayList<WorkflowRuleAttribute>();
177             for (RouteReportRuleTemplateContainer ruleTemplateContainer : ruleTemplateContainers) {
178                 RuleTemplateBo ruleTemplate = ruleTemplateContainer.ruleTemplate;
179                 for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) {
180                     if (!ruleTemplateAttribute.isWorkflowAttribute()) {
181                         continue;
182                     }
183                     WorkflowRuleAttribute workflowAttribute = ruleTemplateAttribute.getWorkflowAttribute();
184 
185                     RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute();
186                     if (ruleAttribute.getType().equals(KewApiConstants.RULE_XML_ATTRIBUTE_TYPE)) {
187                         ((GenericXMLRuleAttribute) workflowAttribute).setExtensionDefinition(RuleAttribute.to(ruleAttribute));
188                     }
189                     List attValidationErrors = workflowAttribute.validateRoutingData(routingForm.getFields());
190                     if (attValidationErrors != null && !attValidationErrors.isEmpty()) {
191                         errors.addAll(attValidationErrors);
192                     }
193                     attributes.add(workflowAttribute);
194                 }
195             }
196 
197             if (!GlobalVariables.getMessageMap().hasNoErrors()) {
198                 throw new ValidationException("errors in search criteria");
199             }
200 
201             DocumentContent docContent = new AttributeDocumentContent(attributes);
202             xmlDocumentContent = docContent.getDocContent();
203         }
204 
205 		routeHeader.setDocContent(xmlDocumentContent);
206 		routeHeader.setInitiatorWorkflowId(getUserSession(request).getPrincipalId());
207 		routeHeader.setDocRouteStatus(KewApiConstants.ROUTE_HEADER_INITIATED_CD);
208 		routeHeader.setDocTitle("Routing Report");
209 		routeHeader.setRoutingReport(true);
210 		long magicCounter = 0;
211 
212 		FlexRM flexRM = new FlexRM(date);
213 
214 		int numberOfRules = 0;
215 		int numberOfActionRequests = 0;
216 		Set<String> alreadyProcessedRuleTemplateNames = new HashSet<String>();
217 		for (Object element : ruleTemplateContainers) {
218 			// initialize the RouteContext
219 		    RouteContext context = RouteContext.createNewRouteContext();
220 		context.setActivationContext(new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION));
221 			try {
222 			    RouteReportRuleTemplateContainer ruleTemplateContainer = (RouteReportRuleTemplateContainer) element;
223 				RuleTemplateBo ruleTemplate = ruleTemplateContainer.ruleTemplate;
224 				RouteNode routeLevel = ruleTemplateContainer.routeNode;
225 
226 				if (!alreadyProcessedRuleTemplateNames.contains(ruleTemplate.getName())) {
227 				    alreadyProcessedRuleTemplateNames.add(ruleTemplate.getName());
228     				List<ActionRequestValue> actionRequests = flexRM.getActionRequests(routeHeader, routeLevel, null, ruleTemplate.getName());
229 
230     				numberOfActionRequests += actionRequests.size();
231     				numberOfRules += flexRM.getNumberOfMatchingRules();
232 
233     				magicCounter = populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(routeLevel, actionRequests, magicCounter);
234     				//routeHeader.getActionRequests().addAll(actionRequests);
235     				routeHeader.getSimulatedActionRequests().addAll(actionRequests);
236 				}
237 			} finally {
238 				RouteContext.clearCurrentRouteContext();
239 			}
240 		}
241 
242 		if (numberOfActionRequests == 0) {
243 			if (numberOfRules == 0) {
244 			    GlobalVariables.getMessageMap().putError("*", "routereport.noRules");
245 			} else {
246 			    GlobalVariables.getMessageMap().putError("*", "routereport.noMatchingRules");
247 			}
248 			if (GlobalVariables.getMessageMap().hasErrors()) {
249 	            throw new ValidationException("errors in search criteria");
250 	        }
251 		}
252 
253 
254 		// PROBLEM HERE!!!!
255 		RouteLogForm routeLogForm = new RouteLogForm();
256 		routeLogForm.setShowFuture(true);
257         if (StringUtils.isNotBlank(routingForm.getBackUrl())) {
258             routeLogForm.setReturnUrlLocation(routingForm.getBackUrl());
259         }
260         LOG.debug("Value of getDisplayCloseButton " + routingForm.getShowCloseButton());
261         LOG.debug("Value of isDisplayCloseButton " + routingForm.isDisplayCloseButton());
262         routeLogForm.setShowCloseButton(routingForm.isDisplayCloseButton());
263 		request.setAttribute("routeHeader", routeHeader);
264 		new RouteLogAction().populateRouteLogFormActionRequests(routeLogForm, routeHeader);
265 		request.setAttribute("KualiForm", routeLogForm);
266 		//END PROBLEM AREA
267 
268 		//return mapping.findForward("basic");
269 		return mapping.findForward("routeLog");
270 	}
271 
272 	private class RouteReportRuleTemplateContainer {
273 	    public RuleTemplateBo ruleTemplate = null;
274 	    public RouteNode routeNode = null;
275 	    public RouteReportRuleTemplateContainer(RuleTemplateBo template, RouteNode node) {
276 	        this.ruleTemplate = template;
277 	        this.routeNode = node;
278 	    }
279 	}
280 
281 	public long populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(RouteNode routeLevel, List<ActionRequestValue> actionRequests, long magicCounter) {
282 
283 		for (ActionRequestValue actionRequest : actionRequests) {
284 			populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(routeLevel, actionRequest.getChildrenRequests(), magicCounter);
285 			actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode());
286 //			actionRequest.setRouteMethodName(routeLevel.getRouteMethodName());
287 			RouteNodeInstance routeNode = new RouteNodeInstance();
288 			routeNode.setRouteNode(routeLevel);
289 			actionRequest.setNodeInstance(routeNode);
290 			actionRequest.setRouteLevel(new Integer(0));
291 			magicCounter++;
292 			actionRequest.setActionRequestId(String.valueOf(magicCounter));
293 		}
294 		return magicCounter;
295 	}
296 
297 	@Override
298 	public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
299 	    return mapping.findForward("basic");
300 	}
301 
302 	private ActionMessages initiateForm(HttpServletRequest request, ActionForm form) throws Exception {
303         RoutingReportForm routingReportForm = (RoutingReportForm) form;
304         if (routingReportForm.getReportType() == null) {
305             // no report type means we must check for potential setup
306             if ( (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentTypeParam())) ||
307                  (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getInitiatorPrincipalId())) ||
308                  (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentContent())) ) {
309                 // at least one parameter was passed... attempt to use Doc Type Report
310                 routingReportForm.setReportType(DOC_TYPE_REPORTING);
311             } else {
312                 // no parameters passed... default to Template Type Rreport
313                 routingReportForm.setReportType(TEMPLATE_REPORTING);
314             }
315         }
316 
317         if (routingReportForm.getReportType().equals(DOC_TYPE_REPORTING)) {
318             if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentTypeParam())) {
319                 throw new RuntimeException("Document Type was not given");
320             } else {
321                 DocumentType docType = getDocumentTypeService().findByName(routingReportForm.getDocumentTypeParam());
322                 if (docType == null) {
323                     throw new RuntimeException("Document Type is invalid");
324                 }
325             }
326             if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getInitiatorPrincipalId())) {
327                 throw new RuntimeException("Initiator Principal ID was not given");
328             } else {
329                 KEWServiceLocator.getIdentityHelperService().getPrincipal(routingReportForm.getInitiatorPrincipalId());
330             }
331             if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentContent())) {
332                 throw new RuntimeException("Document Content was not given");
333             }
334 
335             if (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentType())) {
336                 DocumentType docType = getDocumentTypeService().findByName(routingReportForm.getDocumentType());
337                 if (docType == null) {
338                     throw new RuntimeException("Document Type is missing or invalid");
339                 }
340                 routingReportForm.getRuleTemplateAttributes().clear();
341                 List<RouteNode> routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(docType, true);
342                 for (RouteNode routeNode : routeNodes) {
343                     if (routeNode.isFlexRM()) {
344                         RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateName(routeNode.getRouteMethodName());
345                         if (ruleTemplate != null) {
346                             loadRuleTemplateOnForm(ruleTemplate, routingReportForm, request, false);
347                             if (ruleTemplate.getDelegationTemplate() != null) {
348                                 loadRuleTemplateOnForm(ruleTemplate.getDelegationTemplate(), routingReportForm, request, true);
349                             }
350                         }
351                     }
352                 }
353             }
354 //          routingReportForm.setShowFields(true);
355         } else if (routingReportForm.getReportType().equals(TEMPLATE_REPORTING)) {
356             routingReportForm.setRuleTemplates(getRuleTemplateService().findAll());
357             if (routingReportForm.getRuleTemplateId() != null) {
358                 RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(routingReportForm.getRuleTemplateId());
359                 routingReportForm.getRuleTemplateAttributes().clear();
360                 loadRuleTemplateOnForm(ruleTemplate, routingReportForm, request, false);
361                 if (ruleTemplate.getDelegationTemplate() != null) {
362                     loadRuleTemplateOnForm(ruleTemplate.getDelegationTemplate(), routingReportForm, request, true);
363                 }
364             }
365         }
366         return null;
367 	}
368 
369 	private void loadRuleTemplateOnForm(RuleTemplateBo ruleTemplate, RoutingReportForm routingReportForm, HttpServletRequest request, boolean isDelegate) {
370 
371 		Map<String, String> fieldValues = new HashMap<String, String>();
372 
373 		List<RuleTemplateAttributeBo> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes();
374 		Collections.sort(ruleTemplateAttributes);
375 
376 		List<Row> rows = new ArrayList<Row>();
377 		for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplateAttributes) {
378 			if (!ruleTemplateAttribute.isWorkflowAttribute()) {
379 				continue;
380 			}
381 			WorkflowRuleAttribute workflowAttribute = ruleTemplateAttribute.getWorkflowAttribute();
382 
383 			RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute();
384 			if (ruleAttribute.getType().equals(KewApiConstants.RULE_XML_ATTRIBUTE_TYPE)) {
385 				((GenericXMLRuleAttribute) workflowAttribute).setExtensionDefinition(RuleAttribute.to(ruleAttribute));
386 			}
387 			for (Row row : workflowAttribute.getRoutingDataRows()) {
388 
389 				List<Field> fields = new ArrayList<Field>();
390 				for (Object element2 : row.getFields()) {
391 					Field field = (Field) element2;
392 					if (request.getParameter(field.getPropertyName()) != null) {
393 						field.setPropertyValue(request.getParameter(field.getPropertyName()));
394 					} else if (routingReportForm.getFields() != null && !routingReportForm.getFields().isEmpty()) {
395 						field.setPropertyValue((String) routingReportForm.getFields().get(field.getPropertyName()));
396 					}
397 					fields.add(field);
398 					fieldValues.put(field.getPropertyName(), field.getPropertyValue());
399 				}
400 			}
401 
402 			workflowAttribute.validateRuleData(fieldValues);// populate attribute
403 			List<Row> rdRows = workflowAttribute.getRoutingDataRows();
404 			for (Row row : rdRows)
405 			{
406 				List<Field> fields = new ArrayList<Field>();
407 				List<Field> rowFields = row.getFields();
408 				for (Field field : rowFields )
409 				{
410 					if (request.getParameter(field.getPropertyName()) != null) {
411 						field.setPropertyValue(request.getParameter(field.getPropertyName()));
412 					} else if (routingReportForm.getFields() != null && !routingReportForm.getFields().isEmpty()) {
413 						field.setPropertyValue((String) routingReportForm.getFields().get(field.getPropertyName()));
414 					}
415 					fields.add(field);
416 					fieldValues.put(field.getPropertyName(), field.getPropertyValue());
417 				}
418 				row.setFields(fields);
419 				rows.add(row);
420 
421 			}
422 		}
423 
424 		routingReportForm.getFields().putAll(fieldValues);
425 		routingReportForm.getRuleTemplateAttributes().addAll(rows);
426 		routingReportForm.setShowFields(true);
427 		routingReportForm.setShowViewResults(true);
428 	}
429 
430 	public ActionForward loadTemplate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
431 		RoutingReportForm routingReportForm = (RoutingReportForm) form;
432 		if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDateRef())) {
433 			SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
434 			routingReportForm.setEffectiveHour("5");
435 			routingReportForm.setEffectiveMinute("0");
436 			routingReportForm.setAmPm("1");
437 			routingReportForm.setDateRef(sdf.format(new Date()));
438 		}
439 		return mapping.findForward("basic");
440 	}
441 
442 	private RuleTemplateService getRuleTemplateService() {
443 		return (RuleTemplateService) KEWServiceLocator.getService(KEWServiceLocator.RULE_TEMPLATE_SERVICE);
444 	}
445 
446 	private DocumentTypeService getDocumentTypeService() {
447 		return (DocumentTypeService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
448 	}
449 
450 	private UserSession getUserSession(HttpServletRequest request) {
451 	    return GlobalVariables.getUserSession();
452 	}
453 
454 
455 
456 
457 }