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.docsearch; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.kuali.rice.core.api.uif.RemotableAttributeError; 020import org.kuali.rice.kew.api.WorkflowRuntimeException; 021import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria; 022import org.kuali.rice.kew.api.document.search.DocumentSearchResults; 023import org.kuali.rice.kew.framework.document.search.AttributeFields; 024import org.kuali.rice.kew.framework.document.search.DocumentSearchCriteriaConfiguration; 025import org.kuali.rice.kew.framework.document.search.DocumentSearchResultSetConfiguration; 026import org.kuali.rice.kew.framework.document.search.DocumentSearchResultValues; 027import org.kuali.rice.kew.doctype.DocumentTypeAttributeBo; 028import org.kuali.rice.kew.doctype.bo.DocumentType; 029import org.kuali.rice.kew.framework.KewFrameworkServiceLocator; 030import org.kuali.rice.kew.framework.document.search.DocumentSearchCustomization; 031import org.kuali.rice.kew.framework.document.search.DocumentSearchCustomizationHandlerService; 032import org.kuali.rice.kew.rule.bo.RuleAttribute; 033 034import java.util.ArrayList; 035import java.util.LinkedHashMap; 036import java.util.List; 037 038/** 039 * Reference implementation of {@code DocumentSearchCustomizationMediator}. 040 * 041 * @author Kuali Rice Team (rice.collab@kuali.org) 042 */ 043public class DocumentSearchCustomizationMediatorImpl implements DocumentSearchCustomizationMediator { 044 045 @Override 046 public DocumentSearchCriteriaConfiguration getDocumentSearchCriteriaConfiguration(DocumentType documentType) { 047 048 List<DocumentTypeAttributeBo> searchableAttributes = documentType.getSearchableAttributes(); 049 050 // This first map is used to partition our attributes by application id. It maps an application id to the 051 // list of searchable attribute names that are associated with that application id. Note that 'null' is a 052 // valid key in this map for those attributes that have no application id. 053 LinkedHashMap<String, List<String>> applicationIdToAttributeNameMap = new LinkedHashMap<String, List<String>>(); 054 055 // This second map is used to map the searchable attribute name to the List of RemotableAttributeFields 056 // that are returned by invocations of it's getSearchFields method. This is a LinkedHashMap because it 057 // preserves the order of the keys as they are entered. This allows us to return attribute fields in the 058 // proper order as defined by the order of searchable attributes on the doc type, despite the partitioning 059 // of our attributes by application id. 060 LinkedHashMap<String, AttributeFields> orderedSearchFieldMap = new LinkedHashMap<String, AttributeFields>(); 061 LinkedHashMap<String, AttributeFields> orderedResultSetFieldMap = new LinkedHashMap<String, AttributeFields>(); 062 063 for (DocumentTypeAttributeBo searchableAttribute : searchableAttributes) { 064 RuleAttribute ruleAttribute = searchableAttribute.getRuleAttribute(); 065 String attributeName = ruleAttribute.getName(); 066 String applicationId = ruleAttribute.getApplicationId(); 067 if (!applicationIdToAttributeNameMap.containsKey(applicationId)) { 068 applicationIdToAttributeNameMap.put(applicationId, new ArrayList<String>()); 069 } 070 applicationIdToAttributeNameMap.get(applicationId).add(attributeName); 071 // reserve a spot in the field map 072 orderedSearchFieldMap.put(attributeName, null); 073 } 074 075 for (String applicationId : applicationIdToAttributeNameMap.keySet()) { 076 DocumentSearchCustomizationHandlerService documentSearchCustomizationService = loadCustomizationService( 077 applicationId); 078 List<String> searchableAttributeNames = applicationIdToAttributeNameMap.get(applicationId); 079 DocumentSearchCriteriaConfiguration documentSearchConfiguration = documentSearchCustomizationService.getDocumentSearchConfiguration( 080 documentType.getName(), searchableAttributeNames); 081 mergeAttributeFields(documentSearchConfiguration.getSearchAttributeFields(), orderedSearchFieldMap); 082 } 083 084 DocumentSearchCriteriaConfiguration.Builder configBuilder = DocumentSearchCriteriaConfiguration.Builder.create(); 085 configBuilder.setSearchAttributeFields(flattenOrderedFieldMap(orderedSearchFieldMap)); 086 return configBuilder.build(); 087 } 088 089 @Override 090 public List<RemotableAttributeError> validateLookupFieldParameters(DocumentType documentType, 091 DocumentSearchCriteria documentSearchCriteria) { 092 093 List<DocumentTypeAttributeBo> searchableAttributes = documentType.getSearchableAttributes(); 094 LinkedHashMap<String, List<String>> applicationIdToAttributeNameMap = new LinkedHashMap<String, List<String>>(); 095 096 for (DocumentTypeAttributeBo searchableAttribute : searchableAttributes) { 097 RuleAttribute ruleAttribute = searchableAttribute.getRuleAttribute(); 098 String attributeName = ruleAttribute.getName(); 099 String applicationId = ruleAttribute.getApplicationId(); 100 if (!applicationIdToAttributeNameMap.containsKey(applicationId)) { 101 applicationIdToAttributeNameMap.put(applicationId, new ArrayList<String>()); 102 } 103 applicationIdToAttributeNameMap.get(applicationId).add(attributeName); 104 } 105 106 List<RemotableAttributeError> errors = new ArrayList<RemotableAttributeError>(); 107 for (String applicationId : applicationIdToAttributeNameMap.keySet()) { 108 DocumentSearchCustomizationHandlerService documentSearchCustomizationService = loadCustomizationService(applicationId); 109 List<String> searchableAttributeNames = applicationIdToAttributeNameMap.get(applicationId); 110 List<RemotableAttributeError> searchErrors = documentSearchCustomizationService.validateCriteria( 111 documentSearchCriteria, searchableAttributeNames); 112 if (!CollectionUtils.isEmpty(searchErrors)) { 113 errors.addAll(searchErrors); 114 } 115 } 116 117 return errors; 118 } 119 120 @Override 121 public DocumentSearchCriteria customizeCriteria(DocumentType documentType, DocumentSearchCriteria documentSearchCriteria) { 122 DocumentTypeAttributeBo customizerAttribute = documentType.getCustomizerAttribute(); 123 if (customizerAttribute != null) { 124 DocumentSearchCustomizationHandlerService service = loadCustomizationService(customizerAttribute.getRuleAttribute().getApplicationId()); 125 if (service.getEnabledCustomizations(documentType.getName(), customizerAttribute.getRuleAttribute().getName()).contains( 126 DocumentSearchCustomization.CRITERIA)) { 127 DocumentSearchCriteria customizedCriteria = service.customizeCriteria(documentSearchCriteria, customizerAttribute.getRuleAttribute().getName()); 128 if (customizedCriteria != null) { 129 return customizedCriteria; 130 } 131 } 132 } 133 return null; 134 } 135 136 @Override 137 public DocumentSearchCriteria customizeClearCriteria(DocumentType documentType, DocumentSearchCriteria documentSearchCriteria) { 138 DocumentTypeAttributeBo customizerAttribute = documentType.getCustomizerAttribute(); 139 if (customizerAttribute != null) { 140 DocumentSearchCustomizationHandlerService service = loadCustomizationService(customizerAttribute.getRuleAttribute().getApplicationId()); 141 if (service.getEnabledCustomizations(documentType.getName(), customizerAttribute.getRuleAttribute().getName()).contains( 142 DocumentSearchCustomization.CLEAR_CRITERIA)) { 143 DocumentSearchCriteria customizedCriteria = service.customizeClearCriteria(documentSearchCriteria, customizerAttribute.getRuleAttribute().getName()); 144 if (customizedCriteria != null) { 145 return customizedCriteria; 146 } 147 } 148 } 149 return null; 150 } 151 152 @Override 153 public DocumentSearchResultValues customizeResults(DocumentType documentType, 154 DocumentSearchCriteria documentSearchCriteria, DocumentSearchResults results) { 155 if (!results.getSearchResults().isEmpty()) { 156 DocumentTypeAttributeBo customizerAttribute = documentType.getCustomizerAttribute(); 157 if (customizerAttribute != null) { 158 DocumentSearchCustomizationHandlerService service = loadCustomizationService(customizerAttribute.getRuleAttribute().getApplicationId()); 159 if (service.getEnabledCustomizations(documentType.getName(), customizerAttribute.getRuleAttribute().getName()).contains( 160 DocumentSearchCustomization.RESULTS)) { 161 DocumentSearchResultValues customizedResults = service.customizeResults(documentSearchCriteria, results.getSearchResults(), customizerAttribute.getRuleAttribute().getName()); 162 if (customizedResults != null) { 163 return customizedResults; 164 } 165 } 166 } 167 return null; 168 } 169 return null; 170 } 171 172 @Override 173 public DocumentSearchResultSetConfiguration customizeResultSetConfiguration(DocumentType documentType, 174 DocumentSearchCriteria documentSearchCriteria) { 175 DocumentTypeAttributeBo customizerAttribute = documentType.getCustomizerAttribute(); 176 if (customizerAttribute != null) { 177 DocumentSearchCustomizationHandlerService service = loadCustomizationService(customizerAttribute.getRuleAttribute().getApplicationId()); 178 if (service.getEnabledCustomizations(documentType.getName(), customizerAttribute.getRuleAttribute().getName()).contains( 179 DocumentSearchCustomization.RESULT_SET_FIELDS)) { 180 DocumentSearchResultSetConfiguration resultSetConfiguration = service.customizeResultSetConfiguration( 181 documentSearchCriteria, customizerAttribute.getRuleAttribute().getName()); 182 if (resultSetConfiguration != null) { 183 return resultSetConfiguration; 184 } 185 } 186 } 187 return null; 188 } 189 190 protected DocumentSearchCustomizationHandlerService loadCustomizationService(String applicationId) { 191 DocumentSearchCustomizationHandlerService service = KewFrameworkServiceLocator.getDocumentSearchCustomizationHandlerService( 192 applicationId); 193 if (service == null) { 194 throw new WorkflowRuntimeException("Failed to locate DocumentSearchCustomizationService for applicationId: " + applicationId); 195 } 196 return service; 197 } 198 199 protected void mergeAttributeFields(List<AttributeFields> attributeFieldsList, LinkedHashMap<String, AttributeFields> orderedFieldMap) { 200 if (attributeFieldsList == null) { 201 return; 202 } 203 for (AttributeFields attributeFields : attributeFieldsList) { 204 orderedFieldMap.put(attributeFields.getAttributeName(), attributeFields); 205 } 206 } 207 208 protected List<AttributeFields> flattenOrderedFieldMap(LinkedHashMap<String, AttributeFields> orderedFieldMap) { 209 return new ArrayList<AttributeFields>(orderedFieldMap.values()); 210 } 211 212}