View Javadoc

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