001 /** 002 * Copyright 2005-2012 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 */ 016 package org.kuali.rice.kew.rule.web; 017 018 import org.apache.log4j.Logger; 019 import org.apache.struts.action.ActionForm; 020 import org.apache.struts.action.ActionForward; 021 import org.apache.struts.action.ActionMapping; 022 import org.apache.struts.action.ActionMessages; 023 import org.kuali.rice.core.api.config.property.ConfigContext; 024 import org.kuali.rice.core.api.criteria.Predicate; 025 import org.kuali.rice.core.api.criteria.QueryByCriteria; 026 import org.kuali.rice.kew.doctype.bo.DocumentType; 027 import org.kuali.rice.kew.doctype.service.DocumentTypeService; 028 import org.kuali.rice.kew.engine.node.BranchPrototype; 029 import org.kuali.rice.kew.engine.node.RouteNode; 030 import org.kuali.rice.kew.engine.node.RouteNodeConfigParam; 031 import org.kuali.rice.kew.rule.RuleBaseValues; 032 import org.kuali.rice.kew.rule.bo.RuleTemplateBo; 033 import org.kuali.rice.kew.rule.service.RuleServiceInternal; 034 import org.kuali.rice.kew.service.KEWServiceLocator; 035 import org.kuali.rice.kew.api.KewApiConstants; 036 import org.kuali.rice.kew.web.KewKualiAction; 037 import org.kuali.rice.kim.api.KimConstants; 038 import org.kuali.rice.kim.api.group.Group; 039 import org.kuali.rice.kim.api.permission.Permission; 040 import org.kuali.rice.kim.api.responsibility.Responsibility; 041 import org.kuali.rice.kim.api.services.KimApiServiceLocator; 042 import org.kuali.rice.kns.service.DocumentHelperService; 043 import org.kuali.rice.kns.service.KNSServiceLocator; 044 import org.kuali.rice.kns.service.MaintenanceDocumentDictionaryService; 045 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 046 import org.kuali.rice.krad.util.GlobalVariables; 047 import org.kuali.rice.krad.util.KRADConstants; 048 049 import javax.servlet.http.HttpServletRequest; 050 import javax.servlet.http.HttpServletResponse; 051 import java.util.ArrayList; 052 import java.util.Collections; 053 import java.util.Comparator; 054 import java.util.HashMap; 055 import java.util.Iterator; 056 import java.util.List; 057 058 import static org.kuali.rice.core.api.criteria.PredicateFactory.and; 059 import static org.kuali.rice.core.api.criteria.PredicateFactory.equal; 060 061 062 /** 063 * A Struts Action for building and interacting with the Rule Quick Links. 064 * 065 * @author Kuali Rice Team (rice.collab@kuali.org) 066 */ 067 public class RuleQuickLinksAction extends KewKualiAction { 068 069 private static final Logger LOG = Logger.getLogger(RuleQuickLinksAction.class); 070 071 private MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService; 072 private DocumentHelperService documentHelperService; 073 074 public ActionForward start(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 075 makeLookupPathParam(mapping, request); 076 establishRequiredState(request, form); 077 return mapping.findForward("basic"); 078 } 079 080 @SuppressWarnings("unchecked") 081 public ActionMessages establishRequiredState(HttpServletRequest request, ActionForm form) throws Exception { 082 RuleQuickLinksForm qlForm = (RuleQuickLinksForm) form; 083 List<DocumentType> documentTypes; 084 if (qlForm.getRootDocTypeName() != null) { 085 documentTypes = new ArrayList<DocumentType>(); 086 DocumentType docType = getDocumentTypeService().findByName(qlForm.getRootDocTypeName()); 087 documentTypes.add(docType); 088 request.setAttribute("renderOpened", Boolean.TRUE); 089 } else { 090 documentTypes = getDocumentTypeService().findAllCurrentRootDocuments(); 091 } 092 qlForm.setDocumentTypeQuickLinksStructures(getDocumentTypeDataStructure(documentTypes)); 093 int shouldDisplayCount = 0; 094 for ( DocumentTypeQuickLinksStructure dt : qlForm.getDocumentTypeQuickLinksStructures() ) { 095 if ( dt.isShouldDisplay() ) { 096 shouldDisplayCount++; 097 } 098 } 099 if ( shouldDisplayCount == 1 ) { 100 request.setAttribute("renderOpened", Boolean.TRUE); 101 } 102 String documentTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(DocumentType.class); 103 try { 104 if ((documentTypeName != null) && getDocumentHelperService().getDocumentAuthorizer(documentTypeName).canInitiate(documentTypeName, GlobalVariables.getUserSession().getPerson())) { 105 qlForm.setCanInitiateDocumentTypeDocument( true ); 106 } 107 } catch (Exception ex) { 108 // just skip - and don't display links 109 LOG.error( "Unable to check initiation permission for "+ documentTypeName, ex ); 110 } 111 112 return null; 113 } 114 115 public ActionForward addDelegationRule(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 116 ActionForward result = null; 117 118 String ruleTemplateId = request.getParameter("delegationRule.ruleTemplate.id"); 119 String docTypeName = request.getParameter("delegationRule.documentType.name"); 120 List rules = getRuleService().search(docTypeName, null, ruleTemplateId, "", null, null, Boolean.FALSE, Boolean.TRUE, new HashMap(), null); 121 122 if (rules.size() == 1) { 123 RuleBaseValues rule = (RuleBaseValues)rules.get(0); 124 String url = ConfigContext.getCurrentContextConfig().getKEWBaseURL() + 125 "/DelegateRule.do?methodToCall=start" + 126 "&parentRuleId=" + rule.getId(); 127 result = new ActionForward(url, true); 128 } else { 129 makeLookupPathParam(mapping, request); 130 result = new ActionForward(ConfigContext.getCurrentContextConfig().getKRBaseURL() + 131 "/lookup.do?methodToCall=start&"+ stripMethodToCall(request.getQueryString()), true); 132 } 133 134 return result; 135 } 136 137 private List getDocumentTypeDataStructure(List rootDocuments) { 138 List documentTypeQuickLinksStructures = new ArrayList(); 139 for (Iterator iter = rootDocuments.iterator(); iter.hasNext();) { 140 DocumentTypeQuickLinksStructure quickLinkStruct =new DocumentTypeQuickLinksStructure((DocumentType) iter.next()); 141 if (! quickLinkStruct.getFlattenedNodes().isEmpty() || ! quickLinkStruct.getChildrenDocumentTypes().isEmpty()) { 142 documentTypeQuickLinksStructures.add(quickLinkStruct); 143 } 144 145 } 146 147 return documentTypeQuickLinksStructures; 148 } 149 150 151 /** 152 * A bean to hold a DocumentType with its flattened nodes for rendering purposes 153 * on the quick links. 154 * 155 * @author Kuali Rice Team (rice.collab@kuali.org) 156 */ 157 public static class DocumentTypeQuickLinksStructure { 158 private DocumentType documentType; 159 private List<RouteNode> flattenedNodes = new ArrayList<RouteNode>(); 160 private List<DocumentTypeQuickLinksStructure> childrenDocumentTypes = new ArrayList<DocumentTypeQuickLinksStructure>(); 161 private List<Permission> permissions = null; 162 163 private DocumentTypeQuickLinksStructure(DocumentType documentType) { 164 this.documentType = documentType; 165 if ( documentType != null ) { 166 List<RouteNode> tempFlattenedNodes = KEWServiceLocator.getRouteNodeService() 167 .getFlattenedNodes( documentType, true ); 168 for ( RouteNode routeNode : tempFlattenedNodes ) { 169 if ( routeNode.isFlexRM() || routeNode.isRoleNode() ) { 170 flattenedNodes.add( new RouteNodeForDisplay( routeNode ) ); 171 } 172 } 173 Collections.sort(flattenedNodes,new Comparator() { 174 public int compare(Object o1, Object o2) { 175 return ( ((RouteNode)o1).getRouteNodeName().compareTo(((RouteNode)o2).getRouteNodeName())); 176 } 177 }); 178 for ( Iterator<DocumentType> iter = documentType.getChildrenDocTypes().iterator(); iter.hasNext(); ) { 179 childrenDocumentTypes.add( new DocumentTypeQuickLinksStructure( iter.next() ) ); 180 } 181 Collections.sort(childrenDocumentTypes,new Comparator() { 182 public int compare(Object o1, Object o2) { 183 return ( ((DocumentTypeQuickLinksStructure)o1).documentType.getLabel().compareTo(((DocumentTypeQuickLinksStructure)o2).documentType.getLabel())); 184 } 185 }); 186 } 187 } 188 189 public List getChildrenDocumentTypes() { 190 return childrenDocumentTypes; 191 } 192 public void setChildrenDocumentTypes(List<DocumentTypeQuickLinksStructure> childrenDocumentTypes) { 193 this.childrenDocumentTypes = childrenDocumentTypes; 194 } 195 public DocumentType getDocumentType() { 196 return documentType; 197 } 198 public void setDocumentType(DocumentType documentType) { 199 this.documentType = documentType; 200 } 201 public List getFlattenedNodes() { 202 return flattenedNodes; 203 } 204 public void setFlattenedNodes(List<RouteNode> flattenedNodes) { 205 this.flattenedNodes = flattenedNodes; 206 } 207 public boolean isShouldDisplay() { 208 // if (flattenedNodes.isEmpty()) { 209 // for (DocumentTypeQuickLinksStructure docType : childrenDocumentTypes) { 210 // if (docType.isShouldDisplay()) { 211 // return true; 212 // } 213 // } 214 // return false; 215 // } 216 return true; 217 } 218 219 public List<Permission> getPermissions() { 220 if ( permissions == null ) { 221 Predicate p = and( 222 equal("attributeName", "documentTypeName"), 223 equal("active", "Y"), 224 equal("detailCriteria", 225 KimConstants.AttributeConstants.DOCUMENT_TYPE_NAME+"="+getDocumentType().getName())); 226 permissions = KimApiServiceLocator.getPermissionService().findPermissions( QueryByCriteria.Builder.fromPredicates(p)).getResults(); 227 // sqlLogger.setLevel( Level.INFO ); 228 } 229 return permissions; 230 } 231 232 public boolean isHasRelatedPermissions() { 233 return !getPermissions().isEmpty(); 234 } 235 236 public int getRelatedPermissionCount() { 237 return getPermissions().size(); 238 } 239 } 240 241 public static class RouteNodeForDisplay extends RouteNode { 242 private static final long serialVersionUID = 1L; 243 private RouteNode baseNode; 244 245 public RouteNodeForDisplay( RouteNode baseNode ) { 246 this.baseNode = baseNode; 247 } 248 249 public boolean equals(Object obj) { 250 return this.baseNode.equals(obj); 251 } 252 253 public String getActivationType() { 254 return this.baseNode.getActivationType(); 255 } 256 257 public BranchPrototype getBranch() { 258 return this.baseNode.getBranch(); 259 } 260 261 public List<RouteNodeConfigParam> getConfigParams() { 262 return this.baseNode.getConfigParams(); 263 } 264 265 public String getContentFragment() { 266 return this.baseNode.getContentFragment(); 267 } 268 269 public DocumentType getDocumentType() { 270 return this.baseNode.getDocumentType(); 271 } 272 273 public String getDocumentTypeId() { 274 return this.baseNode.getDocumentTypeId(); 275 } 276 public Group getExceptionWorkgroup() { 277 return this.baseNode.getExceptionWorkgroup(); 278 } 279 public String getExceptionWorkgroupId() { 280 return this.baseNode.getExceptionWorkgroupId(); 281 } 282 public String getExceptionWorkgroupName() { 283 return this.baseNode.getExceptionWorkgroupName(); 284 } 285 public Boolean getFinalApprovalInd() { 286 return this.baseNode.getFinalApprovalInd(); 287 } 288 public Integer getLockVerNbr() { 289 return this.baseNode.getLockVerNbr(); 290 } 291 public Boolean getMandatoryRouteInd() { 292 return this.baseNode.getMandatoryRouteInd(); 293 } 294 public List<RouteNode> getNextNodes() { 295 return this.baseNode.getNextNodes(); 296 } 297 public String getNodeType() { 298 return this.baseNode.getNodeType(); 299 } 300 public List<RouteNode> getPreviousNodes() { 301 return this.baseNode.getPreviousNodes(); 302 } 303 public String getRouteMethodCode() { 304 return this.baseNode.getRouteMethodCode(); 305 } 306 public String getRouteMethodName() { 307 return this.baseNode.getRouteMethodName(); 308 } 309 public String getRouteNodeId() { 310 return this.baseNode.getRouteNodeId(); 311 } 312 public String getRouteNodeName() { 313 return this.baseNode.getRouteNodeName(); 314 } 315 public RuleTemplateBo getRuleTemplate() { 316 return this.baseNode.getRuleTemplate(); 317 } 318 public int hashCode() { 319 return this.baseNode.hashCode(); 320 } 321 public boolean isExceptionGroupDefined() { 322 return this.baseNode.isExceptionGroupDefined(); 323 } 324 public boolean isFlexRM() { 325 return this.baseNode.isFlexRM(); 326 } 327 public boolean isRoleNode() { 328 return this.baseNode.isRoleNode(); 329 } 330 public String toString() { 331 return this.baseNode.toString(); 332 } 333 334 private List<Responsibility> responsibilities = null; 335 336 public List<Responsibility> getResponsibilities() { 337 if ( responsibilities == null ) { 338 QueryByCriteria.Builder builder = QueryByCriteria.Builder.create(); 339 Predicate p = and( 340 equal("template.namespaceCode", KRADConstants.KUALI_RICE_WORKFLOW_NAMESPACE), 341 equal("template.name", KewApiConstants.DEFAULT_RESPONSIBILITY_TEMPLATE_NAME), 342 equal("active", "Y"), 343 equal("attributes[documentTypeName]", getDocumentType().getName()), 344 equal("attributes[routeNodeName]", getRouteNodeName()) 345 ); 346 builder.setPredicates(p); 347 responsibilities = KimApiServiceLocator.getResponsibilityService().findResponsibilities(builder.build()).getResults(); 348 } 349 return responsibilities; 350 } 351 352 public int getResponsibilityCount() { 353 return getResponsibilities().size(); 354 } 355 356 public boolean isHasResponsibility() { 357 return !getResponsibilities().isEmpty(); 358 } 359 } 360 361 private void makeLookupPathParam(ActionMapping mapping, HttpServletRequest request) { 362 String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + mapping.getModuleConfig().getPrefix(); 363 request.setAttribute("basePath", basePath); 364 } 365 366 private String stripMethodToCall(String queryString) { 367 return queryString.replaceAll("methodToCall=addDelegationRule&", ""); 368 } 369 370 private DocumentTypeService getDocumentTypeService() { 371 return KEWServiceLocator.getDocumentTypeService(); 372 } 373 374 private RuleServiceInternal getRuleService() { 375 return KEWServiceLocator.getRuleService(); 376 } 377 378 public DocumentHelperService getDocumentHelperService() { 379 if(documentHelperService == null){ 380 documentHelperService = KNSServiceLocator.getDocumentHelperService(); 381 } 382 return documentHelperService; 383 } 384 385 public MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() { 386 if(maintenanceDocumentDictionaryService == null){ 387 maintenanceDocumentDictionaryService = KNSServiceLocator.getMaintenanceDocumentDictionaryService(); 388 } 389 return maintenanceDocumentDictionaryService; 390 } 391 392 @Override 393 public ActionForward toggleTab(ActionMapping mapping, ActionForm form, 394 HttpServletRequest request, HttpServletResponse response) 395 throws Exception { 396 397 establishRequiredState(request, form); 398 return super.toggleTab(mapping, form, request, response); 399 } 400 401 }