1 /** 2 * Copyright 2005-2015 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.krad.workflow.attribute; 17 18 import org.kuali.rice.kew.engine.RouteContext; 19 import org.kuali.rice.krad.datadictionary.DocumentEntry; 20 import org.kuali.rice.krad.datadictionary.RoutingTypeDefinition; 21 import org.kuali.rice.krad.datadictionary.WorkflowAttributes; 22 import org.kuali.rice.krad.document.Document; 23 import org.kuali.rice.krad.service.KRADServiceLocatorInternal; 24 import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 25 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map; 30 31 /** 32 * QualifierResolver which uses Data Dictionary defined workflow attributes to gather a collection 33 * of qualifiers to use to determine the responsibility for a document at a given workflow route node. 34 * 35 * WorkflowAttributes can be defined in the data dictionary like so (this has been abbreviated): 36 * 37 * <!-- Exported Workflow Attributes --> 38 * <bean id="DisbursementVoucherDocument-workflowAttributes" parent="DisbursementVoucherDocument-workflowAttributes-parentBean"/> 39 * 40 * <bean id="DisbursementVoucherDocument-workflowAttributes-parentBean" abstract="true" parent="WorkflowAttributes"> 41 * <property name="routingTypeDefinitions"> 42 * <map> 43 * <!-- no qualifiers for purchasing node --> 44 * <entry key="Account" value-ref="RoutingType-AccountingDocument-Account-sourceOnly"/> 45 * <entry key="AccountingOrganizationHierarchy" value-ref="RoutingType-AccountingDocument-OrganizationHierarchy-sourceOnly"/> 46 * <entry key="Campus" value-ref="DisbursementVoucherDocument-RoutingType-Campus"/> 47 * <!-- no qualifiers for tax review --> 48 * <!-- no qualifiers for travel review --> 49 * <entry key="PaymentMethod" value-ref="DisbursementVoucherDocument-RoutingType-PaymentMethod"/> 50 * <entry key="Award" value-ref="RoutingType-AccountingDocument-Award"/> 51 * </map> 52 * </property> 53 * </bean> 54 * 55 * <bean id="DisbursementVoucherDocument-RoutingType-PaymentMethod" class="org.kuali.rice.krad.datadictionary.RoutingTypeDefinition"> 56 * <property name="routingAttributes"> 57 * <list> 58 * <bean class="org.kuali.rice.krad.datadictionary.RoutingAttribute"> 59 * <property name="qualificationAttributeName" value="disbVchrPaymentMethodCode"/> 60 * </bean> 61 * </list> 62 * </property> 63 * <property name="documentValuePathGroups"> 64 * <list> 65 * <bean class="org.kuali.rice.krad.datadictionary.DocumentValuePathGroup"> 66 * <property name="documentValues"> 67 * <list> 68 * <value>disbVchrPaymentMethodCode</value> 69 * </list> 70 * </property> 71 * </bean> 72 * </list> 73 * </property> 74 * </bean> 75 * 76 * At the PaymentMethod node of the document, the DisbursementVoucherDocument-RoutingType-PaymentMethod RoutingTypeDefinition will be 77 * consulted; it will pull values from the document (in this case, document.disbVchrPaymentMethodCode) and populate those 78 * into the role qualifier Map<String, String>, with the key being the qualificationAttributeName and the value being the value of the property 79 * listed in the documentValuePathGroups in the document. 80 */ 81 public class DataDictionaryQualifierResolver extends QualifierResolverBase { 82 // private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DataDictionaryQualifierResolver.class); 83 84 85 /** 86 * Given the RouteContext, determines the document type of the document being routed and the current 87 * route nodes; generates a List of qualifier Map<String, String>s based on the the contents of the document. 88 * @see org.kuali.rice.kew.role.QualifierResolver#resolve(org.kuali.rice.kew.engine.RouteContext) 89 */ 90 public List<Map<String, String>> resolve(RouteContext context) { 91 final String routeLevel = context.getNodeInstance().getName(); 92 final DocumentEntry documentEntry = getDocumentEntry(context); 93 final RoutingTypeDefinition routingTypeDefinition = getWorkflowAttributeDefintion(documentEntry, routeLevel); 94 final Document document = getDocument(context); 95 List<Map<String, String>> qualifiers = null; 96 97 if (document != null && routingTypeDefinition != null) { 98 qualifiers = KRADServiceLocatorInternal.getWorkflowAttributePropertyResolutionService().resolveRoutingTypeQualifiers(document, routingTypeDefinition); 99 } else { 100 qualifiers = new ArrayList<Map<String, String>>(); 101 Map<String, String> basicQualifier = new HashMap<String, String>(); 102 qualifiers.add(basicQualifier); 103 } 104 decorateWithCommonQualifiers(qualifiers, document, documentEntry, routeLevel); 105 return qualifiers; 106 } 107 108 /** 109 * Retrieves the data dictionary entry for the document being operated on by the given route context 110 * @param context the current route context 111 * @return the data dictionary document entry 112 */ 113 protected DocumentEntry getDocumentEntry(RouteContext context) { 114 return KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(context.getDocument().getDocumentType().getName()); 115 } 116 117 /** 118 * Retrieves the proper List of WorkflowAttributes for the given route level from the data dictionary 119 * document entry 120 * @param documentEntry the data dictionary document entry for the currently routed document 121 * @param routeLevelName the name of the route level 122 * @return a WorkflowAttributeDefinition if one could be found for the route level; otherwise, nothing 123 */ 124 protected RoutingTypeDefinition getWorkflowAttributeDefintion(DocumentEntry documentEntry, String routeLevelName) { 125 final WorkflowAttributes workflowAttributes = documentEntry.getWorkflowAttributes(); 126 if ( workflowAttributes == null ) { 127 return null; 128 } 129 final Map<String, RoutingTypeDefinition> routingTypeMap = workflowAttributes.getRoutingTypeDefinitions(); 130 if (routingTypeMap.containsKey(routeLevelName)) return routingTypeMap.get(routeLevelName); 131 return null; 132 } 133 134 /** 135 * Add common qualifiers to every Map<String, String> in the given List of Map<String, String> 136 * @param qualifiers a List of Map<String, String>s to add common qualifiers to 137 * @param document the document currently being routed 138 * @param documentEntry the data dictionary entry of the type of document currently being routed 139 * @param routeLevel the document's current route level 140 */ 141 protected void decorateWithCommonQualifiers(List<Map<String, String>> qualifiers, Document document, DocumentEntry documentEntry, String routeLevel) { 142 for (Map<String, String> qualifier : qualifiers) { 143 addCommonQualifiersToMap(qualifier, document, documentEntry, routeLevel); 144 } 145 } 146 147 /** 148 * Adds common qualifiers to a given Map<String, String> 149 * @param qualifier an Map<String, String> to add common qualifiers to 150 * @param document the document currently being routed 151 * @param documentEntry the data dictionary entry of the type of document currently being routed 152 * @param routeLevel the document's current route level 153 */ 154 protected void addCommonQualifiersToMap(Map<String, String> qualifier, Document document, DocumentEntry documentEntry, String routeLevel) { 155 if ( document != null ) { 156 qualifier.put(KIM_ATTRIBUTE_DOCUMENT_NUMBER, document.getDocumentNumber()); 157 } 158 if ( documentEntry != null ) { 159 qualifier.put(KIM_ATTRIBUTE_DOCUMENT_TYPE_NAME, documentEntry.getDocumentTypeName()); 160 } 161 qualifier.put(KIM_ATTRIBUTE_ROUTE_LEVEL_NAME, routeLevel); 162 } 163 }