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