001/** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kew.rule.web; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.struts.action.ActionForm; 020import org.apache.struts.action.ActionForward; 021import org.apache.struts.action.ActionMapping; 022import org.apache.struts.action.ActionMessages; 023import org.kuali.rice.core.api.uif.RemotableAttributeError; 024import org.kuali.rice.kew.actionrequest.ActionRequestValue; 025import org.kuali.rice.kew.api.KewApiConstants; 026import org.kuali.rice.kew.api.action.ActionRequestStatus; 027import org.kuali.rice.kew.doctype.bo.DocumentType; 028import org.kuali.rice.kew.doctype.service.DocumentTypeService; 029import org.kuali.rice.kew.engine.ActivationContext; 030import org.kuali.rice.kew.engine.RouteContext; 031import org.kuali.rice.kew.engine.node.RouteNode; 032import org.kuali.rice.kew.engine.node.RouteNodeInstance; 033import org.kuali.rice.kew.routeheader.AttributeDocumentContent; 034import org.kuali.rice.kew.routeheader.DocumentContent; 035import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue; 036import org.kuali.rice.kew.routelog.web.RouteLogAction; 037import org.kuali.rice.kew.routelog.web.RouteLogForm; 038import org.kuali.rice.kew.rule.FlexRM; 039import org.kuali.rice.kew.rule.WorkflowRuleAttribute; 040import org.kuali.rice.kew.rule.WorkflowRuleAttributeRows; 041import org.kuali.rice.kew.rule.bo.RuleAttribute; 042import org.kuali.rice.kew.rule.bo.RuleTemplateAttributeBo; 043import org.kuali.rice.kew.rule.bo.RuleTemplateBo; 044import org.kuali.rice.kew.rule.service.RuleTemplateService; 045import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute; 046import org.kuali.rice.kew.service.KEWServiceLocator; 047import org.kuali.rice.kew.web.KewKualiAction; 048import org.kuali.rice.kns.web.ui.Field; 049import org.kuali.rice.kns.web.ui.Row; 050import org.kuali.rice.krad.UserSession; 051import org.kuali.rice.krad.exception.ValidationException; 052import org.kuali.rice.krad.util.GlobalVariables; 053 054import javax.servlet.http.HttpServletRequest; 055import javax.servlet.http.HttpServletResponse; 056import java.sql.Timestamp; 057import java.text.SimpleDateFormat; 058import java.util.ArrayList; 059import java.util.Calendar; 060import java.util.Collections; 061import java.util.Date; 062import java.util.HashMap; 063import java.util.HashSet; 064import java.util.Iterator; 065import java.util.List; 066import java.util.Map; 067import java.util.Set; 068 069 070/** 071 * A Struts Action for executing routing reports and retrieving the results. 072 * 073 * @author Kuali Rice Team (rice.collab@kuali.org) 074 */ 075public class RoutingReportAction extends KewKualiAction { 076 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(RoutingReportAction.class); 077 078 public static final String DOC_TYPE_REPORTING = "documentType"; 079 public static final String TEMPLATE_REPORTING = "template"; 080 081 @Override 082 public ActionForward execute(ActionMapping mapping, ActionForm form, 083 HttpServletRequest request, HttpServletResponse response) 084 throws Exception { 085 this.initiateForm(request, form); 086 RoutingReportForm routingForm = (RoutingReportForm)form; 087 if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDateRef())) { 088 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); 089 routingForm.setEffectiveHour("5"); 090 routingForm.setEffectiveMinute("0"); 091 routingForm.setAmPm("1"); 092 routingForm.setDateRef(sdf.format(new Date())); 093 routingForm.setReportType(TEMPLATE_REPORTING); 094 } 095 if (DOC_TYPE_REPORTING.equals(routingForm.getReportType())) { 096 if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDocumentTypeParam())) { 097 throw new RuntimeException("No document type was given"); 098 } 099 if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getInitiatorPrincipalId())) { 100 throw new RuntimeException("No initiator principal id was given"); 101 } 102 if (org.apache.commons.lang.StringUtils.isEmpty(routingForm.getDocumentContent())) { 103 throw new RuntimeException("No document content was given"); 104 } 105 } else if (!(TEMPLATE_REPORTING.equals(routingForm.getReportType()))) { 106 // report type is not Document Type or Template Type... error out 107 throw new RuntimeException("The Routing Report type is not set"); 108 } 109 return super.execute(mapping, form, request, response); 110 } 111 112 public ActionForward calculateRoute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 113 RoutingReportForm routingForm = (RoutingReportForm) form; 114 115 // this is never actually used?? 116 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>(); 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 RuleTemplateBo 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 RuleTemplateBo 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<WorkflowRuleAttribute> attributes = new ArrayList<WorkflowRuleAttribute>(); 179 for (RouteReportRuleTemplateContainer ruleTemplateContainer : ruleTemplateContainers) { 180 RuleTemplateBo ruleTemplate = ruleTemplateContainer.ruleTemplate; 181 for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplate.getActiveRuleTemplateAttributes()) { 182 if (!ruleTemplateAttribute.isWorkflowAttribute()) { 183 continue; 184 } 185 WorkflowRuleAttribute workflowAttribute = ruleTemplateAttribute.getWorkflowAttribute(); 186 187 RuleAttribute ruleAttribute = ruleTemplateAttribute.getRuleAttribute(); 188 if (ruleAttribute.getType().equals(KewApiConstants.RULE_XML_ATTRIBUTE_TYPE)) { 189 ((GenericXMLRuleAttribute) workflowAttribute).setExtensionDefinition(RuleAttribute.to(ruleAttribute)); 190 } 191 List<RemotableAttributeError> attValidationErrors = workflowAttribute.validateRoutingData(routingForm.getFields()); 192 if (attValidationErrors != null && !attValidationErrors.isEmpty()) { 193 errors.addAll(attValidationErrors); 194 } 195 attributes.add(workflowAttribute); 196 } 197 } 198 199 if (!GlobalVariables.getMessageMap().hasNoErrors()) { 200 throw new ValidationException("errors in search criteria"); 201 } 202 203 DocumentContent docContent = new AttributeDocumentContent(attributes); 204 xmlDocumentContent = docContent.getDocContent(); 205 } 206 207 routeHeader.setDocContent(xmlDocumentContent); 208 routeHeader.setInitiatorWorkflowId(getUserSession(request).getPrincipalId()); 209 routeHeader.setDocRouteStatus(KewApiConstants.ROUTE_HEADER_INITIATED_CD); 210 routeHeader.setDocTitle("Routing Report"); 211 routeHeader.setRoutingReport(true); 212 long magicCounter = 0; 213 214 FlexRM flexRM = new FlexRM(date); 215 216 int numberOfRules = 0; 217 int numberOfActionRequests = 0; 218 Set<String> alreadyProcessedRuleTemplateNames = new HashSet<String>(); 219 for (Object element : ruleTemplateContainers) { 220 // initialize the RouteContext 221 RouteContext context = RouteContext.createNewRouteContext(); 222 context.setActivationContext(new ActivationContext(ActivationContext.CONTEXT_IS_SIMULATION)); 223 try { 224 RouteReportRuleTemplateContainer ruleTemplateContainer = (RouteReportRuleTemplateContainer) element; 225 RuleTemplateBo ruleTemplate = ruleTemplateContainer.ruleTemplate; 226 RouteNode routeLevel = ruleTemplateContainer.routeNode; 227 228 if (!alreadyProcessedRuleTemplateNames.contains(ruleTemplate.getName())) { 229 alreadyProcessedRuleTemplateNames.add(ruleTemplate.getName()); 230 List<ActionRequestValue> actionRequests = flexRM.getActionRequests(routeHeader, routeLevel, null, ruleTemplate.getName()); 231 232 numberOfActionRequests += actionRequests.size(); 233 numberOfRules += flexRM.getNumberOfMatchingRules(); 234 235 magicCounter = populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(routeLevel, actionRequests, magicCounter); 236 //routeHeader.getActionRequests().addAll(actionRequests); 237 routeHeader.getSimulatedActionRequests().addAll(actionRequests); 238 } 239 } finally { 240 RouteContext.clearCurrentRouteContext(); 241 } 242 } 243 244 if (numberOfActionRequests == 0) { 245 if (numberOfRules == 0) { 246 GlobalVariables.getMessageMap().putError("*", "routereport.noRules"); 247 } else { 248 GlobalVariables.getMessageMap().putError("*", "routereport.noMatchingRules"); 249 } 250 if (GlobalVariables.getMessageMap().hasErrors()) { 251 throw new ValidationException("errors in search criteria"); 252 } 253 } 254 255 256 // PROBLEM HERE!!!! 257 RouteLogForm routeLogForm = new RouteLogForm(); 258 routeLogForm.setShowFuture(true); 259 if (StringUtils.isNotBlank(routingForm.getBackUrl())) { 260 routeLogForm.setReturnUrlLocation(routingForm.getBackUrl()); 261 } 262 LOG.debug("Value of getDisplayCloseButton " + routingForm.getShowCloseButton()); 263 LOG.debug("Value of isDisplayCloseButton " + routingForm.isDisplayCloseButton()); 264 routeLogForm.setShowCloseButton(routingForm.isDisplayCloseButton()); 265 request.setAttribute("routeHeader", routeHeader); 266 new RouteLogAction().populateRouteLogFormActionRequests(routeLogForm, routeHeader); 267 request.setAttribute("KualiForm", routeLogForm); 268 //END PROBLEM AREA 269 270 //return mapping.findForward("basic"); 271 return mapping.findForward("routeLog"); 272 } 273 274 private class RouteReportRuleTemplateContainer { 275 public RuleTemplateBo ruleTemplate = null; 276 public RouteNode routeNode = null; 277 public RouteReportRuleTemplateContainer(RuleTemplateBo template, RouteNode node) { 278 this.ruleTemplate = template; 279 this.routeNode = node; 280 } 281 } 282 283 public long populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(RouteNode routeLevel, List<ActionRequestValue> actionRequests, long magicCounter) { 284 285 for (ActionRequestValue actionRequest : actionRequests) { 286 populateActionRequestsWithRouteLevelInformationAndIterateMagicCounter(routeLevel, actionRequest.getChildrenRequests(), magicCounter); 287 actionRequest.setStatus(ActionRequestStatus.INITIALIZED.getCode()); 288// actionRequest.setRouteMethodName(routeLevel.getRouteMethodName()); 289 RouteNodeInstance routeNode = new RouteNodeInstance(); 290 routeNode.setRouteNode(routeLevel); 291 actionRequest.setNodeInstance(routeNode); 292 actionRequest.setRouteLevel(new Integer(0)); 293 magicCounter++; 294 actionRequest.setActionRequestId(String.valueOf(magicCounter)); 295 } 296 return magicCounter; 297 } 298 299 @Override 300 public ActionForward refresh(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 301 return mapping.findForward("basic"); 302 } 303 304 private ActionMessages initiateForm(HttpServletRequest request, ActionForm form) throws Exception { 305 RoutingReportForm routingReportForm = (RoutingReportForm) form; 306 if (routingReportForm.getReportType() == null) { 307 // no report type means we must check for potential setup 308 if ( (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentTypeParam())) || 309 (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getInitiatorPrincipalId())) || 310 (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentContent())) ) { 311 // at least one parameter was passed... attempt to use Doc Type Report 312 routingReportForm.setReportType(DOC_TYPE_REPORTING); 313 } else { 314 // no parameters passed... default to Template Type Rreport 315 routingReportForm.setReportType(TEMPLATE_REPORTING); 316 } 317 } 318 319 if (routingReportForm.getReportType().equals(DOC_TYPE_REPORTING)) { 320 if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentTypeParam())) { 321 throw new RuntimeException("Document Type was not given"); 322 } else { 323 DocumentType docType = getDocumentTypeService().findByName(routingReportForm.getDocumentTypeParam()); 324 if (docType == null) { 325 throw new RuntimeException("Document Type is invalid"); 326 } 327 } 328 if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getInitiatorPrincipalId())) { 329 throw new RuntimeException("Initiator Principal ID was not given"); 330 } else { 331 KEWServiceLocator.getIdentityHelperService().getPrincipal(routingReportForm.getInitiatorPrincipalId()); 332 } 333 if (org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentContent())) { 334 throw new RuntimeException("Document Content was not given"); 335 } 336 337 if (!org.apache.commons.lang.StringUtils.isEmpty(routingReportForm.getDocumentType())) { 338 DocumentType docType = getDocumentTypeService().findByName(routingReportForm.getDocumentType()); 339 if (docType == null) { 340 throw new RuntimeException("Document Type is missing or invalid"); 341 } 342 routingReportForm.getRuleTemplateAttributes().clear(); 343 List<RouteNode> routeNodes = KEWServiceLocator.getRouteNodeService().getFlattenedNodes(docType, true); 344 for (RouteNode routeNode : routeNodes) { 345 if (routeNode.isFlexRM()) { 346 RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateName(routeNode.getRouteMethodName()); 347 if (ruleTemplate != null) { 348 loadRuleTemplateOnForm(ruleTemplate, routingReportForm, request, false); 349 if (ruleTemplate.getDelegationTemplate() != null) { 350 loadRuleTemplateOnForm(ruleTemplate.getDelegationTemplate(), routingReportForm, request, true); 351 } 352 } 353 } 354 } 355 } 356// routingReportForm.setShowFields(true); 357 } else if (routingReportForm.getReportType().equals(TEMPLATE_REPORTING)) { 358 routingReportForm.setRuleTemplates(getRuleTemplateService().findAll()); 359 if (routingReportForm.getRuleTemplateId() != null) { 360 RuleTemplateBo ruleTemplate = getRuleTemplateService().findByRuleTemplateId(routingReportForm.getRuleTemplateId()); 361 routingReportForm.getRuleTemplateAttributes().clear(); 362 if (ruleTemplate != null) { 363 loadRuleTemplateOnForm(ruleTemplate, routingReportForm, request, false); 364 if (ruleTemplate.getDelegationTemplate() != null) { 365 loadRuleTemplateOnForm(ruleTemplate.getDelegationTemplate(), routingReportForm, request, true); 366 } 367 } 368 } 369 } 370 return null; 371 } 372 373 private void loadRuleTemplateOnForm(RuleTemplateBo ruleTemplate, RoutingReportForm routingReportForm, HttpServletRequest request, boolean isDelegate) { 374 375 Map<String, String> fieldValues = new HashMap<String, String>(); 376 377 List<RuleTemplateAttributeBo> ruleTemplateAttributes = ruleTemplate.getActiveRuleTemplateAttributes(); 378 Collections.sort(ruleTemplateAttributes); 379 380 List<Row> rows = new ArrayList<Row>(); 381 for (RuleTemplateAttributeBo ruleTemplateAttribute : ruleTemplateAttributes) { 382 if (!ruleTemplateAttribute.isWorkflowAttribute()) { 383 continue; 384 } 385 386 WorkflowRuleAttributeRows workflowRuleAttributeRows = 387 KEWServiceLocator.getWorkflowRuleAttributeMediator().getRoutingDataRows(fieldValues, ruleTemplateAttribute); 388 389 for (Row row : workflowRuleAttributeRows.getRows()) { 390 391 List<Field> fields = new ArrayList<Field>(); 392 for (Object element2 : row.getFields()) { 393 Field field = (Field) element2; 394 if (request.getParameter(field.getPropertyName()) != null) { 395 field.setPropertyValue(request.getParameter(field.getPropertyName())); 396 } else if (routingReportForm.getFields() != null && !routingReportForm.getFields().isEmpty()) { 397 field.setPropertyValue((String) routingReportForm.getFields().get(field.getPropertyName())); 398 } 399 fields.add(field); 400 fieldValues.put(field.getPropertyName(), field.getPropertyValue()); 401 } 402 } 403 404 for (Row row : workflowRuleAttributeRows.getRows()) 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}